vgxness 1.9.7 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/agents/canonical-agent-manifest.js +2 -2
- package/dist/cli/cli-flags.js +15 -2
- package/dist/cli/cli-help.js +13 -13
- package/dist/cli/commands/mcp-dispatcher.js +8 -4
- package/dist/cli/commands/setup-dispatcher.js +2 -2
- package/dist/cli/tui/setup/setup-tui-read-model.js +17 -17
- package/dist/cli/tui/setup/setup-tui-state.js +1 -3
- package/dist/mcp/claude-code-config.js +2 -0
- package/dist/mcp/claude-code-scope.js +1 -0
- package/dist/mcp/claude-code-user-config.js +2 -0
- package/dist/mcp/client-install-claude-code-contract.js +15 -72
- package/dist/mcp/client-install-claude-code.js +4 -6
- package/dist/mcp/client-install-opencode-contract.js +5 -79
- package/dist/mcp/opencode-visibility.js +4 -3
- package/dist/mcp/provider-change-plan.js +10 -7
- package/dist/mcp/provider-doctor.js +31 -14
- package/dist/mcp/provider-health-types.js +19 -0
- package/dist/mcp/provider-status.js +19 -10
- package/dist/mcp/schema.js +5 -4
- package/dist/mcp/validation.js +11 -1
- package/dist/setup/backup-rollback-service.js +33 -2
- package/dist/setup/providers/claude-setup-adapter.js +13 -15
- package/dist/setup/providers/opencode-setup-adapter.js +12 -12
- package/dist/setup/setup-defaults.js +1 -0
- package/dist/setup/setup-plan.js +6 -6
- package/docs/architecture.md +3 -3
- package/docs/cli.md +29 -33
- package/docs/glossary.md +2 -2
- package/docs/mcp.md +1 -1
- package/docs/prd.md +3 -3
- package/docs/providers.md +14 -15
- package/docs/roadmap.md +1 -1
- package/docs/safety.md +1 -1
- package/docs/storage.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ VGXNESS is an installable CLI, MCP control plane, and native code runtime for gu
|
|
|
6
6
|
|
|
7
7
|
This package is proprietary software. The npm package ships inspectable JavaScript (`dist/`) so Node can run it, but it is **not open-source licensed** and may not be redistributed unless you have written permission. See [LICENSE](./LICENSE).
|
|
8
8
|
|
|
9
|
-
OpenCode is the primary supported provider.
|
|
9
|
+
OpenCode is the primary supported provider. Claude setup support is secondary. VGX-managed OpenCode and Claude provider configuration is user-global only; provider config writes require explicit CLI confirmation.
|
|
10
10
|
|
|
11
11
|
VGXNESS v1.9.1 has a canonical project health audit with validated evidence: 38 MCP tools, 106 test files, and the official Bun validation path passing, including package evidence with `releaseReadiness: pass`. Current unreleased builds expose 41 MCP tools after adding read-only SDD/run recovery parity. See [Project health audit v1.9.1](./docs/project-health-audit-v1.9.1.md) for the versioned matrix and safety taxonomy.
|
|
12
12
|
|
|
@@ -150,7 +150,7 @@ vgxness sdd continue --project <project> --change <change>
|
|
|
150
150
|
vgxness code sdd <change> <phase> --project <project> --save-artifact
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
Stable defaults are: package `vgxness`, provider `opencode`, global user data DB, user
|
|
153
|
+
Stable defaults are: package `vgxness`, provider `opencode`, global user data DB, user-global OpenCode config (`$HOME/.config/opencode/opencode.json`), and `mcp-plus-agents` mode. VGX-managed OpenCode and Claude provider configuration is user-global only; runtime VGXNESS state remains project-aware through `--project`, `--change`, workspace, and database context. Existing project-local provider files such as `.opencode/`, `opencode.json`, `.mcp.json`, `.claude/`, and `CLAUDE.md` remain untouched by VGXNESS setup. They may still affect OpenCode or Claude behavior externally, but VGXNESS treats them as external/manual diagnostics and will not repair, write, back up, or delete them. The generated MCP command for the global DB default is:
|
|
154
154
|
|
|
155
155
|
```bash
|
|
156
156
|
vgxness mcp start
|
|
@@ -182,7 +182,8 @@ Edits, shell, network, git mutations, SDD persistence, and memory saves route th
|
|
|
182
182
|
## Safety model
|
|
183
183
|
|
|
184
184
|
- Preview, status, and plan commands do not write provider config; local VGXNESS store initialization may occur where the command needs SQLite-backed state.
|
|
185
|
-
-
|
|
185
|
+
- VGX-managed OpenCode and Claude provider config writes are user-global only and require explicit `--yes` confirmation.
|
|
186
|
+
- Runtime VGXNESS state remains project-aware; project-local provider files are read-only external/manual diagnostics and may still affect provider behavior outside VGXNESS.
|
|
186
187
|
- Setup/status TUI surfaces are read-only setup, diagnostics, recovery, and fallback surfaces; daily SDD progression stays in OpenCode with VGXNESS MCP.
|
|
187
188
|
- SDD artifacts are SQLite-backed through VGXNESS services. Do not create or write `openspec/`.
|
|
188
189
|
- `vgxness sdd accept-artifact` records explicit human-only acceptance; saving a draft never implies acceptance.
|
|
@@ -260,7 +261,7 @@ Do not publish from CI. Publication or registry dry-run checks require separate
|
|
|
260
261
|
npm uninstall -g vgxness
|
|
261
262
|
```
|
|
262
263
|
|
|
263
|
-
Remove any OpenCode config entries and local/global VGXNESS data manually if you no longer need them.
|
|
264
|
+
Remove any user-global OpenCode/Claude config entries and local/global VGXNESS data manually if you no longer need them. Project-local provider files are external/manual and are not created, repaired, or deleted by VGXNESS setup.
|
|
264
265
|
|
|
265
266
|
## More docs
|
|
266
267
|
|
|
@@ -207,12 +207,12 @@ const registryManagerInstructionsV10 = [
|
|
|
207
207
|
'OpenCode native/provider tools are governance-v1 audit-only/non-hard-blocking; report warnings, never say they are hard-blocked by config.',
|
|
208
208
|
].join(' ');
|
|
209
209
|
const subagentData = {
|
|
210
|
-
'vgxness-sdd-explore': { seedDescription: 'Investigates codebase context and identifies options before proposals.', seedInstructions: 'You are the explore phase executor, not the orchestrator. Do not delegate. Explore repository evidence for the requested SDD change. Do not implement code changes. Return concise findings, risks, and recommended next artifacts.', capabilities: ['sdd-exploration', 'codebase-research', 'discovery'], permissions: { read: 'allow', edit: 'deny', shell: '
|
|
210
|
+
'vgxness-sdd-explore': { seedDescription: 'Investigates codebase context and identifies options before proposals.', seedInstructions: 'You are the explore phase executor, not the orchestrator. Do not delegate. Explore repository evidence for the requested SDD change. Do not implement code changes. Return concise findings, risks, and recommended next artifacts.', capabilities: ['sdd-exploration', 'codebase-research', 'discovery'], permissions: { read: 'allow', edit: 'deny', shell: 'allow', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:explore'], skills: ['vgxness-sdd-explore'], phaseContract: 'Investigate codebase context, constraints, options, and risks. Do not implement code changes. Return findings and recommended next artifacts.' },
|
|
211
211
|
'vgxness-sdd-propose': { seedDescription: 'Creates focused change proposals from exploration findings.', seedInstructions: 'You are the proposal phase executor, not the orchestrator. Do not delegate. Create a focused SDD proposal from exploration evidence. Do not implement code changes. Identify scope, tradeoffs, non-goals, and acceptance direction.', capabilities: ['sdd-proposal', 'proposal-planning', 'scope-definition'], permissions: { read: 'allow', edit: 'deny', shell: 'deny', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:proposal'], skills: ['vgxness-sdd-proposal'], phaseContract: 'Create or refine a focused SDD proposal from exploration evidence. Do not implement code changes. Include scope, tradeoffs, non-goals, and acceptance direction.' },
|
|
212
212
|
'vgxness-sdd-spec': { seedDescription: 'Writes detailed requirements and acceptance criteria for SDD changes.', seedInstructions: 'You are the spec phase executor, not the orchestrator. Do not delegate. Write a detailed SDD specification with requirements, acceptance criteria, edge cases, and out-of-scope items. Do not implement code changes.', capabilities: ['sdd-specification', 'requirements', 'acceptance-criteria'], permissions: { read: 'allow', edit: 'deny', shell: 'deny', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:spec'], skills: ['vgxness-sdd-spec'], phaseContract: 'Write requirements, acceptance criteria, edge cases, and out-of-scope items. Do not implement code changes.' },
|
|
213
213
|
'vgxness-sdd-design': { seedDescription: 'Creates technical design from accepted proposals and accepted or trusted draft specs.', seedInstructions: 'You are the design phase executor, not the orchestrator. Do not delegate. Create a technical design grounded in the repository. Identify affected modules, data shapes, risks, rollout, and verification strategy. Do not implement code changes.', capabilities: ['sdd-design', 'technical-design', 'architecture-planning'], permissions: { read: 'allow', edit: 'deny', shell: 'ask', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:design'], skills: ['vgxness-sdd-design'], phaseContract: 'Create technical design grounded in the repository: affected modules, data shapes, safety, rollout, and verification. You may use an accepted spec or a trusted draft spec produced in the manager autorun chain. Do not implement code changes.' },
|
|
214
214
|
'vgxness-sdd-tasks': { seedDescription: 'Breaks accepted or trusted draft specs and designs into implementation tasks.', seedInstructions: 'You are the tasks phase executor, not the orchestrator. Do not delegate. Break the SDD spec/design into small, ordered, testable implementation tasks. Do not implement code changes.', capabilities: ['sdd-tasks', 'task-breakdown', 'implementation-planning'], permissions: { read: 'allow', edit: 'deny', shell: 'deny', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:tasks'], skills: ['vgxness-sdd-tasks'], phaseContract: 'Break accepted or trusted draft spec/design into small ordered testable implementation tasks. Do not implement code changes.' },
|
|
215
|
-
'vgxness-sdd-apply': { seedDescription: 'Implements code changes from SDD task definitions.', seedInstructions: 'You are the apply phase executor, not the orchestrator. Implement only the assigned SDD tasks directly. Do not delegate. Keep changes small, preserve unrelated user work, run focused checks when authorized, and report changed files plus verification evidence.', capabilities: ['sdd-apply', 'implementation', 'code-change'], permissions: { read: 'allow', edit: 'ask', shell: '
|
|
215
|
+
'vgxness-sdd-apply': { seedDescription: 'Implements code changes from SDD task definitions.', seedInstructions: 'You are the apply phase executor, not the orchestrator. Implement only the assigned SDD tasks directly. Do not delegate. Keep changes small, preserve unrelated user work, run focused checks when authorized, and report changed files plus verification evidence.', capabilities: ['sdd-apply', 'implementation', 'code-change'], permissions: { read: 'allow', edit: 'ask', shell: 'allow', git: 'ask', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:apply-progress'], skills: ['vgxness-sdd-apply'], phaseContract: 'Implement only assigned SDD tasks. Preserve unrelated dirty files and user work. Use focused tests when authorized. Report changed files, tests/evidence, and residual risks.' },
|
|
216
216
|
'vgxness-sdd-verify': { seedDescription: 'Validates implementation against specs, tasks, and evidence.', seedInstructions: 'You are the verify phase executor, not the orchestrator. Do not delegate. Verify the implementation against SDD artifacts. Prefer focused local tests, inspect evidence, and report residual risk. Do not implement unrelated changes.', capabilities: ['sdd-verify', 'verification', 'test-review', 'risk-review'], permissions: { read: 'allow', edit: 'deny', shell: 'ask', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:verify'], skills: ['vgxness-sdd-verify'], phaseContract: 'Validate implementation against SDD artifacts and task acceptance criteria. Prefer focused local tests and evidence review. Do not implement unrelated changes.' },
|
|
217
217
|
'vgxness-sdd-archive': { seedDescription: 'Archives completed SDD change artifacts and outcomes.', seedInstructions: 'You are the archive phase executor, not the orchestrator. Do not delegate. Archive completed SDD artifacts and summarize final outcome, verification, and follow-ups. Confirm before writes beyond the requested archive artifact.', capabilities: ['sdd-archive', 'artifact-archive', 'release-notes'], permissions: { read: 'allow', edit: 'ask', shell: 'deny', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:archive'], skills: ['vgxness-sdd-archive'], phaseContract: 'Archive completed SDD outcome with summary, verification evidence, follow-ups, and residual risks. Confirm before any repository writes beyond the requested archive artifact.' },
|
|
218
218
|
'vgxness-sdd-init': { seedDescription: 'Bootstraps SDD context and project configuration.', seedInstructions: 'You are the init phase executor, not the orchestrator. Do not delegate. Initialize SDD context and project setup safely. Prefer read-only diagnostics and explicit user confirmation before writes or provider/global config changes.', capabilities: ['sdd-init', 'setup', 'bootstrap'], permissions: { read: 'allow', edit: 'ask', shell: 'ask', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:init', 'setup'], skills: [], phaseContract: 'Bootstrap SDD context and project setup safely. Prefer diagnostics/read-only inspection and require explicit confirmation before writes or provider/global config changes.' },
|
package/dist/cli/cli-flags.js
CHANGED
|
@@ -112,9 +112,22 @@ function optionalScopeFlag(flags, name) {
|
|
|
112
112
|
return { ok: true, value: undefined };
|
|
113
113
|
return value === 'project' || value === 'personal' ? { ok: true, value } : validationFailure(`--${name} must be project or personal`);
|
|
114
114
|
}
|
|
115
|
+
const providerUserGlobalOnlyMigrationMessage = 'VGX-managed provider configuration is user-global only for OpenCode and Claude. Project/local provider files are treated as external/manual diagnostics and will not be written by VGXNESS. Re-run without the project/local install scope.';
|
|
115
116
|
function opencodeInstallScopeFlag(flags, name) {
|
|
116
117
|
const value = optionalStringFlag(flags, name) ?? vgxnessSetupDefaults.defaultOpenCodeScope;
|
|
117
|
-
|
|
118
|
+
if (value === 'user' || value === 'global' || value === 'personal')
|
|
119
|
+
return { ok: true, value: 'user' };
|
|
120
|
+
if (value === 'project' || value === 'local')
|
|
121
|
+
return validationFailure(providerUserGlobalOnlyMigrationMessage);
|
|
122
|
+
return validationFailure(`--${name} must be user, global, or personal`);
|
|
123
|
+
}
|
|
124
|
+
function opencodeDiagnosticScopeFlag(flags, name) {
|
|
125
|
+
const value = optionalStringFlag(flags, name) ?? vgxnessSetupDefaults.defaultOpenCodeScope;
|
|
126
|
+
if (value === 'user' || value === 'global' || value === 'personal')
|
|
127
|
+
return { ok: true, value: 'user' };
|
|
128
|
+
if (value === 'project')
|
|
129
|
+
return { ok: true, value };
|
|
130
|
+
return validationFailure(`--${name} must be user, global, personal, or project`);
|
|
118
131
|
}
|
|
119
132
|
function optionalModeFlag(flags, name) {
|
|
120
133
|
const value = optionalStringFlag(flags, name);
|
|
@@ -325,4 +338,4 @@ function setupInstallModeFlag(flags) {
|
|
|
325
338
|
return { ok: true, value: 'mcp-only' };
|
|
326
339
|
return { ok: true, value: vgxnessSetupDefaults.defaultInstallMode };
|
|
327
340
|
}
|
|
328
|
-
export { acceptedAtFlag, codeApprovalPolicyFlag, codeMemoryPolicyFlag, codeTranscriptModeFlag, codeVerificationModeFlag, csvFlag, databasePathFor, databasePathSelectionFor, finalRunStatusFlag, instructionKindFlag, isRunStatus, isSkillEvaluationResultStatus, isSkillTargetType, jsonFlag, opencodeInstallScopeFlag, optionalJsonFlag, optionalModeFlag, optionalNumberFlag, optionalRunStatusFlag, optionalScopeFlag, optionalSkillEvaluationResultStatusFlag, optionalSkillImprovementProposalStatusFlag, optionalSkillResolutionUsageFlag, optionalSkillTargetTypeFlag, optionalSkillVersionStatusFlag, optionalStringFlag, optionalTrimmedFlag, parseArgs, permissionCategoryFlag, requiredFlag, requiredTrimmedFlag, retryPolicyFlag, runOutcomeFlag, scopeFlag, setupDatabaseFlags, setupInstallModeFlag, setupProviderFlag, skillEvaluationResultStatusFlag, skillSourceFromFlags, skillSourceKindFlag, skillTargetTypeFlag, skillUsageOutcomeFlag, };
|
|
341
|
+
export { acceptedAtFlag, codeApprovalPolicyFlag, codeMemoryPolicyFlag, codeTranscriptModeFlag, codeVerificationModeFlag, csvFlag, databasePathFor, databasePathSelectionFor, finalRunStatusFlag, instructionKindFlag, isRunStatus, isSkillEvaluationResultStatus, isSkillTargetType, jsonFlag, providerUserGlobalOnlyMigrationMessage, opencodeDiagnosticScopeFlag, opencodeInstallScopeFlag, optionalJsonFlag, optionalModeFlag, optionalNumberFlag, optionalRunStatusFlag, optionalScopeFlag, optionalSkillEvaluationResultStatusFlag, optionalSkillImprovementProposalStatusFlag, optionalSkillResolutionUsageFlag, optionalSkillTargetTypeFlag, optionalSkillVersionStatusFlag, optionalStringFlag, optionalTrimmedFlag, parseArgs, permissionCategoryFlag, requiredFlag, requiredTrimmedFlag, retryPolicyFlag, runOutcomeFlag, scopeFlag, setupDatabaseFlags, setupInstallModeFlag, setupProviderFlag, skillEvaluationResultStatusFlag, skillSourceFromFlags, skillSourceKindFlag, skillTargetTypeFlag, skillUsageOutcomeFlag, };
|
package/dist/cli/cli-help.js
CHANGED
|
@@ -9,9 +9,9 @@ Areas:
|
|
|
9
9
|
status [--project <name>] [--change <id>] [--db <path>] [--json]
|
|
10
10
|
next [--project <name>] [--change <id>] [--db <path>] [--json]
|
|
11
11
|
resume [--project <name>] [--run-id <id>] [--db <path>] [--json]
|
|
12
|
-
init [--project <name>] [--provider opencode|claude|none] [--scope user|
|
|
13
|
-
setup plan [--project <name>] [--provider opencode|claude|none] [--scope user|
|
|
14
|
-
setup apply --yes [--project <name>] [--provider opencode|claude|none] [--scope user|
|
|
12
|
+
init [--project <name>] [--provider opencode|claude|none] [--scope user|global|personal] [--db global|project-local|custom|<path>] [--db-path <path>] [--mode mcp-only|mcp-plus-agents] [--json]
|
|
13
|
+
setup plan [--project <name>] [--provider opencode|claude|none] [--scope user|global|personal] [--db global|project-local|custom|<path>] [--db-path <path>] [--mode mcp-only|mcp-plus-agents] [--json]
|
|
14
|
+
setup apply --yes [--project <name>] [--provider opencode|claude|none] [--scope user|global|personal] [--db global|project-local|custom|<path>] [--db-path <path>] [--mode mcp-only|mcp-plus-agents]
|
|
15
15
|
setup backup list --provider opencode [--scope project|user|global] [--target <path>] [--json]
|
|
16
16
|
setup rollback --backup <path> [--preview|--yes] [--json]
|
|
17
17
|
setup status [--project <name>] [--scope project|personal] [--db <path>] [--json]
|
|
@@ -23,7 +23,7 @@ Areas:
|
|
|
23
23
|
Next answers "what should I do now?" with a shorter next-action view.
|
|
24
24
|
Resume answers "how do I continue interrupted work?" with run inspection guidance.
|
|
25
25
|
Without --change or --run-id they stay orientation-only and do not open local memory; with --change or --run-id they read SQLite read-only. Pass --json for automation.
|
|
26
|
-
Setup plan/init default to human-readable read-only output; pass --json for automation.
|
|
26
|
+
Setup plan/init default to human-readable read-only output; pass --json for automation. VGX-managed provider configuration is user-global only for OpenCode and Claude; setup apply writes provider config only with --yes and uses the global user DB plus mcp-plus-agents by default.
|
|
27
27
|
Setup status defaults to human-readable read-only output; pass --json for automation. It never writes provider config or executes providers.
|
|
28
28
|
Doctor defaults to human-readable output; pass --json for automation.
|
|
29
29
|
Verification plans are read-only recommendations only; they never execute commands, write provider config, persist results, mutate SDD artifacts, or infer acceptance.
|
|
@@ -64,19 +64,19 @@ Areas:
|
|
|
64
64
|
Approval commands resolve explicit run/preflight approval records; they do not change agent seed permissions or globally allow shell/provider access.
|
|
65
65
|
|
|
66
66
|
mcp setup --preview --provider opencode|claude [--db <path>]
|
|
67
|
-
mcp install opencode --plan [--scope user|
|
|
68
|
-
mcp install opencode --yes [--scope user|
|
|
69
|
-
mcp install claude --plan [--scope
|
|
70
|
-
mcp install claude --yes --run-id <id> [--scope
|
|
67
|
+
mcp install opencode --plan [--scope user|global|personal] [--db <path>] [--mcp-only|--no-agents] [--overwrite-vgxness|--reinstall]
|
|
68
|
+
mcp install opencode --yes [--scope user|global|personal] [--db <path>] [--mcp-only|--no-agents] [--overwrite-vgxness|--reinstall]
|
|
69
|
+
mcp install claude --plan [--scope user|global|personal] [--db <path>] [--overwrite-vgxness|--reinstall]
|
|
70
|
+
mcp install claude --yes --run-id <id> [--scope user|global|personal] [--db <path>] [--phase <phase>] [--agent-id <id>] [--overwrite-vgxness|--reinstall]
|
|
71
71
|
mcp doctor opencode [--scope user|project] [--project-root <path>]
|
|
72
72
|
mcp doctor [--db <path>] [--project <name>] [--change <id>] [--timeout-ms <ms>]
|
|
73
73
|
MCP setup preview is read-only; it does not install or write .opencode/, .claude/, or provider config.
|
|
74
74
|
Without --db, MCP install and setup commands use the vgxness global default database; pass --db .vgx/memory.sqlite for project-local compatibility.
|
|
75
|
-
OpenCode install defaults to user
|
|
75
|
+
OpenCode install defaults to user-global scope and installs mcp.vgxness plus top-level permission.bash=ask, vgxness-manager with bash=allow, and hidden vgxness-sdd-* agents with explicit permissions; use --mcp-only for legacy MCP-only config.
|
|
76
76
|
Use --overwrite-vgxness (alias --reinstall) to reinstall only VGXNESS-managed OpenCode entries while preserving unrelated config; --yes is still required to write.
|
|
77
|
-
It writes only after --yes.
|
|
78
|
-
Project
|
|
79
|
-
Claude support is first-class for guarded MCP setup. Claude
|
|
77
|
+
It writes only after --yes. VGX-managed provider configuration is user-global only for OpenCode and Claude; the OpenCode target is $HOME/.config/opencode/opencode.json.
|
|
78
|
+
Project/local provider files are external/manual diagnostics and will not be written by VGXNESS. Plans are read-only; applies refuse unsafe existing user-global config and create backups before merge.
|
|
79
|
+
Claude support is first-class for guarded MCP setup. Claude user/global/personal scopes all target user-global managed config. Confirmed Claude writes narrowly merge mcpServers.vgxness in ~/.claude.json, write ~/.claude/agents/*.md, and manage only the VGXNESS block in ~/.claude/CLAUDE.md. Confirmed Claude writes/CLI execution require VGXNESS run preflight metadata (--run-id, with optional --phase/--agent-id). Status/doctor/change-plan are read-only and do not execute Claude Code.
|
|
80
80
|
|
|
81
81
|
skills register --project <name> --name <name> --description <text>
|
|
82
82
|
skills list [--project <name>] [--scope project|personal]
|
|
@@ -105,7 +105,7 @@ Areas:
|
|
|
105
105
|
No args in an interactive TTY opens the OpenTUI main menu.
|
|
106
106
|
No args without a TTY prints static safe setup guidance and exits 0 without opening project state.
|
|
107
107
|
Setup TUI may launch without --project; Installation remains available and project-scoped checks are deferred while project screens render project-required recovery states.
|
|
108
|
-
Provider setup support: OpenCode first-class supported default guided install; Claude first-class supported guarded install
|
|
108
|
+
Provider setup support: OpenCode first-class supported default guided install; Claude first-class supported guarded user-global install; project/local provider files are diagnostics only; Antigravity placeholder; Custom/future extension point.
|
|
109
109
|
Provider config writes/install/apply are external-only and require explicit confirmation.
|
|
110
110
|
|
|
111
111
|
sdd status --project <name> --change <id> [--json]
|
|
@@ -9,7 +9,7 @@ import { resolveClaudeCodeScope } from '../../mcp/claude-code-scope.js';
|
|
|
9
9
|
import { computeEffectiveManagerInstructions } from '../../agents/manager-profile-overlay-service.js';
|
|
10
10
|
import { RunService } from '../../runs/run-service.js';
|
|
11
11
|
import { isTerminalRunStatus } from '../../runs/schema.js';
|
|
12
|
-
import { databasePathFor, databasePathSelectionFor, opencodeInstallScopeFlag, optionalNumberFlag, optionalStringFlag } from '../cli-flags.js';
|
|
12
|
+
import { databasePathFor, databasePathSelectionFor, opencodeDiagnosticScopeFlag, opencodeInstallScopeFlag, optionalNumberFlag, optionalStringFlag, providerUserGlobalOnlyMigrationMessage, } from '../cli-flags.js';
|
|
13
13
|
import { usageFailure, validationFailure } from '../cli-help.js';
|
|
14
14
|
import { jsonResult, openCliDatabase, resultFailure } from '../cli-helpers.js';
|
|
15
15
|
import { renderDoctorReport } from '../doctor-renderer.js';
|
|
@@ -129,8 +129,12 @@ export function runMcpInstallCommand(parsed, environment) {
|
|
|
129
129
|
}
|
|
130
130
|
function claudeInstallScopeFlag(flags) {
|
|
131
131
|
const value = optionalStringFlag(flags, 'scope');
|
|
132
|
-
const resolved = resolveClaudeCodeScope(value);
|
|
133
|
-
|
|
132
|
+
const resolved = resolveClaudeCodeScope(value, 'user');
|
|
133
|
+
if (!resolved.ok)
|
|
134
|
+
return validationFailure(resolved.error.message);
|
|
135
|
+
if (resolved.value.canonical === 'project' || resolved.value.canonical === 'local')
|
|
136
|
+
return validationFailure(providerUserGlobalOnlyMigrationMessage);
|
|
137
|
+
return { ok: true, value: resolved.value.canonical };
|
|
134
138
|
}
|
|
135
139
|
function createClaudeCodeInstallPreflight(parsed, database, environment) {
|
|
136
140
|
return (request) => {
|
|
@@ -211,7 +215,7 @@ export function runMcpDoctorCommand(parsed, environment, output = 'json') {
|
|
|
211
215
|
})();
|
|
212
216
|
}
|
|
213
217
|
export function runMcpDoctorOpenCodeCommand(parsed, environment) {
|
|
214
|
-
const scope =
|
|
218
|
+
const scope = opencodeDiagnosticScopeFlag(parsed.flags, 'scope');
|
|
215
219
|
if (!scope.ok)
|
|
216
220
|
return resultFailure(scope);
|
|
217
221
|
const projectRoot = optionalStringFlag(parsed.flags, 'project-root');
|
|
@@ -9,7 +9,7 @@ import { applyRollbackConfigBackup, listProviderConfigBackups, previewRollbackCo
|
|
|
9
9
|
import { vgxnessSetupDefaults } from '../../setup/setup-defaults.js';
|
|
10
10
|
import { SetupLifecycleService } from '../../setup/setup-lifecycle-service.js';
|
|
11
11
|
import { createSetupPlan } from '../../setup/setup-plan.js';
|
|
12
|
-
import { databasePathFor, databasePathSelectionFor, opencodeInstallScopeFlag, optionalStringFlag, scopeFlag, setupDatabaseFlags, setupInstallModeFlag, setupProviderFlag, } from '../cli-flags.js';
|
|
12
|
+
import { databasePathFor, databasePathSelectionFor, opencodeInstallScopeFlag, optionalStringFlag, providerUserGlobalOnlyMigrationMessage, scopeFlag, setupDatabaseFlags, setupInstallModeFlag, setupProviderFlag, } from '../cli-flags.js';
|
|
13
13
|
import { okText, usageFailure, validationFailure } from '../cli-help.js';
|
|
14
14
|
import { jsonResult, openCliDatabase, resultFailure } from '../cli-helpers.js';
|
|
15
15
|
import { renderSetupPlan } from '../setup-plan-renderer.js';
|
|
@@ -141,7 +141,7 @@ export async function applySetupPlanInput(input, environment) {
|
|
|
141
141
|
ok: true,
|
|
142
142
|
value: {
|
|
143
143
|
status: 'manual-required',
|
|
144
|
-
message:
|
|
144
|
+
message: `Claude setup apply is intentionally non-mutating here; use vgxness mcp install claude --yes --run-id <id> for guarded user-global Claude writes. ${providerUserGlobalOnlyMigrationMessage}`,
|
|
145
145
|
plan: plan.value,
|
|
146
146
|
},
|
|
147
147
|
};
|
|
@@ -35,20 +35,20 @@ export function setupTuiViewModelFromPlan(plan, status, state) {
|
|
|
35
35
|
databaseLabel: plan === undefined ? 'pending' : plan.db.mode,
|
|
36
36
|
databasePathLabel: compactPath(databasePath, 72),
|
|
37
37
|
databaseSourceLabel: String(databaseSource),
|
|
38
|
-
scopeLabel: isOpenCode ?
|
|
38
|
+
scopeLabel: isOpenCode ? 'user-global provider config' : isClaude ? 'User-global Claude config only; project-local files are diagnostics' : 'Manual / none (OpenCode controls disabled)',
|
|
39
39
|
installModeLabel: isOpenCode
|
|
40
40
|
? opencode?.installsAgents === false
|
|
41
41
|
? 'mcp-only'
|
|
42
42
|
: (selections?.installMode ?? 'mcp-plus-agents')
|
|
43
43
|
: isClaude
|
|
44
|
-
? 'Claude guarded apply outside guided OpenCode install'
|
|
44
|
+
? 'Claude guarded user-global apply outside guided OpenCode install'
|
|
45
45
|
: 'Manual / none (no OpenCode install)',
|
|
46
|
-
targetPathLabel: isOpenCode && opencode?.targetPath !== undefined ? compactPath(opencode.targetPath, 72) : isClaude ? 'Claude targets: .
|
|
47
|
-
opencodeActionLabel: isOpenCode ? opencodeActionLabel(opencode?.action) : isClaude ? 'No guided setup write; use guarded Claude install with run preflight.' : 'No automatic provider write; use manual setup guidance.',
|
|
46
|
+
targetPathLabel: isOpenCode && opencode?.targetPath !== undefined ? compactPath(opencode.targetPath, 72) : isClaude ? 'Claude targets: user-global ~/.claude.json, ~/.claude/agents/*.md, ~/.claude/CLAUDE.md via guarded apply' : 'No provider config target; manual/no-provider-write mode',
|
|
47
|
+
opencodeActionLabel: isOpenCode ? opencodeActionLabel(opencode?.action) : isClaude ? 'No guided setup write; use guarded user-global Claude install with run preflight.' : 'No automatic provider write; use manual setup guidance.',
|
|
48
48
|
memoryPathExplanation: memoryExplanation,
|
|
49
49
|
providerInstallabilityLabel: isOpenCode
|
|
50
|
-
? 'OpenCode is the default guided install provider. Claude is first-class supported via guarded mcp install claude --
|
|
51
|
-
: 'Manual / none is read-only guidance. Claude remains supported through explicit guarded apply outside this guided OpenCode flow.',
|
|
50
|
+
? 'OpenCode is the default guided install provider. VGXNESS will manage user-global provider configuration. Claude is first-class supported via guarded mcp install claude --yes --run-id <id>. Project-local provider files are external/manual diagnostics and will not be modified.'
|
|
51
|
+
: 'Manual / none is read-only guidance. Claude remains supported through explicit guarded user-global apply outside this guided OpenCode flow.',
|
|
52
52
|
agentReadinessLabel: agentReadiness.label,
|
|
53
53
|
agentReadinessDetail: agentReadiness.detail,
|
|
54
54
|
plannedActions: plan?.actions.map((action) => ({
|
|
@@ -63,8 +63,8 @@ export function setupTuiViewModelFromPlan(plan, status, state) {
|
|
|
63
63
|
nextCommands: plan?.nextCommands ?? ['vgxness setup plan'],
|
|
64
64
|
canAutoApply: plan?.provider === 'opencode' && plan.status === 'ready' && state?.selections.provider !== 'none' && plan.opencode !== undefined,
|
|
65
65
|
safetyWarning: isOpenCode && (selections?.overwriteVgxness === true || opencode?.overwriteVgxness === true)
|
|
66
|
-
? 'Final confirmation is required. Reinstall is enabled: VGXNESS OpenCode entries will be overwritten after a managed backup when the target exists; unrelated config is preserved.'
|
|
67
|
-
: 'Final confirmation is required before any provider config write.
|
|
66
|
+
? 'Final confirmation is required. Reinstall is enabled: user-global VGXNESS OpenCode entries will be overwritten after a managed backup when the target exists; unrelated config is preserved. Project-local provider files are external/manual diagnostics and will not be modified.'
|
|
67
|
+
: 'Final confirmation is required before any provider config write. VGXNESS will manage user-global provider configuration. Project-local provider files are external/manual diagnostics and will not be modified.',
|
|
68
68
|
frameLabel: 'VGXNESS Setup Assistant workspace',
|
|
69
69
|
progressLabel: progressLabel(state?.screen),
|
|
70
70
|
previewLabel,
|
|
@@ -78,14 +78,13 @@ export function setupTuiViewModelFromPlan(plan, status, state) {
|
|
|
78
78
|
choice('database:custom', 'Custom database path', 'Deferred/read-only in the TUI unless already supplied by flags or environment.', selections?.databaseMode === 'custom' || (selections === undefined && plan?.db.mode === 'custom'), state?.focusedChoiceId, [badgeLabels.deferred, badgeLabels.readOnly]),
|
|
79
79
|
],
|
|
80
80
|
providerChoices: [
|
|
81
|
-
choice('provider:opencode', 'OpenCode', 'Default guided install provider
|
|
82
|
-
choice('provider:claude-supported', 'Claude (first-class supported)', 'Claude CLI MCP registration and
|
|
81
|
+
choice('provider:opencode', 'OpenCode', 'Default guided install provider. VGXNESS will manage user-global provider configuration.', (selections?.provider ?? plan?.provider ?? 'opencode') === 'opencode', state?.focusedChoiceId, [badgeLabels.recommended]),
|
|
82
|
+
choice('provider:claude-supported', 'Claude (first-class supported)', 'Claude user-global CLI MCP registration and config apply only via guarded mcp install claude --yes --run-id <id>; project-local files are diagnostics only.', (selections?.provider ?? plan?.provider) === 'claude', state?.focusedChoiceId, ['[supported]', badgeLabels.readOnly]),
|
|
83
83
|
choice('provider:none', 'Manual / none', 'No automatic provider config write; follow manual setup guidance.', (selections?.provider ?? plan?.provider) === 'none', state?.focusedChoiceId, [badgeLabels.manual, badgeLabels.readOnly]),
|
|
84
84
|
],
|
|
85
85
|
scopeChoices: isOpenCode
|
|
86
86
|
? [
|
|
87
|
-
choice('scope:user', 'User
|
|
88
|
-
choice('scope:project', 'Project scope', 'Opt in to writing project OpenCode config only after final confirmation.', (selections?.scope ?? opencode?.scope) === 'project', state?.focusedChoiceId, [badgeLabels.writeAfterConfirm]),
|
|
87
|
+
choice('scope:user', 'User-global provider config', 'VGXNESS will manage user-global provider configuration. Project-local provider files are external/manual diagnostics and will not be modified.', true, state?.focusedChoiceId, [badgeLabels.recommended, badgeLabels.writeAfterConfirm]),
|
|
89
88
|
]
|
|
90
89
|
: [],
|
|
91
90
|
installModeChoices: isOpenCode
|
|
@@ -96,7 +95,7 @@ export function setupTuiViewModelFromPlan(plan, status, state) {
|
|
|
96
95
|
: [],
|
|
97
96
|
overwriteChoices: isOpenCode
|
|
98
97
|
? [
|
|
99
|
-
choice('overwrite:vgxness', 'Reinstall VGXNESS entries', 'Default off. When enabled, final confirmation overwrites existing VGXNESS OpenCode entries and preserves unrelated OpenCode config.', selections?.overwriteVgxness ?? opencode?.overwriteVgxness ?? false, state?.focusedChoiceId, [badgeLabels.warning, badgeLabels.writeAfterConfirm]),
|
|
98
|
+
choice('overwrite:vgxness', 'Reinstall VGXNESS entries', 'Default off. When enabled, final confirmation overwrites existing user-global VGXNESS OpenCode entries and preserves unrelated OpenCode config.', selections?.overwriteVgxness ?? opencode?.overwriteVgxness ?? false, state?.focusedChoiceId, [badgeLabels.warning, badgeLabels.writeAfterConfirm]),
|
|
100
99
|
]
|
|
101
100
|
: [],
|
|
102
101
|
};
|
|
@@ -109,10 +108,10 @@ function previewDetailLines(input) {
|
|
|
109
108
|
`Provider: ${input.provider === 'opencode' ? 'OpenCode [recommended default]' : input.provider === 'claude' ? 'Claude [first-class supported] [guarded explicit apply]' : 'Manual / none [manual] [read-only]'}`,
|
|
110
109
|
`Memory path: ${plan?.db.mode ?? 'pending'} at ${compactPath(input.databasePath, 72)} (source: ${String(input.databaseSource)})`,
|
|
111
110
|
`Memory guidance: ${memoryPathExplanation(plan, input.databasePath, input.databaseSource)}`,
|
|
112
|
-
`Scope: ${input.isOpenCode ?
|
|
111
|
+
`Scope: ${input.isOpenCode ? 'user-global provider config' : 'disabled for manual/none provider'}`,
|
|
113
112
|
`Install mode: ${input.isOpenCode ? (opencode?.installsAgents === false ? 'mcp-only' : 'mcp-plus-agents') : 'disabled for manual/none provider'}`,
|
|
114
113
|
`Reinstall VGXNESS entries: ${input.isOpenCode ? String(opencode?.overwriteVgxness ?? false) : 'disabled for manual/none provider'}`,
|
|
115
|
-
`Provider installability: ${input.isOpenCode ? 'OpenCode installable after final confirmation
|
|
114
|
+
`Provider installability: ${input.isOpenCode ? 'OpenCode installable after final confirmation. VGXNESS will manage user-global provider configuration. Claude first-class support requires guarded mcp install claude --yes --run-id <id>. Project-local provider files are external/manual diagnostics and will not be modified.' : 'No guided provider install from this selection; Claude uses guarded explicit user-global apply.'}`,
|
|
116
115
|
`Agent readiness: ${agentReadinessFromPlan(plan)}`,
|
|
117
116
|
`Target config: ${input.isOpenCode && opencode?.targetPath !== undefined ? compactPath(opencode.targetPath, 72) : 'none; no provider config will be written'}`,
|
|
118
117
|
`Safety: ${input.isOpenCode ? '[will write after confirm] only on final confirmation' : '[read-only] manual/no-provider-write mode'}`,
|
|
@@ -132,7 +131,8 @@ function helpLines(screen) {
|
|
|
132
131
|
'Next/back: Tab continues; Shift+Tab goes back. Enter continues on review and confirms only on final confirmation.',
|
|
133
132
|
'Cancel/close: q or Esc cancels setup; when help is open, ?/h toggles it closed.',
|
|
134
133
|
reviewLine,
|
|
135
|
-
'Provider support: OpenCode is the default guided install provider; Claude is first-class supported for guarded explicit apply via mcp install claude --
|
|
134
|
+
'Provider support: OpenCode is the default guided install provider; Claude is first-class supported for guarded explicit user-global apply via mcp install claude --yes --run-id <id>; Manual / none writes no provider config.',
|
|
135
|
+
'Provider config: VGXNESS will manage user-global provider configuration. Project-local provider files are external/manual diagnostics and will not be modified.',
|
|
136
136
|
'Agent readiness: the preview checks vgxness-manager/SDD readiness guidance; preview screens never seed agents.',
|
|
137
137
|
'No-write guarantee: no provider config is written before explicit final confirmation.',
|
|
138
138
|
];
|
|
@@ -177,7 +177,7 @@ function progressLabel(screen) {
|
|
|
177
177
|
if (screen === 'provider')
|
|
178
178
|
return 'Step 3/6 Provider: choose OpenCode or manual/none';
|
|
179
179
|
if (screen === 'opencode-details')
|
|
180
|
-
return 'Step 4/6 OpenCode:
|
|
180
|
+
return 'Step 4/6 OpenCode: user-global target and install mode';
|
|
181
181
|
if (screen === 'plan-review')
|
|
182
182
|
return 'Step 5/6 Review: read-only plan review';
|
|
183
183
|
if (screen === 'final-confirmation')
|
|
@@ -4,7 +4,7 @@ const screenChoiceIds = {
|
|
|
4
4
|
welcome: [],
|
|
5
5
|
'project-database': ['database:global', 'database:project-local', 'database:custom'],
|
|
6
6
|
provider: ['provider:opencode', 'provider:none'],
|
|
7
|
-
'opencode-details': ['scope:
|
|
7
|
+
'opencode-details': ['scope:user', 'install:mcp-plus-agents', 'install:mcp-only', 'overwrite:vgxness'],
|
|
8
8
|
'plan-review': [],
|
|
9
9
|
'final-confirmation': [],
|
|
10
10
|
applying: [],
|
|
@@ -126,8 +126,6 @@ function selectFocusedChoice(state) {
|
|
|
126
126
|
return reduceSetupTuiState(state, { type: 'select-provider', provider: 'opencode' });
|
|
127
127
|
case 'provider:none':
|
|
128
128
|
return reduceSetupTuiState(state, { type: 'select-provider', provider: 'none' });
|
|
129
|
-
case 'scope:project':
|
|
130
|
-
return reduceSetupTuiState(state, { type: 'select-scope', scope: 'project' });
|
|
131
129
|
case 'scope:user':
|
|
132
130
|
return reduceSetupTuiState(state, { type: 'select-scope', scope: 'user' });
|
|
133
131
|
case 'install:mcp-plus-agents':
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join, relative, resolve } from 'node:path';
|
|
3
|
+
import { providerConfigPathDiagnostics } from './provider-health-types.js';
|
|
3
4
|
export function resolveClaudeCodeMcpJsonPath(workspaceRoot) {
|
|
4
5
|
const target = resolve(workspaceRoot, '.mcp.json');
|
|
5
6
|
assertInsideWorkspace(workspaceRoot, target);
|
|
@@ -55,6 +56,7 @@ export function claudeMcpConfigPathStatus(state) {
|
|
|
55
56
|
parsed: state.parsed,
|
|
56
57
|
status: state.status === 'configured' ? 'pass' : state.status === 'invalid' || state.status === 'conflicting' ? 'fail' : 'not-configured',
|
|
57
58
|
detail: state.message,
|
|
59
|
+
diagnostics: providerConfigPathDiagnostics('external-project', state.exists),
|
|
58
60
|
};
|
|
59
61
|
}
|
|
60
62
|
export function claudeMcpEntryStatus(state) {
|
|
@@ -16,3 +16,4 @@ export function resolveClaudeCodeScope(input, fallback = 'project') {
|
|
|
16
16
|
export function isClaudeCodeUserScope(scope) {
|
|
17
17
|
return scope === 'user';
|
|
18
18
|
}
|
|
19
|
+
export const CLAUDE_CODE_USER_GLOBAL_ONLY_MESSAGE = 'VGX-managed Claude provider configuration is user-global only. Project/local Claude files are treated as external/manual diagnostics and will not be written by VGXNESS. Re-run without the project/local install scope.';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { providerConfigPathDiagnostics } from './provider-health-types.js';
|
|
3
4
|
import { isManagedClaudeCodeMcpServer } from './claude-code-config.js';
|
|
4
5
|
import { safeHomeDirectory } from './claude-code-agent-config.js';
|
|
5
6
|
export function resolveClaudeCodeUserMcpJsonPath(env = process.env) {
|
|
@@ -39,6 +40,7 @@ export function claudeUserMcpConfigPathStatus(state) {
|
|
|
39
40
|
parsed: state.parsed,
|
|
40
41
|
status: state.status === 'configured' ? 'pass' : state.status === 'invalid' || state.status === 'conflicting' ? 'fail' : 'not-configured',
|
|
41
42
|
detail: state.message,
|
|
43
|
+
diagnostics: providerConfigPathDiagnostics('managed-user-global', state.exists),
|
|
42
44
|
};
|
|
43
45
|
}
|
|
44
46
|
export function claudeUserMcpEntryStatus(state) {
|
|
@@ -1,68 +1,23 @@
|
|
|
1
1
|
import { withEffectiveManagerInstructions } from '../agents/canonical-agent-projection.js';
|
|
2
2
|
import { expectedClaudeCodeAgentFiles, inspectClaudeCodeAgents, renderClaudeCodeAgentMarkdown } from './claude-code-agent-config.js';
|
|
3
3
|
import { buildClaudeCodeMcpAddCommand } from './claude-code-cli.js';
|
|
4
|
-
import { createClaudeCodeMcpDoctorCommand, createClaudeCodeMcpServerConfig
|
|
5
|
-
import {
|
|
6
|
-
import { resolveClaudeCodeScope } from './claude-code-scope.js';
|
|
4
|
+
import { createClaudeCodeMcpDoctorCommand, createClaudeCodeMcpServerConfig } from './claude-code-config.js';
|
|
5
|
+
import { CLAUDE_CODE_USER_GLOBAL_ONLY_MESSAGE, resolveClaudeCodeScope } from './claude-code-scope.js';
|
|
7
6
|
import { inspectClaudeCodeUserMcpConfig, resolveClaudeCodeUserMcpJsonPath } from './claude-code-user-config.js';
|
|
8
7
|
import { inspectClaudeUserMemory } from './claude-code-user-memory.js';
|
|
9
8
|
export function planClaudeCodeMcpInstall(input) {
|
|
10
9
|
const source = input.databasePathSource ?? 'flag';
|
|
11
10
|
const server = createClaudeCodeMcpServerConfig(input.databasePath, source);
|
|
12
11
|
const overwriteVgxness = input.overwriteVgxness === true;
|
|
13
|
-
const resolvedScope = resolveClaudeCodeScope(input.scope);
|
|
12
|
+
const resolvedScope = resolveClaudeCodeScope(input.scope, 'user');
|
|
14
13
|
if (!resolvedScope.ok)
|
|
15
14
|
return refused(input, server, 'unsupported_scope', resolvedScope.error.message, [], [], overwriteVgxness);
|
|
15
|
+
if (resolvedScope.value.canonical !== 'user')
|
|
16
|
+
return refused(input, server, 'unsupported_scope', CLAUDE_CODE_USER_GLOBAL_ONLY_MESSAGE, [], [], overwriteVgxness);
|
|
16
17
|
const cliCommand = buildClaudeCodeMcpAddCommand({ scope: resolvedScope.value.canonical });
|
|
17
18
|
if (!cliCommand.ok)
|
|
18
19
|
return refused(input, server, 'unsupported_scope', cliCommand.error.message, [], [], overwriteVgxness);
|
|
19
|
-
|
|
20
|
-
if (resolvedScope.value.canonical === 'local') {
|
|
21
|
-
const targets = [{ kind: 'cli-mcp-registration', scope: resolvedScope.value.canonical, command: cliCommand.value, action: 'register' }];
|
|
22
|
-
return { ...base(input, server, targets, [], false, overwriteVgxness, resolvedScope.value.canonical, cliCommand.value, resolvedScope.value.warnings), status: 'would_install' };
|
|
23
|
-
}
|
|
24
|
-
return planUserInstall(input, server, overwriteVgxness, cliCommand.value, resolvedScope.value.warnings);
|
|
25
|
-
}
|
|
26
|
-
let mcpPath;
|
|
27
|
-
try {
|
|
28
|
-
mcpPath = resolveClaudeCodeMcpJsonPath(input.cwd);
|
|
29
|
-
}
|
|
30
|
-
catch (cause) {
|
|
31
|
-
return refused(input, server, 'outside_workspace', cause instanceof Error ? cause.message : String(cause), [], [], overwriteVgxness);
|
|
32
|
-
}
|
|
33
|
-
const mcpState = inspectClaudeCodeMcpConfig(input.cwd);
|
|
34
|
-
const targets = [];
|
|
35
|
-
targets.push({ kind: 'cli-mcp-registration', scope: resolvedScope.value.canonical, command: cliCommand.value, action: 'register' });
|
|
36
|
-
const preservedTopLevelKeys = mcpState.parsed ? Object.keys(mcpState.config) : [];
|
|
37
|
-
if (mcpState.status === 'missing')
|
|
38
|
-
targets.push({ kind: 'mcp-json', path: mcpPath, action: 'create' });
|
|
39
|
-
else if (mcpState.status === 'stale')
|
|
40
|
-
targets.push({ kind: 'mcp-json', path: mcpPath, action: 'merge' });
|
|
41
|
-
else if (mcpState.status === 'configured')
|
|
42
|
-
targets.push({ kind: 'mcp-json', path: mcpPath, action: 'update-vgxness' });
|
|
43
|
-
else
|
|
44
|
-
targets.push({ kind: 'mcp-json', path: mcpPath, action: 'blocked', reason: mcpState.message });
|
|
45
|
-
const agentInspection = inspectClaudeCodeAgents(input.cwd);
|
|
46
|
-
for (const agent of agentInspection.agents) {
|
|
47
|
-
if (agent.status === 'missing')
|
|
48
|
-
targets.push({ kind: 'agent-file', path: agent.path, agentName: agent.agentName, scope: 'project', external: false, action: 'create' });
|
|
49
|
-
else if (agent.status === 'managed')
|
|
50
|
-
targets.push({ kind: 'agent-file', path: agent.path, agentName: agent.agentName, scope: 'project', external: false, action: 'update-vgxness' });
|
|
51
|
-
else
|
|
52
|
-
targets.push({ kind: 'agent-file', path: agent.path, agentName: agent.agentName, scope: 'project', external: false, action: 'blocked', reason: agent.detail });
|
|
53
|
-
}
|
|
54
|
-
const projectMemory = inspectClaudeProjectMemory(input.cwd);
|
|
55
|
-
targets.push({ kind: 'project-memory', path: projectMemory.path, action: projectMemory.action, status: projectMemory.status, backupRequired: projectMemory.backupRequired, ...(projectMemory.status === 'blocked' ? { reason: projectMemory.message } : {}) });
|
|
56
|
-
const blocked = targets.find((target) => target.action === 'blocked');
|
|
57
|
-
if (blocked !== undefined) {
|
|
58
|
-
const reason = blocked.kind === 'mcp-json' ? mcpRefusalReason(mcpState.status) : blocked.kind === 'project-memory' ? projectMemoryRefusalReason(projectMemory) : 'existing_vgxness_agent';
|
|
59
|
-
return refused(input, server, reason, blocked.reason ?? 'Claude Code install plan is blocked by an existing conflicting target.', targets, preservedTopLevelKeys, overwriteVgxness);
|
|
60
|
-
}
|
|
61
|
-
const backupRequired = targets.some((target) => (target.kind === 'mcp-json' && target.action !== 'create') || (target.kind === 'agent-file' && target.action === 'update-vgxness') || (target.kind === 'project-memory' && target.backupRequired));
|
|
62
|
-
return {
|
|
63
|
-
...base(input, server, targets, preservedTopLevelKeys, backupRequired, overwriteVgxness, resolvedScope.value.canonical, cliCommand.value, resolvedScope.value.warnings),
|
|
64
|
-
status: 'would_install',
|
|
65
|
-
};
|
|
20
|
+
return planUserInstall(input, server, overwriteVgxness, cliCommand.value, resolvedScope.value.warnings);
|
|
66
21
|
}
|
|
67
22
|
export function expectedClaudeCodeRenderedAgents(workspaceRoot, options) {
|
|
68
23
|
const files = expectedClaudeCodeAgentFiles(workspaceRoot);
|
|
@@ -116,21 +71,21 @@ function planUserInstall(input, server, overwriteVgxness, cliCommand, scopeWarni
|
|
|
116
71
|
return { ...base(input, server, targets, preservedTopLevelKeys, backupRequired, overwriteVgxness, 'user', cliCommand, scopeWarnings), status: 'would_install' };
|
|
117
72
|
}
|
|
118
73
|
function refused(input, server, reason, message, targets, preservedTopLevelKeys, overwriteVgxness) {
|
|
119
|
-
const resolved = resolveClaudeCodeScope(input.scope);
|
|
120
|
-
const canonical = resolved.ok ? resolved.value.canonical : '
|
|
121
|
-
const cli = buildClaudeCodeMcpAddCommand({ scope: canonical });
|
|
122
|
-
return { ...base(input, server, targets, preservedTopLevelKeys, false, overwriteVgxness, canonical, cli
|
|
74
|
+
const resolved = resolveClaudeCodeScope(input.scope, 'user');
|
|
75
|
+
const canonical = resolved.ok ? resolved.value.canonical : 'user';
|
|
76
|
+
const cli = canonical === 'user' ? buildClaudeCodeMcpAddCommand({ scope: canonical }) : undefined;
|
|
77
|
+
return { ...base(input, server, targets, preservedTopLevelKeys, false, overwriteVgxness, canonical, cli?.ok ? cli.value : undefined, resolved.ok ? resolved.value.warnings : []), status: 'refused', reason, message };
|
|
123
78
|
}
|
|
124
79
|
function base(input, server, targets, preservedTopLevelKeys, backupRequired, overwriteVgxness, canonicalClaudeScope, cliCommand, scopeWarnings) {
|
|
125
80
|
const source = input.databasePathSource ?? 'flag';
|
|
126
|
-
const targetPath =
|
|
81
|
+
const targetPath = resolveClaudeCodeUserMcpJsonPath(input.env);
|
|
127
82
|
return {
|
|
128
83
|
version: 1,
|
|
129
84
|
kind: 'mcp-client-install-claude-code',
|
|
130
85
|
installable: true,
|
|
131
86
|
mutating: false,
|
|
132
87
|
provider: 'claude',
|
|
133
|
-
scope: input.scope ?? '
|
|
88
|
+
scope: input.scope ?? 'user',
|
|
134
89
|
targetPath,
|
|
135
90
|
targets,
|
|
136
91
|
backupRequired,
|
|
@@ -138,12 +93,12 @@ function base(input, server, targets, preservedTopLevelKeys, backupRequired, ove
|
|
|
138
93
|
warnings: [
|
|
139
94
|
...scopeWarnings,
|
|
140
95
|
'Claude Code MCP registration is modeled as structured config/argv, never shell strings.',
|
|
141
|
-
'
|
|
96
|
+
'VGX-managed Claude provider configuration is user-global only; project/local Claude files are treated as external/manual diagnostics and are not written by VGXNESS.',
|
|
142
97
|
'Claude user/global support narrowly merges only mcpServers.vgxness in ~/.claude.json and writes VGXNESS-owned ~/.claude/agents/*.md plus a managed block in ~/.claude/CLAUDE.md after confirmation/preflight; unknown config keys and non-managed memory content are preserved.',
|
|
143
98
|
],
|
|
144
99
|
verificationHints: [
|
|
145
|
-
{ kind: 'restart-client', message: 'Restart or reload Claude Code after confirmed
|
|
146
|
-
{ kind: 'manual-check', message: 'Open
|
|
100
|
+
{ kind: 'restart-client', message: 'Restart or reload Claude Code after confirmed user-global config installation.' },
|
|
101
|
+
{ kind: 'manual-check', message: 'Open Claude Code and verify the vgxness MCP server and user agents are visible.' },
|
|
147
102
|
{ kind: 'command', message: 'Run the MCP doctor command after installation.', command: createClaudeCodeMcpDoctorCommand(input.databasePath, source) },
|
|
148
103
|
],
|
|
149
104
|
server,
|
|
@@ -154,13 +109,6 @@ function base(input, server, targets, preservedTopLevelKeys, backupRequired, ove
|
|
|
154
109
|
overwriteVgxness,
|
|
155
110
|
};
|
|
156
111
|
}
|
|
157
|
-
function mcpRefusalReason(status) {
|
|
158
|
-
if (status === 'invalid')
|
|
159
|
-
return 'malformed_json';
|
|
160
|
-
if (status === 'conflicting')
|
|
161
|
-
return 'existing_vgxness_mcp';
|
|
162
|
-
return 'invalid_mcp_shape';
|
|
163
|
-
}
|
|
164
112
|
function userMcpRefusalReason(status) {
|
|
165
113
|
if (status === 'invalid')
|
|
166
114
|
return 'malformed_json';
|
|
@@ -168,11 +116,6 @@ function userMcpRefusalReason(status) {
|
|
|
168
116
|
return 'existing_vgxness_mcp';
|
|
169
117
|
return 'invalid_mcp_shape';
|
|
170
118
|
}
|
|
171
|
-
function projectMemoryRefusalReason(state) {
|
|
172
|
-
if (state.status === 'blocked' && state.reason === 'conflicting_ownership')
|
|
173
|
-
return 'conflicting_claude_project_memory';
|
|
174
|
-
return 'malformed_claude_project_memory';
|
|
175
|
-
}
|
|
176
119
|
function userMemoryRefusalReason(state) {
|
|
177
120
|
if (state.status === 'blocked' && state.reason === 'conflicting_ownership')
|
|
178
121
|
return 'conflicting_claude_project_memory';
|
|
@@ -15,17 +15,15 @@ export async function installClaudeCodeMcpClient(input) {
|
|
|
15
15
|
if (plan.status === 'refused')
|
|
16
16
|
return refusal(plan.reason, plan.message, plan, server, [], []);
|
|
17
17
|
if (!input.confirmed)
|
|
18
|
-
return refusal('confirmation_required', '`mcp install claude` requires explicit --yes before any
|
|
18
|
+
return refusal('confirmation_required', '`mcp install claude` requires explicit --yes before any user-global provider config write.', plan, server, [], []);
|
|
19
19
|
if (input.preflight === undefined) {
|
|
20
|
-
return refusal('preflight_failed', 'Claude Code provider config writes require VGXNESS preflight before any
|
|
20
|
+
return refusal('preflight_failed', 'Claude Code provider config writes require VGXNESS preflight before any user-global provider config write.', plan, server, [], []);
|
|
21
21
|
}
|
|
22
|
-
const preflightPaths = unique(plan.targets.flatMap((target) => (isMutatingTarget(target) ? [target.path] : [])));
|
|
23
|
-
if (plan.canonicalClaudeScope !== 'project')
|
|
24
|
-
preflightPaths.unshift(plan.targetPath);
|
|
22
|
+
const preflightPaths = unique([plan.targetPath, ...plan.targets.flatMap((target) => (isMutatingTarget(target) ? [target.path] : []))]);
|
|
25
23
|
for (const targetPath of preflightPaths) {
|
|
26
24
|
const preflight = await input.preflight({
|
|
27
25
|
category: 'provider-tool',
|
|
28
|
-
operation:
|
|
26
|
+
operation: 'write claude user-global provider config',
|
|
29
27
|
targetPath,
|
|
30
28
|
workspaceRoot: input.cwd,
|
|
31
29
|
providerToolName: 'claude-code',
|