Skip to content

feat(cli): add Claude worker launch flags#11

Open
andrei-hasna wants to merge 11 commits into
mainfrom
codewith/claude-headless-workers-20260714
Open

feat(cli): add Claude worker launch flags#11
andrei-hasna wants to merge 11 commits into
mainfrom
codewith/claude-headless-workers-20260714

Conversation

@andrei-hasna

Copy link
Copy Markdown
Contributor

Summary\n- add first-class Claude worker flags to accounts launch/run: --headless, --background/--bg, and --name\n- keep raw passthrough semantics intact and preserve --permissions dangerous ordering\n- update launcher package provenance metadata to hasna/accounts-legacy\n- refresh generated SDK/storage kit artifacts required by release checks\n\n## Validation\n- bun install --frozen-lockfile\n- bun test src/accounts.test.ts src/login-cli.test.ts\n- bun run typecheck\n- bun test\n- rm -rf dist && bun run contracts:no-cloud-scan\n- bun run vendor-kit:check\n- bun run build\n- built dist/cli.js fake-Claude smoke for launch --headless, launch --background --name, and run --headless\n- git diff --cached --check\n- shield review\n- gitleaks protect --staged --no-banner --redact\n\n## Notes\nExternal Claude adversarial review was attempted but timed out; fallback adversarial self-review found no blocking issues.\n

…ore + ApiStore)

Consolidate the registry behind one Store abstraction: LocalStore (on-box JSON)
and ApiStore (self-hosted/cloud <API_URL>/v1 + bearer). resolveStore() is the
mode resolver from env. CLI commands and MCP tools now read/write the registry
only through the Store — no scattered cloud/local branches, no raw fetch/sqlite
outside the Store/server. Extends cloud-awareness to list/show/use/active/current/
env/launch/shell/set/rename/detect/path/remove/doctor.

- New src/lib/store.ts: AccountsStore interface + LocalStore + ApiStore + resolveStore
- Add update()/rename() to the cloud client; add PATCH-backed update + new
  POST /v1/accounts/:tool/:name/rename server endpoint (repo + schema + OpenAPI + SDK).
  NOTE: rename endpoint requires an ECS redeploy of accounts-serve.
- Depend on @hasna/contracts@0.5.2
- Tests for Store transport selection/routing, cloud update/rename, server rename
- Bump version to 0.2.0

Machine-local orchestration (apply/switch/run/login/pick/supervisor) and the
applied/toolLocks maps remain per-machine by design; they resolve the profile
record through the Store.
Complete the single-AccountsStore refactor so no CLI command, MCP tool, or
SDK method reads/writes the accounts registry via the local JSON store in
self_hosted/cloud (api) mode.

- resolveSupervisorLaunch is now async and resolves profiles + the active
  selection through the Store (was calling getProfile/currentProfile/
  appliedProfile directly from profiles.js). The machine-local applied
  pointer name still lives on-box, but its record is resolved via the Store.
- Supervised launch/restart marks the active selection via store.useProfile
  instead of the local-only useProfile, eliminating split-brain current
  writes in api mode.
- Delete dead/duplicate ensureProfileForLogin + findProfileByName from
  import-profile.ts (login uses the Store-routed existingOrCreateProfile);
  drop the stale export and tests.
…rage through the Store

Removes the dead dual code path flagged by adversarial review:
- storage.ts kept ONLY the local registry primitives (accountsHome, storePath,
  profilesDir, loadStore, saveStore). Deleted AccountsStorageMode
  local|remote|hybrid, parseMode, the S3 client, storagePush/Pull/Sync,
  snapshots, and all HASNA_ACCOUNTS_S3_* / STORAGE_MODE env plumbing. The only
  storage abstraction is now AccountsStore (LocalStore + ApiStore).
- Removed the CLI `storage status|push|pull|sync` command group and its print
  helpers (they bypassed the Store and used forbidden remote/hybrid words).
- Dropped the @aws-sdk/client-s3 dependency and its build-script external flag.

Fixes the live crash: a stale HASNA_ACCOUNTS_STORAGE_MODE=remote|hybrid|s3
(left from the S3 era) made every registry command throw via the contracts
resolver. deriveEnv now only honors the canonical local|self_hosted|cloud
words (mode's sole authority is to force local) and strips any other value so
it can never reach the resolver; URL+KEY presence remains the cloud toggle.

Reworked health/readiness storage section to report local vs self_hosted (api)
via the Store resolver instead of the deleted S3 status, and rewrote
storage.test.ts to cover the local primitives plus the legacy-mode crash
regression.
In cloud mode 'accounts tools add/remove' wrote to the local accounts.json
and never reached the shared cloud registry (split-brain). Add a cloud
custom_tools table + POST/DELETE/GET /v1/tools server routes, route the CLI
and MCP tool commands through AccountsStore.listTools/addTool/removeTool, and
have ApiStore refresh a machine-local resolution cache so synchronous
getTool/listTools still resolve cloud-registered tools for launch/apply.

Bump 0.2.1.
The health/readiness command and doctor cross-checks read profiles, custom
tools, and the per-tool 'current' selection from the local JSON file via
loadStore(), even in api (self_hosted/cloud) mode where those are cloud-owned.
On a flipped machine with an empty/stale local file this reported empty or
stale profiles and a wrong active selection while claiming transport=api — a
split-brain / routing-bar violation.

- getAccountsReadiness is now async and reads profiles, tools, and current
  through resolveStore(); 'applied' stays machine-local.
- doctor reads current through the Store and applied via loadAppliedMap().
- add loadAppliedMap(): reads the machine-local applied pointer without the
  local-profile pruning loadStore() applies, so it stays correct in api mode
  (profiles live in the cloud) and lets doctor still flag stale pointers.
- delete the dead toolsFromStore() local-merge helper.
- regression test proves api-mode readiness reflects the Store, not the file.
accounts list crashed (exit 1, "unknown tool") against the shared cloud
registry whenever it held profiles for tools not in the client's local
tool set (e.g. aicopilot, browserplan): per-profile prelaunch rendering
called getTool(), which threw and aborted the whole listing.

- prelaunchSummaryFor now degrades an unknown tool to an unsupported
  summary instead of throwing.
- list hydrates the local tool cache from the active Store first, so
  cloud-registered custom tools resolve fully (best-effort).
- action() wrapper now surfaces cloud HasnaHttpError as a single clean
  error line + exit 1 (with a redeploy hint on 404) instead of dumping
  an uncaught Node stack trace, which is what rename/tools add/tools
  remove did when they hit a stale server missing those routes.

Adds a regression test that lists profiles referencing unknown tools.
…oint

Mutating registry calls (accounts rename, tools add, tools remove) route
correctly through the Store to endpoints that already exist in src/server.
When the connected accounts-serve is an older deployed build, those routes
are absent and return a generic route-missing 404 ({"error":"not found"}).

Surface an actionable 'redeploy accounts-serve' diagnostic for that case
instead of a raw HTTP failure, while leaving genuine entity-404s untouched.
Adds regression coverage. Bump 0.2.4.
…istent profile

The ApiStore.remove path threw a plain Error for entity-not-found and
multi-tool ambiguity, so the CLI action() wrapper (which only cleans up
AccountsError + HasnaHttpError) re-threw it as an unhandled exception,
dumping a stack trace that leaked the internal cli.js path. Local mode
already threw AccountsError. Now cloud mode matches: a single clean
'error: no profile named ...' line + exit 1. Adds regression tests.
The self-host refactor enriched GET /v1/tools (full ToolDef + custom tools)
and grew the OpenAPI Tool schema's required set to
[id,label,envVar,defaultDir,bin]. The deployed 0.1.x server only guaranteed
[id,label] and never emitted defaultDir, so the change narrowed an existing
response contract and the server-redeploy safety gate flagged it non-additive.

Revert Tool.required to [id,label] and document the extra ToolDef fields as
optional, making the HTTP response contract a strict superset of the deployed
version. Runtime behavior is unchanged; old /v1 clients keep working. No route
removed/renamed; rename + custom-tool endpoints stay additive alongside.

Bump @hasna/accounts 0.2.5 -> 0.2.6.
@andrei-hasna

Copy link
Copy Markdown
Contributor Author

Launch integration review: do not merge this stack as presented. Independent adversarial review found the title/body materially understate an 11-commit, 48-file storage/API migration and server redeploy dependency. P1 defects: ApiStore.listTools mutates local cache during readiness while cold add/launch can miss cloud custom-tool hydration; mixed raw/convenience Claude flags such as --headless with raw --bg and --background with raw -p are not rejected/tested; PostgreSQL upgrade/rollback and old-client/new-server compatibility are unproven; npm 0.2.7 lacks gitHead/tag provenance. Preserve this branch and ea5a744 as evidence. Restack commits through ba5f8c4 into an explicit storage/API stabilization PR with compatibility/deployment/rollback proof and cache fixes, then replay/fix the Claude-only hunks into a separate PR and release corrected source as 0.2.8. Full review is tracked by Alumia task 466d092b.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant