feat(local-agent): execute uninstall_teamai commands via sync + ack (sandbox-safe) - #249
Merged
Merged
Conversation
m0Nst3r873
force-pushed
the
feat/http-source-cmd
branch
from
July 30, 2026 03:30
b02365e to
5ff02f0
Compare
Implement the clawpro three-phase uninstall_teamai command in the HTTP source sync channel. The backend pushes an uninstall_teamai command carrying a `cmd` string (e.g. "teamai uninstall --force --agent codebuddy"); the local agent runs it once and reports the result via the existing ack channel. Delivery, ack, and retry semantics are reused unchanged. PR Tencent#261 landed uninstall_teamai in UNIMPLEMENTED_COMMAND_TYPES (silently skipped, no execution path existed). This adds the execution path and removes it from that set; hook rule types stay skipped. Execution (runCmdCommand) security boundary: - teamai subcommands only — argv[0] must strictly equal `teamai`; anything else is rejected (acked failed) and never executed. - No shell — execFile(process.execPath, [entry, ...args]); shell metacharacters are literal, no PATH dependency (works in bundled-node sandboxes). - 120s timeout, 4 MiB maxBuffer, error detail capped at 200 chars. - TEAMAI_DISABLE_REMOTE_CMD=1 kill switch (acked failed). Converged to the clawpro ch.7 unified contract: the interface defines uninstall_teamai as the type that carries a one-shot `cmd`, so this drops the earlier generic `type:"cmd"` dispatch branch (not in the ch.7 type enum) and routes only uninstall_teamai. Commands flow through the unified cmds[] parser from Tencent#261. Also change the CloudStudio sandbox guard from "skip report + sync" to "skip report, still run sync + processCommands", so sandboxed agents can receive the pushed uninstall. Report-side bookkeeping (plugin reconcile, binding prune, config save) stays gated behind the report path to avoid pruning host bindings not mounted in the container. Docs updated in both languages; unit tests cover the tokenizer, rejection, kill switch, subcommand failure, uninstall_teamai execution, and the sandbox no-prune guarantee. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
m0Nst3r873
force-pushed
the
feat/http-source-cmd
branch
from
July 30, 2026 06:53
5ff02f0 to
3b89fee
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implement the clawpro three-phase
uninstall_teamaicommand in the HTTP source sync channel. The backend pushes anuninstall_teamaicommand carrying acmdstring (a singleteamaisubcommand); the local agent runs it once and reports the result via the existing ack channel. Delivery, ack, and retry semantics are reused unchanged.{ "id": 42, "type": "uninstall_teamai", "cmd": "teamai uninstall --force --agent codebuddy" }Resolves #235. Converged to the clawpro ch.7 unified
cmds[]contract (implemented in #261): the interface models "push a one-shot teamai command" as the specific typeuninstall_teamai, so this PR routes only that type and does not add a generictype:"cmd"(which is not in the ch.7 enum and the backend does not send). Commands flow through the unifiedcmds[]parser from #261 (falls back to legacycommands[]).Behavior
uninstall_teamai(placed it inUNIMPLEMENTED_COMMAND_TYPES, since no execution path existed). This PR adds the execution path and removes it from that set. Hook rule types (install_hook_rule/uninstall_hook_rule) stay skipped — out of scope.runCmdCommand.Security boundary (
runCmdCommand)argv[0]must strictly equalteamai; anything else is rejected (ackedfailed) and never executed. No arbitrary-shell surface.execFile(process.execPath, [entry, ...args]); shell metacharacters are literal, no PATH dependency (works in bundled-node sandboxes).TEAMAI_DISABLE_REMOTE_CMD=1short-circuits and acksfailedwithremote cmd disabled by client.Sandbox delivery
Changes the CloudStudio sandbox guard from "skip report + sync" to "skip report, still run sync + processCommands", so sandboxed agents can receive the pushed uninstall. Report-side bookkeeping (plugin reconcile, binding prune, config save) stays gated behind the report path to avoid pruning host bindings not mounted in the container.
TEAMAI_ALLOW_SANDBOX_REPORT=1keeps its original meaning.Test Plan
npx tsc --noEmit— cleannpx vitest run— full suite green (1844 tests); new/updated tests cover theparseTeamaiCmdtokenizer, non-teamai rejection,TEAMAI_DISABLE_REMOTE_CMDkill switch, subcommand non-zero exit,uninstall_teamaiexecution + success ack, and the sandbox no-prune guarantee.npm run build— successteamai hook-dispatch session-start --tool codebuddyagainst a mock backend returning anuninstall_teamaicommand incmds[]— thecmdactually executed and ackedsuccess(previously, under feat(local-agent): read unified cmds[] from sync response #261 alone, it was silently skipped).🤖 Generated with Claude Code