Commit Graph

4 Commits

Author SHA1 Message Date
Michal
170dc06496 fix(cli): close third review — token collision, migration, ownership
Some checks failed
CI/CD / typecheck (pull_request) Successful in 1m5s
CI/CD / lint (pull_request) Successful in 2m13s
CI/CD / test (pull_request) Successful in 1m20s
CI/CD / build (pull_request) Successful in 2m9s
CI/CD / smoke (pull_request) Failing after 2m44s
CI/CD / publish (pull_request) Has been skipped
Round 2 fixed the first review but introduced regressions of its own, all
of which only bite against state written by the previously installed build.

`config prime-agent`:
- Mint each credential under a unique `prime-agent-<stamp>` name again.
  `McpToken` is unique on (name, projectId) and revoke is a soft delete, so
  round 2's fixed `prime-agent` name could only ever be minted once per
  project — and the revoke-first ordering destroyed the working credential
  before discovering the mint would fail.
- Provision the credential BEFORE touching settings.json. Registering the
  new project unmounts the previously active one, so a failed mint must not
  be able to leave prime-agent with no working project at all. The command
  now aborts with settings.json untouched.
- Retire only the token this auth.json actually held, once its replacement
  is stored. Sweeping every `prime-agent*` token for the project would
  revoke the credential another install (or a custom --output run) is
  using; anything else that looks orphaned is reported, not deleted.
- Validate a pre-existing credential instead of trusting its presence: a
  revoked or expired token used to short-circuit provisioning and leave
  prime-agent broken while the command reported success. Matched by
  tokenPrefix against the project's active tokens, so the secret is never
  sent. Fails open when the API can't be consulted.
- Actually write auth.json 0600. `writeFile`'s mode is ignored for an
  existing file and prime-agent creates auth.json itself at 0644, so chmod
  after writing.
- Recognise the untagged mcpServers entries older CLIs wrote (canonical
  proxy URL + an `mcp:<name>` mcpctl PAT in auth.json) so a switch unmounts
  them instead of leaving two gateways live. Hand-configured servers have
  no such credential and are still preserved. Same rule in the `/mcpctl`
  switcher's active-project lookup.
- Add `--skip-marker`, and pass it from the `/mcpctl` switcher: the
  extension runs from whatever directory prime-agent was started in, and
  was silently re-scoping that repo's `.mcpctl-project`.

`skills sync --agent prime-agent`:
- Record ownership from the skill's own scope, not the syncing project's.
  Globals were being pinned to whichever project happened to sync them,
  after which every other project refused to update them forever.
- Never adopt legacy, ownership-less state into the current scope. Round 2
  did, which deleted the other project's skills on the first sync after
  upgrading. Such entries are attributed to the project that last wrote the
  state file, and left alone when that isn't the project syncing now.
- Close the overwrite-guard bypass: a sync with no project, or a global
  landing on a project-owned name, could still clobber and re-own a
  tracked skill.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017BMXdb2qZbPSh8Q7XpTyjB
2026-08-08 12:01:52 +01:00
Michal
fa7055ac5e 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
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.
2026-08-08 11:28:15 +01:00
Michal
eb1642ab1a 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
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).
2026-08-08 10:22:46 +01:00
Michal
582f6f185b feat(cli): add mcpctl config prime-agent — proxy MCP + skills sync for prime-agent
Some checks failed
CI/CD / lint (pull_request) Successful in 1m6s
CI/CD / typecheck (pull_request) Successful in 2m10s
CI/CD / test (pull_request) Successful in 1m19s
CI/CD / smoke (pull_request) Failing after 1m53s
CI/CD / build (pull_request) Successful in 4m14s
CI/CD / publish (pull_request) Has been skipped
Mirror `mcpctl config claude` for prime-agent (which talks to the same mcpctl
proxy MCP gateway over HTTP instead of stdio):

`mcpctl config prime-agent --project X`:
- registers the proxy MCP gateway in ~/.prime/agent/settings.json as
  mcpServers.X = { type: "http", url: <gateway>/projects/X/mcp }, merging with
  any existing servers (e.g. the bundled `sre` project) and preserving all other
  settings
- writes a .mcpctl-project marker so later syncs resolve the project
- syncs the project's skills into ~/.prime/agent/skills/<name>/ as markdown
  skills (prime-agent auto-discovers them at session start)

New `mcpctl skills sync --agent prime-agent` target re-syncs the tree later.

- src/cli/src/config/prime-agent.ts: settings.json read/merge/write helpers
- src/cli/src/utils/prime-agent-skills.ts: prime-agent sync (reuses
  installSkillAtomic + skills-state; skips Claude-only hooks/postInstall)
- completes config.ts/skills.ts wiring; regenerated shell completions
- tests: commands/prime-agent.test.ts + utils/prime-agent-skills.test.ts
2026-08-08 09:34:15 +01:00