fix(cli): harden config prime-agent skills sync + install /mcpctl switcher extension #94

Closed
michal wants to merge 0 commits from feat/config-prime-agent into main
Owner

Follow-up to #93 (merged). Hardens the config prime-agent/skills sync against the silent-data-loss paths found in review, and adds the in-app /mcpctl project switcher.

Safety/correctness fixes

The shared, hand-editable ~/.prime/agent tree must never suffer silent data loss:

  • settings.json corruptionloadPrimeAgentSettings now fails loudly and refuses to overwrite a corrupt file (previously it swallowed the parse error and rewrote the whole file, destroying every non-mcpServers setting).
  • entry merge — a re-configured project's mcpServers entry is merged, preserving user-added fields, rather than replaced wholesale.
  • first-sync rm -rf — under the prime-agent target the sync preserves untracked, pre-existing skill dirs (e.g. hand-authored sre) instead of clobbering them because the state file is fresh.
  • cross-project orphan deletion — skills are ownership-tracked per project; configuring a second project no longer deletes the first project's skills.
  • mcpServers auto-attach — re-added (was dropped from the fork); kept for both targets.
  • credentialsconfig prime-agent now provisions mcp:<project> in auth.json (via --token, an existing entry, or auto-mint through POST /api/v1/mcptokens) instead of only documenting it.
  • marker — the .mcpctl-project marker is written only when none exists up-tree, and never from $HOME (running it from home used to scope every later sync).
  • exit code — the skills sync non-zero exit code is now propagated (an auth failure is reported rather than swallowed).
  • --agent validation — an unknown value errors instead of silently running the Claude sync.

DRY

The near-verbatim 180-line runPrimeAgentSkillsSync copy is gone — runSkillsSync now accepts target: 'claude' | 'prime-agent' and the prime-agent module is a thin wrapper.

New feature: /mcpctl switcher extension

config prime-agent installs a /mcpctl project-switcher extension into ~/.prime/agent/extensions/ (skip with --skip-extension). It lists projects via mcpctl get projects -o json, lets you pick one from the prime-agent TUI (ctx.ui.select), applies the switch through the CLI, and calls ctx.reload() so MCP servers, credentials and skills take effect without an app restart.

Validation

  • tsc --build clean; full CLI suite 538 tests green (new coverage: settings corruption, entry merge, auth provisioning, extension install/skip, marker $HOME handling, untracked/cross-project skill preservation, --agent validation).
  • Live end-to-end: registers settings.json + auth.json + extension; sync preserves the hand-authored sre skill.
Follow-up to #93 (merged). Hardens the `config prime-agent`/skills sync against the silent-data-loss paths found in review, and adds the in-app `/mcpctl` project switcher. ## Safety/correctness fixes The shared, hand-editable `~/.prime/agent` tree must never suffer silent data loss: - **settings.json corruption** — `loadPrimeAgentSettings` now fails loudly and refuses to overwrite a corrupt file (previously it swallowed the parse error and rewrote the whole file, destroying every non-`mcpServers` setting). - **entry merge** — a re-configured project's `mcpServers` entry is merged, preserving user-added fields, rather than replaced wholesale. - **first-sync `rm -rf`** — under the prime-agent target the sync preserves untracked, pre-existing skill dirs (e.g. hand-authored `sre`) instead of clobbering them because the state file is fresh. - **cross-project orphan deletion** — skills are ownership-tracked per project; configuring a second project no longer deletes the first project's skills. - **mcpServers auto-attach** — re-added (was dropped from the fork); kept for both targets. - **credentials** — `config prime-agent` now provisions `mcp:<project>` in `auth.json` (via `--token`, an existing entry, or auto-mint through POST `/api/v1/mcptokens`) instead of only documenting it. - **marker** — the `.mcpctl-project` marker is written only when none exists up-tree, and never from `$HOME` (running it from home used to scope every later sync). - **exit code** — the skills sync non-zero exit code is now propagated (an auth failure is reported rather than swallowed). - **`--agent` validation** — an unknown value errors instead of silently running the Claude sync. ## DRY The near-verbatim 180-line `runPrimeAgentSkillsSync` copy is gone — `runSkillsSync` now accepts `target: 'claude' | 'prime-agent'` and the prime-agent module is a thin wrapper. ## New feature: `/mcpctl` switcher extension `config prime-agent` installs a `/mcpctl` project-switcher extension into `~/.prime/agent/extensions/` (skip with `--skip-extension`). It lists projects via `mcpctl get projects -o json`, lets you pick one from the prime-agent TUI (`ctx.ui.select`), applies the switch through the CLI, and calls `ctx.reload()` so MCP servers, credentials and skills take effect without an app restart. ## Validation - `tsc --build` clean; full CLI suite **538 tests green** (new coverage: settings corruption, entry merge, auth provisioning, extension install/skip, marker `$HOME` handling, untracked/cross-project skill preservation, `--agent` validation). - Live end-to-end: registers settings.json + auth.json + extension; sync preserves the hand-authored `sre` skill.
michal added 1 commit 2026-08-08 09:25:04 +00:00
fix(cli): harden config prime-agent sync + install /mcpctl switcher extension
Some checks failed
CI/CD / lint (pull_request) Successful in 1m4s
CI/CD / typecheck (pull_request) Successful in 1m6s
CI/CD / test (pull_request) Successful in 3m9s
CI/CD / build (pull_request) Successful in 2m16s
CI/CD / smoke (pull_request) Failing after 3m27s
CI/CD / publish (pull_request) Has been skipped
eb1642ab1a
Addresses a review of the `config prime-agent` feature and adds the in-app
project switcher.

Safety/correctness fixes (prime-agent's shared, hand-editable ~/.prime/agent
tree must never suffer silent data loss):
- config/prime-agent.ts: loadPrimeAgentSettings now fails loudly on corrupt
  JSON instead of swallowing it and rewriting the file (which destroyed every
  non-mcpServers setting). A project's mcpServers entry is merged (keeping
  user-added fields) rather than replaced wholesale. Added writePrimeAgentAuth
  / hasPrimeAgentAuth helpers for auth provisioning.
- skills sync: unified the near-verbatim prime-agent copy into runSkillsSync
  via a `target: 'claude' | 'prime-agent'` option (prime-agent-skills.ts is now
  a thin wrapper). Under the prime-agent target it: preserves untracked
  pre-existing skill dirs on first sync (no more rm -rf of hand-authored `sre`),
  records per-project ownership so configuring a second project never deletes
  the first project's skills, skips Claude-only hooks/postInstall, and keeps
  the mcpServers auto-attach step.
- config.ts: `config prime-agent` now (a) provisions the bearer credential in
  auth.json (--token, existing entry, or auto-mint via POST /api/v1/mcptokens),
  (b) writes the .mcpctl-project marker only when none exists up-tree and never
  from $HOME, and (c) propagates the skills sync exit code so auth failures are
  reported instead of swallowing them.
- skills.ts: `--agent` is validated; an unknown value errors instead of
  silently running the Claude sync.

New feature: `config prime-agent` installs a `/mcpctl` project-switcher
extension into ~/.prime/agent/extensions/ (skip with --skip-extension). It lists
mcpctl projects via `mcpctl get projects -o json`, lets you pick one from the
prime-agent TUI, applies the switch through the CLI, and reloads the session.

Regenerated shell completions. Tests: 538 pass (new coverage for settings
corruption, entry merge, auth provisioning, extension install/skip, marker
$HOME handling, untracked/cross-project skill preservation, --agent validation).
michal added 1 commit 2026-08-08 10:28:25 +00:00
fix(cli): close second review on prime-agent sync + switcher (auth, ownership, switching)
Some checks failed
CI/CD / lint (pull_request) Successful in 1m4s
CI/CD / typecheck (pull_request) Successful in 1m5s
CI/CD / test (pull_request) Successful in 3m7s
CI/CD / smoke (pull_request) Failing after 3m13s
CI/CD / build (pull_request) Successful in 2m12s
CI/CD / publish (pull_request) Has been skipped
fa7055ac5e
Addresses the second round of `config prime-agent` review (10 findings).

auth.json (config/prime-agent.ts) — the settings.json data-loss fix had a twin:
- loadPrimeAgentAuth now fails loudly on corrupt JSON instead of swallow-and-
  rewrite, so one syntax error can no longer destroy the provider API key and
  every other project's credential. hasPrimeAgentAuth shares that guarantee.
- writePrimeAgentAuth writes 0600 (preserving an existing file's mode) instead
  of the default umask — bearer tokens are no longer world-readable on first
  creation.

state ownership (commands/skills.ts) — the ownership model edge cases:
- orphan-removal guard now normalises a canonical scope (project name, or null
  for globals; legacy undefined adopted to current scope) instead of comparing
  null against undefined, so global-only syncs and pre-PR state can no longer
  leave stale skills on disk forever.
- a same-named skill *tracked* to a different project is preserved (with a
  warning) rather than silently overwritten in the shared flat tree.
- mcpServers auto-attach is gated behind !isPrimeAgent with an explicit warning
  (prime-agent's HTTP gateway must not mutate shared mcpd project attachments);
  this also makes the earlier dropped-attach concern explicit rather than silent.

single-active project + switcher (config/prime-agent.ts, prime-agent-extension.ts):
- registerPrimeAgentMcp tags the project's entry mcpctlManaged:true and removes
  other mcpctl-managed entries, so prime-agent has one *active* mcpctl project
  while preserving untagged servers (hand-configured sre, websearch, etc).
- the /mcpctl extension now reads that tag as the single source of truth for the
  active project, fixing the false short-circuit / no-op switch.

config.ts command:
- an explicit -p now updates a differing up-tree .mcpctl-project marker (scope
  no longer silently reverts on the next sync), no-ops when it matches, and
  still never scopes $HOME.
- a project left with no usable credential now exits non-zero (the /mcpctl
  extension checks child exit status, so it no longer reports a successful
  switch after provisioning failed).
- skills sync is treated as best-effort: settings+auth determine switch success,
  so a skills error no longer falsely fails the switch.
- token minting now revokes prior active `prime-agent` tokens before creating a
  fresh one (no more never-expiring token litter / lost-credential duplication).

Tests (544 green): corrupt auth.json refusal, 0600 mode, mint-failure exit
code, single-active dedup preserving untagged sre, cross-project overwrite
preservation, and global-orphan removal on global-only sync.
michal closed this pull request 2026-08-08 10:30:01 +00:00
Some checks failed
CI/CD / lint (pull_request) Successful in 1m4s
CI/CD / typecheck (pull_request) Successful in 1m5s
CI/CD / test (pull_request) Successful in 3m7s
CI/CD / smoke (pull_request) Failing after 3m13s
CI/CD / build (pull_request) Successful in 2m12s
CI/CD / publish (pull_request) Has been skipped

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: michal/mcpctl#94