vgxness 1.3.0 → 1.4.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.
Files changed (36) hide show
  1. package/README.md +16 -16
  2. package/dist/agents/agent-activation-service.js +9 -5
  3. package/dist/cli/commands/interactive-entrypoint-dispatcher.js +4 -4
  4. package/dist/cli/commands/setup-dispatcher.js +4 -4
  5. package/dist/cli/doctor-renderer.js +1 -1
  6. package/dist/cli/sdd-renderer.js +7 -7
  7. package/dist/cli/setup-status-renderer.js +1 -0
  8. package/dist/cli/tui/main-menu/main-menu-read-model.js +8 -0
  9. package/dist/cli/tui/main-menu/main-menu-render-shape.js +14 -1
  10. package/dist/cli/tui/opentui/code/index.js +4 -4
  11. package/dist/cli/tui/opentui/main-menu/screen.js +6 -0
  12. package/dist/cli/tui/opentui/setup/screen.js +1 -1
  13. package/dist/cli/tui/opentui/setup/smoke.js +1 -1
  14. package/dist/cli/tui/setup/setup-tui-read-model.js +3 -3
  15. package/dist/cli/tui/setup/setup-tui-render-shape.js +8 -9
  16. package/dist/cli/tui/setup/setup-tui-state.js +1 -1
  17. package/dist/code/runtime/sdd-context.js +2 -2
  18. package/dist/mcp/validation.js +6 -2
  19. package/dist/orchestrator/natural-language-planner.js +1 -1
  20. package/dist/sdd/sdd-workflow-service.js +1 -1
  21. package/dist/setup/backup-rollback-service.js +2 -2
  22. package/dist/setup/setup-lifecycle-service.js +6 -6
  23. package/dist/setup/setup-plan.js +3 -3
  24. package/dist/verification/verification-plan-service.js +1 -1
  25. package/docs/architecture.md +39 -38
  26. package/docs/cli.md +134 -127
  27. package/docs/funcionamiento-del-sistema.md +16 -16
  28. package/docs/harness-gap-analysis.md +15 -1
  29. package/docs/prd.md +10 -10
  30. package/docs/vgxcode.md +20 -9
  31. package/docs/vgxness-code.md +6 -4
  32. package/package.json +1 -1
  33. package/dist/cli/guided-main-menu.js +0 -470
  34. package/dist/cli/setup-wizard-read-model.js +0 -72
  35. package/dist/cli/setup-wizard-renderer.js +0 -155
  36. package/dist/cli/setup-wizard-state.js +0 -82
package/README.md CHANGED
@@ -123,8 +123,8 @@ bun run package:bun:evidence
123
123
 
124
124
  ```bash
125
125
  npm install -g vgxness
126
- vgx --help
127
126
  vgxness --help
127
+ vgx --help # compatibility alias
128
128
  ```
129
129
 
130
130
  ## First setup with OpenCode
@@ -132,16 +132,16 @@ vgxness --help
132
132
  Run the guided setup wizard in a TTY:
133
133
 
134
134
  ```bash
135
- vgx init
135
+ vgxness init
136
136
  ```
137
137
 
138
- In non-TTY shells, `vgx init` prints the same read-only setup plan instead of prompting. For a copyable happy path after installing the package globally:
138
+ In non-TTY shells, `vgxness init` prints the same read-only setup plan instead of prompting. For a copyable happy path after installing the package globally:
139
139
 
140
140
  ```bash
141
- vgx setup plan
142
- vgx setup apply --yes
143
- vgx doctor
144
- vgx sdd next --project <project> --change <change>
141
+ vgxness setup plan
142
+ vgxness setup apply --yes
143
+ vgxness doctor
144
+ vgxness sdd next --project <project> --change <change>
145
145
  ```
146
146
 
147
147
  Stable defaults are: package `vgxness`, provider `opencode`, global user data DB, user/global OpenCode scope (`$HOME/.config/opencode/opencode.json`), and `mcp-plus-agents` mode. Use `--scope project` only when you intentionally want `<workspace>/.opencode/opencode.json`. The generated MCP command for the global DB default is:
@@ -153,10 +153,10 @@ vgxness mcp start
153
153
  Apply only after reviewing the plan:
154
154
 
155
155
  ```bash
156
- vgx setup apply --yes
156
+ vgxness setup apply --yes
157
157
  ```
158
158
 
159
- `vgx setup plan` and `vgx setup status` are human-readable and read-only by default. `vgx doctor`, `vgx sdd status`, `vgx sdd next`, and `vgx sdd accept-artifact` are also human-readable by default. Pass `--json` when you need parseable automation output. `vgx setup apply --yes` is the explicit provider-config write path.
159
+ `vgxness setup plan` and `vgxness setup status` are human-readable and read-only by default. `vgxness doctor`, `vgxness sdd status`, `vgxness sdd next`, and `vgxness sdd accept-artifact` are also human-readable by default. Pass `--json` when you need parseable automation output. `vgxness setup apply --yes` is the explicit provider-config write path.
160
160
 
161
161
  ## Safety model
162
162
 
@@ -164,18 +164,18 @@ vgx setup apply --yes
164
164
  - Provider config writes require explicit `--yes` confirmation.
165
165
  - Setup/status TUI surfaces are preview-oriented; run copied commands explicitly when you choose to act.
166
166
  - SDD artifacts are SQLite-backed through VGXNESS services. Do not create or write `openspec/`.
167
- - `vgx sdd accept-artifact` records explicit human-only acceptance; saving a draft never implies acceptance.
167
+ - `vgxness sdd accept-artifact` records explicit human-only acceptance; saving a draft never implies acceptance.
168
168
  - OpenCode is the primary supported provider; other providers are preview/manual extension points.
169
169
 
170
170
  ## Main menu entrypoint
171
171
 
172
- Run `vgx` or `vgxness` with no arguments in an interactive terminal to open the OpenTUI main menu. In non-TTY shells, no-args prints static safe setup guidance and exits 0 without inferring project state.
172
+ Run `vgxness` with no arguments in an interactive terminal to open the OpenTUI main menu. `vgx` remains a compatibility alias. In non-TTY shells, no-args prints static safe setup guidance and exits 0 without inferring project state.
173
173
 
174
174
  For scripts, use explicit read-only commands with an explicit project:
175
175
 
176
176
  ```bash
177
- vgx setup status --project <name>
178
- vgx sdd status --project <name> --change <change>
177
+ vgxness setup status --project <name>
178
+ vgxness sdd status --project <name> --change <change>
179
179
  ```
180
180
 
181
181
  For project-local or custom databases, use `--db project-local` or `--db custom --db-path <path>` with setup commands. Existing low-level commands remain available:
@@ -188,7 +188,7 @@ vgxness mcp install opencode --yes
188
188
  ## Verify
189
189
 
190
190
  ```bash
191
- vgx doctor
191
+ vgxness doctor
192
192
  vgxness mcp doctor opencode
193
193
  vgxness setup status
194
194
  ```
@@ -200,10 +200,10 @@ Restart OpenCode after applying config and verify that the `vgxness` MCP server
200
200
  OpenCode applies create a backup before merging existing config. Restore one with:
201
201
 
202
202
  ```bash
203
- vgx setup rollback --backup <path>
203
+ vgxness setup rollback --backup <path>
204
204
  ```
205
205
 
206
- Rollback validates the backup, creates a pre-rollback backup of the current target when present, restores the selected backup byte-for-byte, and keeps the original backup if anything fails. Rerun `vgx doctor` after rollback.
206
+ Rollback validates the backup, creates a pre-rollback backup of the current target when present, restores the selected backup byte-for-byte, and keeps the original backup if anything fails. Rerun `vgxness doctor` after rollback.
207
207
 
208
208
  Common issues:
209
209
 
@@ -37,7 +37,8 @@ export class AgentActivationService {
37
37
  });
38
38
  if (!run.ok)
39
39
  return run;
40
- const payload = this.dependencies.opencodeManagerPayload.build(toPayloadInput(validated.value, agent.value.id));
40
+ const payloadMode = resolvePayloadMode(validated.value);
41
+ const payload = this.dependencies.opencodeManagerPayload.build(toPayloadInput(validated.value, agent.value.id, payloadMode));
41
42
  if (!payload.ok)
42
43
  return this.failAfterRun(run.value.id, payload.error.code, payload.error.message);
43
44
  const verboseEnvelopeWithoutRun = {
@@ -56,11 +57,11 @@ export class AgentActivationService {
56
57
  ...payload.value.warnings,
57
58
  ],
58
59
  };
59
- const envelopeWithoutRun = validated.value.payloadMode === 'compact' ? compactActivationEnvelope(verboseEnvelopeWithoutRun, validated.value) : verboseEnvelopeWithoutRun;
60
+ const envelopeWithoutRun = payloadMode === 'compact' ? compactActivationEnvelope(verboseEnvelopeWithoutRun, validated.value) : verboseEnvelopeWithoutRun;
60
61
  const checkpoint = this.dependencies.runs.appendCheckpoint({
61
62
  runId: run.value.id,
62
63
  label: 'agent-activation-initial',
63
- state: toJson(checkpointState(envelopeWithoutRun, run.value.id, validated.value.payloadMode ?? 'verbose')),
64
+ state: toJson(checkpointState(envelopeWithoutRun, run.value.id, payloadMode)),
64
65
  });
65
66
  if (!checkpoint.ok)
66
67
  return this.failAfterRun(run.value.id, checkpoint.error.code, checkpoint.error.message);
@@ -138,7 +139,10 @@ function validateActivationInput(input) {
138
139
  validated.payloadMode = input.payloadMode;
139
140
  return ok(validated);
140
141
  }
141
- function toPayloadInput(input, agentId) {
142
+ function resolvePayloadMode(input) {
143
+ return input.payloadMode ?? 'compact';
144
+ }
145
+ function toPayloadInput(input, agentId, payloadMode) {
142
146
  const payload = { project: input.project, scope: input.scope };
143
147
  if (input.agentId !== undefined)
144
148
  payload.agentId = agentId;
@@ -148,7 +152,7 @@ function toPayloadInput(input, agentId) {
148
152
  payload.workspaceRoot = input.workspaceRoot;
149
153
  if (input.maxSourceBytes !== undefined)
150
154
  payload.maxSourceBytes = input.maxSourceBytes;
151
- payload.payloadMode = input.payloadMode ?? 'verbose';
155
+ payload.payloadMode = payloadMode;
152
156
  return payload;
153
157
  }
154
158
  function checkpointState(envelopeWithoutRun, runId, mode) {
@@ -14,16 +14,16 @@ import { runSetupTuiCommand } from './setup-dispatcher.js';
14
14
  function defaultNoTtyGuidance() {
15
15
  return ([
16
16
  'VGXNESS main menu requires a TTY; no provider config was written.',
17
- 'Next: rerun `vgx` in an interactive terminal, run `vgx init --plan`, or run `vgx setup plan` for read-only installation guidance.',
17
+ 'Next: rerun `vgxness` in an interactive terminal, run `vgxness init --plan`, or run `vgxness setup plan` for read-only installation guidance.',
18
18
  ].join('\n') + '\n');
19
19
  }
20
20
  function guidanceForMainMenuResult(result) {
21
21
  if (result.type === 'show-doctor-guidance')
22
- return ['Doctor / recovery guidance:', '- Read-only status: `vgx setup status`', '- Provider doctor: `vgx mcp doctor opencode`', '- No provider config was written.'].join('\n') + '\n';
22
+ return ['Doctor / recovery guidance:', '- Read-only status: `vgxness setup status`', '- Provider doctor: `vgxness mcp doctor opencode`', '- No provider config was written.'].join('\n') + '\n';
23
23
  if (result.type === 'show-sdd-guidance')
24
- return ['SDD / workflow guidance:', '- Use VGXNESS MCP tools from OpenCode for normal SDD progression.', '- Manual status: `vgx sdd status --project <name> --change <change>`', '- No provider config was written.'].join('\n') + '\n';
24
+ return ['SDD / workflow guidance:', '- Use VGXNESS MCP tools from OpenCode for normal SDD progression.', '- Manual status: `vgxness sdd status --project <name> --change <change>`', '- No provider config was written.'].join('\n') + '\n';
25
25
  if (result.type === 'show-advanced-cli')
26
- return ['Advanced CLI guidance:', '- Installation preview: `vgx init --plan` or `vgx setup plan`', '- Setup status: `vgx setup status --project <name>`', '- SDD status: `vgx sdd status --project <name> --change <change>`', '- No provider config was written.'].join('\n') + '\n';
26
+ return ['Advanced CLI guidance:', '- Installation preview: `vgxness init --plan` or `vgxness setup plan`', '- Setup status: `vgxness setup status --project <name>`', '- SDD status: `vgxness sdd status --project <name> --change <change>`', '- No provider config was written.'].join('\n') + '\n';
27
27
  if (result.type === 'exit')
28
28
  return 'Exited main menu; no provider config was written.\n';
29
29
  return undefined;
@@ -25,7 +25,7 @@ function renderSetupRollbackApply(result, parsed) {
25
25
  `Target: ${result.value.targetPath}`,
26
26
  `Restored from: ${result.value.backupPath}`,
27
27
  ...(result.value.preRollbackBackupPath === undefined ? [] : [`Pre-rollback backup: ${result.value.preRollbackBackupPath}`]),
28
- 'Next: vgx doctor; restart OpenCode and verify the vgxness MCP server is visible.',
28
+ 'Next: vgxness doctor; restart OpenCode and verify the vgxness MCP server is visible.',
29
29
  ];
30
30
  return okText(`${lines.join('\n')}\n`);
31
31
  }
@@ -89,7 +89,7 @@ export function runSetupRollbackCommand(parsed, environment) {
89
89
  `Backup: ${result.value.backupPath}`,
90
90
  ...result.value.blockers.map((blocker) => `Blocker: ${blocker}`),
91
91
  ...result.value.warnings.map((warning) => `Warning: ${warning}`),
92
- ...(result.value.restorable ? [`Apply with: vgx setup rollback --backup ${result.value.backupPath} --yes`] : []),
92
+ ...(result.value.restorable ? [`Apply with: vgxness setup rollback --backup ${result.value.backupPath} --yes`] : []),
93
93
  ];
94
94
  return okText(`${lines.join('\n')}\n`);
95
95
  }
@@ -153,7 +153,7 @@ export async function applySetupPlanInput(input, environment) {
153
153
  status: 'installed',
154
154
  plan: plan.value,
155
155
  opencode: result,
156
- nextCommands: ['vgx doctor', 'Restart OpenCode and verify the vgxness MCP server is visible.'],
156
+ nextCommands: ['vgxness doctor', 'Restart OpenCode and verify the vgxness MCP server is visible.'],
157
157
  },
158
158
  }
159
159
  : validationFailure(`${result.reason}: ${result.message}`);
@@ -336,7 +336,7 @@ export async function runInitCommandWithSetupTui(parsed, environment, setupTui)
336
336
  }
337
337
  export async function runSetupTuiCommand(environment, input) {
338
338
  if (!canRunInteractiveTui(environment.stdin, environment.stdout))
339
- return okText('Setup TUI requires an interactive TTY; no provider config was written. Run `vgx init --plan` or `vgx setup plan` for read-only output.\n');
339
+ return okText('Setup TUI requires an interactive TTY; no provider config was written. Run `vgxness init --plan` or `vgxness setup plan` for read-only output.\n');
340
340
  const selectedDatabasePath = databasePathSelectionFor({}, environment);
341
341
  if (!selectedDatabasePath.ok)
342
342
  return resultFailure(selectedDatabasePath);
@@ -7,7 +7,7 @@ export function renderDoctorReport(input) {
7
7
  const failedCheckRemediation = input.report.checks.find((check) => check.status === 'fail' && check.remediation !== undefined)?.remediation;
8
8
  const next = input.report.ready
9
9
  ? 'VGXNESS doctor checks are ready; continue with your SDD workflow.'
10
- : (failedCheckRemediation ?? 'Resolve failed or skipped checks, then rerun `vgx doctor --json` or `vgx doctor`.');
10
+ : (failedCheckRemediation ?? 'Resolve failed or skipped checks, then rerun `vgxness doctor --json` or `vgxness doctor`.');
11
11
  const lines = [
12
12
  'VGXNESS Doctor',
13
13
  `Project: ${input.project}`,
@@ -4,7 +4,7 @@ export function renderSddStatus(input) {
4
4
  const blockers = input.status.phases.filter((phase) => phase.present && phase.accepted !== true);
5
5
  const complete = input.status.phases.length > 0 && input.status.phases.every((phase) => phase.present && phase.accepted === true);
6
6
  const statusLabel = complete ? 'complete' : input.status.nextReadyPhase === undefined ? 'blocked' : 'ready';
7
- const directPhaseCommand = input.status.nextReadyPhase === undefined ? undefined : `vgx code sdd ${input.status.change} ${input.status.nextReadyPhase} --save-artifact`;
7
+ const directPhaseCommand = input.status.nextReadyPhase === undefined ? undefined : `vgxness code sdd ${input.status.change} ${input.status.nextReadyPhase} --save-artifact`;
8
8
  const recommendedAction = complete
9
9
  ? 'No next SDD phase remains for this change.'
10
10
  : input.status.nextReadyPhase === undefined
@@ -27,8 +27,8 @@ export function renderSddStatus(input) {
27
27
  ...(missing.length === 0 ? ['- none'] : missing.map((topicKey) => `- ${topicKey}`)),
28
28
  '',
29
29
  `Recommended action: ${recommendedAction}`,
30
- `Command: ${directPhaseCommand ?? `vgx sdd next --project ${input.project} --change ${input.status.change}`}`,
31
- `JSON: vgx sdd status --project ${input.project} --change ${input.status.change} --json`,
30
+ `Command: ${directPhaseCommand ?? `vgxness sdd next --project ${input.project} --change ${input.status.change}`}`,
31
+ `JSON: vgxness sdd status --project ${input.project} --change ${input.status.change} --json`,
32
32
  ];
33
33
  return `${lines.join('\n')}\n`;
34
34
  }
@@ -36,8 +36,8 @@ export function renderSddNext(input) {
36
36
  const blockers = input.decision.blockedPrerequisites ?? [];
37
37
  const phase = input.decision.nextPhase ?? 'none';
38
38
  const commandGuidance = input.decision.status === 'runnable' && input.decision.nextPhase !== undefined
39
- ? `vgx code sdd ${input.decision.change} ${input.decision.nextPhase} --save-artifact`
40
- : `vgx sdd status --project ${input.project} --change ${input.decision.change}`;
39
+ ? `vgxness code sdd ${input.decision.change} ${input.decision.nextPhase} --save-artifact`
40
+ : `vgxness sdd status --project ${input.project} --change ${input.decision.change}`;
41
41
  const lines = [
42
42
  'SDD Next',
43
43
  `Project: ${input.project}`,
@@ -54,7 +54,7 @@ export function renderSddNext(input) {
54
54
  '',
55
55
  `Recommended action: ${input.decision.recommendedAction}`,
56
56
  `Command: ${commandGuidance}`,
57
- `JSON: vgx sdd next --project ${input.project} --change ${input.decision.change} --json`,
57
+ `JSON: vgxness sdd next --project ${input.project} --change ${input.decision.change} --json`,
58
58
  ];
59
59
  return `${lines.join('\n')}\n`;
60
60
  }
@@ -89,7 +89,7 @@ export function renderSddArtifactAccepted(input) {
89
89
  `- Accepted by: ${input.acceptedBy.displayName} (${input.acceptedBy.id})`,
90
90
  `- Accepted at: ${input.acceptedAt}`,
91
91
  ...(input.note === undefined ? [] : [`- Note: ${input.note}`]),
92
- `JSON: vgx sdd accept-artifact --project ${input.project} --change ${input.change} --phase ${input.phase} --actor ${input.acceptedBy.id} --json`,
92
+ `JSON: vgxness sdd accept-artifact --project ${input.project} --change ${input.change} --phase ${input.phase} --actor ${input.acceptedBy.id} --json`,
93
93
  ];
94
94
  return `${lines.join('\n')}\n`;
95
95
  }
@@ -29,6 +29,7 @@ function renderProviderPreview(provider) {
29
29
  ...(preview.backupRequired === undefined ? [] : [` Backup required: ${String(preview.backupRequired)}`]),
30
30
  ...(preview.confirmationRequired === undefined ? [] : [` Confirmation required: ${String(preview.confirmationRequired)}`]),
31
31
  ...(preview.risks.length === 0 ? [] : [` Risks: ${preview.risks.join(' ')}`]),
32
+ ...(preview.warnings.length === 0 ? [] : [` Warnings: ${preview.warnings.join(' ')}`]),
32
33
  ];
33
34
  }
34
35
  function renderDefaults(status) {
@@ -1,6 +1,12 @@
1
1
  import { tuiBadges } from '../visual/badges.js';
2
2
  import { formatTuiFooter } from '../visual/footer.js';
3
3
  import { mainMenuOptionIds } from './main-menu-state.js';
4
+ const statusSnapshotLines = [
5
+ 'Primary provider: OpenCode.',
6
+ 'Manual checks: vgxness setup status; vgxness mcp doctor opencode.',
7
+ 'SDD cue: vgxness sdd next --project <project> --change <change>.',
8
+ 'No checks run here; copy and run commands explicitly when needed.',
9
+ ];
4
10
  const optionCopy = {
5
11
  setup: {
6
12
  label: 'Installation',
@@ -57,8 +63,10 @@ export function buildMainMenuViewModel(state) {
57
63
  contextLines: ['Choose where to go next. Installation is first; the menu itself is read-only and does not write provider config.'],
58
64
  options,
59
65
  detail: { title: focused.detailTitle, lines: focused.detailLines, badges: focused.badges },
66
+ statusSnapshot: { title: 'Status snapshot', lines: statusSnapshotLines, badges: [tuiBadges.readOnly, tuiBadges.noProviderWrites] },
60
67
  safetyLines: [
61
68
  'Previews are read-only.',
69
+ 'Status snapshot is static guidance; no SQLite, doctor/status checks, provider calls, or provider config writes run from the main menu.',
62
70
  'Installation/provider writes require final confirmation.',
63
71
  'OpenCode is the only automatic provider path and still requires explicit consent.',
64
72
  ],
@@ -11,6 +11,8 @@ export function renderMainMenuShape(input) {
11
11
  ...vm.options.map(choiceLine),
12
12
  `Detail: ${vm.detail.title}${vm.detail.badges.length === 0 ? '' : ` ${vm.detail.badges.join(' ')}`}`,
13
13
  ...vm.detail.lines,
14
+ `${vm.statusSnapshot.title}${vm.statusSnapshot.badges.length === 0 ? '' : ` ${vm.statusSnapshot.badges.join(' ')}`}`,
15
+ ...vm.statusSnapshot.lines,
14
16
  'Safety',
15
17
  ...vm.safetyLines,
16
18
  ...vm.helpLines.map((line) => `Help: ${line}`),
@@ -21,7 +23,18 @@ export function renderMainMenuShape(input) {
21
23
  function clampLine(line, width) {
22
24
  if (line.length <= width)
23
25
  return line;
24
- const protectedPhrases = ['final confirmation', 'read-only', 'Requires confirmation', 'explicit consent', 'No provider writes', 'quit without writes'];
26
+ const protectedPhrases = [
27
+ 'final confirmation',
28
+ 'read-only',
29
+ 'Requires confirmation',
30
+ 'explicit consent',
31
+ 'No provider writes',
32
+ 'quit without writes',
33
+ 'vgxness setup status',
34
+ 'vgxness mcp doctor opencode',
35
+ 'no SQLite',
36
+ 'provider config writes',
37
+ ];
25
38
  const phrase = protectedPhrases.find((candidate) => line.includes(candidate));
26
39
  if (phrase !== undefined)
27
40
  return `${line.slice(0, Math.max(0, width - phrase.length - 5)).trim()} ... ${phrase}`.trim();
@@ -92,7 +92,7 @@ async function runReadOnlyBridge(state, render) {
92
92
  const prompt = submission.prompt;
93
93
  if (prompt === '') {
94
94
  state.status = 'error';
95
- state.errors = ['Enter a prompt before running inspect, plan, or craft-preview. Prefix with /plan, /inspect, or /craft-preview; press Tab to switch inspect/plan.'];
95
+ state.errors = ['Enter a prompt before running inspect, plan, craft-preview, or craft. Prefix with /inspect, /plan, /craft-preview, or /craft; press Tab to switch inspect/plan.'];
96
96
  render();
97
97
  return;
98
98
  }
@@ -107,7 +107,7 @@ async function runReadOnlyBridge(state, render) {
107
107
  render();
108
108
  const root = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../..');
109
109
  const approvalCapableCraft = state.mode === 'craft';
110
- const child = spawn('npm', commandArgsForMode(state.mode, prompt), {
110
+ const child = spawn('bun', commandArgsForMode(state.mode, prompt), {
111
111
  cwd: root,
112
112
  stdio: approvalCapableCraft ? ['pipe', 'pipe', 'pipe'] : ['ignore', 'pipe', 'pipe'],
113
113
  env: process.env,
@@ -173,13 +173,13 @@ async function runReadOnlyBridge(state, render) {
173
173
  if (code !== 0 && !(state.mode === 'craft-preview' && code === 3)) {
174
174
  const detail = stderr.trim() === '' ? `signal ${signal ?? 'none'}` : stderr.trim();
175
175
  state.status = 'error';
176
- state.errors.push(`Root CLI ${state.mode} failed (exit ${code ?? 'signal'}): ${detail}`);
176
+ state.errors.push(`Root Bun CLI ${state.mode} failed (exit ${code ?? 'signal'}): ${detail}`);
177
177
  }
178
178
  render();
179
179
  });
180
180
  }
181
181
  function commandArgsForMode(mode, prompt) {
182
- const args = ['run', '--silent', 'cli', '--', 'code', mode, prompt, '--events-jsonl'];
182
+ const args = ['run', '--silent', 'cli:bun', '--', 'code', mode, prompt, '--events-jsonl'];
183
183
  if (mode === 'craft')
184
184
  args.push('--approval-channel', 'stdio');
185
185
  return args;
@@ -19,6 +19,12 @@ export function createOpenTuiMainMenuScreen(state) {
19
19
  paddingX: 1,
20
20
  title: ' VGXNESS ',
21
21
  }, Text({ content: `${vm.title}\n${vm.subtitle} ${tuiBadges.readOnly}\n${vm.contextLines.join('\n')}`, fg: '#E0F2FE', wrapMode: 'word' })), Box({
22
+ border: true,
23
+ borderStyle: 'rounded',
24
+ borderColor: '#14B8A6',
25
+ paddingX: 1,
26
+ title: ` ${vm.statusSnapshot.title} ${vm.statusSnapshot.badges.join(' ')} `,
27
+ }, Text({ content: vm.statusSnapshot.lines.join('\n'), fg: '#CCFBF1', wrapMode: 'word' })), Box({
22
28
  flexDirection: state.viewport.mode === 'narrow' ? 'column' : 'row',
23
29
  flexGrow: 1,
24
30
  gap: 1,
@@ -101,7 +101,7 @@ function setupScreenContent(state, vm, width) {
101
101
  case 'result':
102
102
  return { leftTitle: ' Result ', left: ['Setup finished.', ...vm.nextCommands.map((command) => `Next: ${command}`)], rightTitle: ' Summary ', right: previewLines(vm), safety, help, footer };
103
103
  case 'error-recovery':
104
- return { leftTitle: ' Recovery ', left: ['! Setup hit an error.', 'No unconfirmed provider config write was performed.', 'Inspect `vgx setup plan`, resolve blockers, then retry.'], rightTitle: ' Context ', right: previewLines(vm), safety, help, footer };
104
+ return { leftTitle: ' Recovery ', left: ['! Setup hit an error.', 'No unconfirmed provider config write was performed.', 'Inspect `vgxness setup plan`, resolve blockers, then retry.'], rightTitle: ' Context ', right: previewLines(vm), safety, help, footer };
105
105
  case 'cancelled':
106
106
  return { leftTitle: ' Cancelled ', left: ['Setup was cancelled.', 'No provider config was written.', 'No agent seeding was performed.'], rightTitle: ' Context ', right: previewLines(vm), safety, help, footer };
107
107
  }
@@ -26,7 +26,7 @@ try {
26
26
  conflicts: [],
27
27
  backupsPlanned: [{ targetPath: '/tmp/.config/opencode/opencode.json', reason: 'Existing OpenCode config would be backed up before merge.' }],
28
28
  safety: { mutating: false, writesProviderConfig: false, requiresConfirmationForApply: true },
29
- nextCommands: ['vgx setup apply --yes', 'vgx doctor'],
29
+ nextCommands: ['vgxness setup apply --yes', 'vgxness doctor'],
30
30
  },
31
31
  }), 120));
32
32
  await setup.renderOnce();
@@ -57,7 +57,7 @@ export function setupTuiViewModelFromPlan(plan, status, state) {
57
57
  warnings,
58
58
  blockers,
59
59
  backupLabel: backups.length === 0 ? 'Backup: none planned' : `Backup planned: ${backups.join('; ')}`,
60
- nextCommands: plan?.nextCommands ?? ['vgx setup plan'],
60
+ nextCommands: plan?.nextCommands ?? ['vgxness setup plan'],
61
61
  canAutoApply: plan?.provider === 'opencode' && plan.status === 'ready' && state?.selections.provider !== 'none' && plan.opencode !== undefined,
62
62
  safetyWarning: 'Final confirmation is required before any provider config write. OpenCode config may be modified and backed up.',
63
63
  frameLabel: 'VGXNESS Setup Assistant workspace',
@@ -108,7 +108,7 @@ function previewDetailLines(input) {
108
108
  ...actions,
109
109
  input.backups.length === 0 ? 'Backups: none planned' : `Backups: ${input.backups.join('; ')}`,
110
110
  ...(input.warnings.length === 0 ? ['Warnings: none'] : input.warnings.map((warning) => `Warning: ${warning}`)),
111
- ...(input.blockers.length === 0 ? ['Blockers: none'] : input.blockers.map((blocker) => `Blocker: ${blocker}`)),
111
+ ...(input.blockers.length === 0 ? ['Blockers: none'] : input.blockers.map((blocker) => `Blocked because: ${blocker}`)),
112
112
  ];
113
113
  }
114
114
  function helpLines(screen) {
@@ -145,7 +145,7 @@ function agentReadinessLabels(plan, status) {
145
145
  if (status?.agents.status === 'blocked')
146
146
  return {
147
147
  label: 'Agents need attention',
148
- detail: `${status.agents.blocker ?? 'Required agents are not ready.'} Next: ${status.agents.nextAction ?? 'vgx agents seed --scope project'}`,
148
+ detail: `${status.agents.blocker ?? 'Required agents are not ready.'} Next: ${status.agents.nextAction ?? 'vgxness agents seed --scope project'}`,
149
149
  };
150
150
  return { label: 'Agent readiness preview', detail: `Required agents: ${names.join(', ')}. Preview/status screens do not seed agents.` };
151
151
  }
@@ -59,11 +59,10 @@ function screenLines(input, width) {
59
59
  'Read-only plan review',
60
60
  'Plan summary ' + badgeLabels.readOnly,
61
61
  ...planLines(vm, width),
62
- `Doctor next step: ${doctorCommand(vm)}`,
63
- 'Restart next step: Restart OpenCode after confirmed setup so it reloads MCP configuration.',
62
+ ...nextCommandLines(vm),
64
63
  'Review only: this screen does not write provider config.',
65
- vm.canAutoApply ? 'Press Enter to continue to final confirmation.' : 'Manual setup required; no automatic apply is available.',
66
- ], width, [setupFooterHints.finalConfirmation, setupFooterHints.back, setupFooterHints.cancel]);
64
+ vm.canAutoApply ? 'Press Enter to continue to final confirmation.' : 'Press Enter to show manual next steps; no automatic apply is available.',
65
+ ], width, vm.canAutoApply ? [setupFooterHints.finalConfirmation, setupFooterHints.back, setupFooterHints.cancel] : [setupFooterHints.continue, setupFooterHints.back, setupFooterHints.cancel]);
67
66
  case 'final-confirmation':
68
67
  return workspaceLines(vm, [
69
68
  'Final confirmation',
@@ -84,7 +83,7 @@ function screenLines(input, width) {
84
83
  badgeLabels.error,
85
84
  `Error: ${input.error ?? 'Unknown setup error'}`,
86
85
  'No unconfirmed provider config write was performed.',
87
- 'Next: inspect `vgx setup plan`, resolve blockers, then retry.',
86
+ 'Next: inspect `vgxness setup plan`, resolve blockers, then retry.',
88
87
  footer([setupFooterHints.close], width),
89
88
  ];
90
89
  case 'cancelled':
@@ -106,7 +105,7 @@ function planLines(vm, width) {
106
105
  vm.backupLabel,
107
106
  ...vm.plannedActions.map((action) => `Action: ${action.safetyBadge} ${action.label}${action.targetPathLabel === undefined ? '' : ` (${compactPath(action.targetPathLabel, width - 12)})`}`),
108
107
  ...vm.warnings.map((warning) => `Warning: ${warning}`),
109
- ...vm.blockers.map((blocker) => `Blocked: ${blocker}`),
108
+ ...vm.blockers.map((blocker) => `Blocked because: ${blocker}`),
110
109
  ];
111
110
  }
112
111
  function workspaceLines(vm, lines, width, hints = [setupFooterHints.continue, setupFooterHints.back, setupFooterHints.cancel]) {
@@ -155,11 +154,11 @@ function resultLines(result, vm, width) {
155
154
  }
156
155
  function resultNextCommands(vm) {
157
156
  const filtered = vm.nextCommands.filter((command) => !/^vgx(?:ness)? setup apply\b/.test(command));
158
- const withDoctor = filtered.some((command) => /\bdoctor\b/.test(command)) ? filtered : [...filtered, 'vgx doctor'];
157
+ const withDoctor = filtered.some((command) => /\bdoctor\b/.test(command)) ? filtered : [...filtered, 'vgxness doctor'];
159
158
  return withDoctor.some((command) => /Restart OpenCode/i.test(command)) ? withDoctor : [...withDoctor, 'Restart OpenCode and verify the vgxness MCP server is visible.'];
160
159
  }
161
- function doctorCommand(vm) {
162
- return vm.nextCommands.find((command) => /\bdoctor\b/.test(command)) ?? 'vgx doctor';
160
+ function nextCommandLines(vm) {
161
+ return ['Next commands:', ...vm.nextCommands.map((command) => `Next: ${command}`)];
163
162
  }
164
163
  function footer(hints, width) {
165
164
  return formatFooter(hints, width);
@@ -81,7 +81,7 @@ export function reduceSetupTuiState(state, action) {
81
81
  result: {
82
82
  status: 'failed',
83
83
  message: action.message,
84
- recovery: ['Inspect the setup plan with `vgx setup plan`.', 'Resolve blockers before retrying.'],
84
+ recovery: ['Inspect the setup plan with `vgxness setup plan`.', 'Resolve blockers before retrying.'],
85
85
  writesOccurred: false,
86
86
  },
87
87
  };
@@ -84,8 +84,6 @@ export function validateSddReadiness(context) {
84
84
  if (context.next.status === 'complete')
85
85
  return { ok: true };
86
86
  const present = context.status.phases.find((candidate) => candidate.phase === context.phase)?.present === true;
87
- if (present)
88
- return { ok: true };
89
87
  const blockedPrerequisites = activeBlockedPrerequisites(context);
90
88
  if (blockedPrerequisites.length > 0)
91
89
  return {
@@ -100,6 +98,8 @@ export function validateSddReadiness(context) {
100
98
  recommendedAction: `Accept or restore prerequisites before running ${context.phase}.`,
101
99
  },
102
100
  };
101
+ if (present)
102
+ return { ok: true };
103
103
  if (context.status.nextReadyPhase === context.phase)
104
104
  return { ok: true };
105
105
  return {
@@ -244,7 +244,7 @@ function readProjectAndChange(record, tool) {
244
244
  return { ok: true, value: { project: project.value, change: change.value } };
245
245
  }
246
246
  function validateSddReadyInput(input, tool) {
247
- const record = inputRecord(input, tool, ['project', 'change', 'phase']);
247
+ const record = inputRecord(input, tool, ['project', 'change', 'phase', 'runId', 'agentId']);
248
248
  if (!record.ok)
249
249
  return record;
250
250
  const base = readProjectAndChange(record.value, tool);
@@ -253,7 +253,11 @@ function validateSddReadyInput(input, tool) {
253
253
  const phase = readPhase(record.value, tool);
254
254
  if (!phase.ok)
255
255
  return phase;
256
- return { ok: true, value: { ...base.value, phase: phase.value } };
256
+ const result = { ...base.value, phase: phase.value };
257
+ const copied = copyOptionalStrings(result, record.value, tool, ['runId', 'agentId']);
258
+ if (!copied.ok)
259
+ return copied;
260
+ return { ok: true, value: result };
257
261
  }
258
262
  function validateSddGetReadinessInput(input, tool) {
259
263
  return validateSddReadyInput(input, tool);
@@ -226,7 +226,7 @@ function buildPreviewActions(input, flow, needsClarification) {
226
226
  if (flow === 'build')
227
227
  return [{ kind: 'workflow-preview', description: 'Preview a scoped build workflow; no execution occurs in this planner response.' }];
228
228
  const change = input.change;
229
- const command = change === undefined ? undefined : `npm run cli -- sdd next --project ${input.project} --change ${change}`;
229
+ const command = change === undefined ? undefined : `vgxness sdd next --project ${input.project} --change ${change}`;
230
230
  return [
231
231
  {
232
232
  kind: 'sdd-preview',
@@ -96,7 +96,7 @@ export class SddWorkflowService {
96
96
  acceptedCount: cockpitPhases.filter((phase) => phase.accepted).length,
97
97
  legacyCount: cockpitPhases.filter((phase) => phase.legacy).length,
98
98
  aggregateBlockers,
99
- inspectCommand: `vgx sdd cockpit --project ${validated.value.project} --change ${validated.value.change} --json`,
99
+ inspectCommand: `vgxness sdd cockpit --project ${validated.value.project} --change ${validated.value.change} --json`,
100
100
  };
101
101
  return ok(cockpit);
102
102
  }
@@ -81,7 +81,7 @@ export function previewRollbackConfigBackup(input) {
81
81
  restorable: blockers.length === 0 && targetPath !== undefined,
82
82
  blockers,
83
83
  warnings,
84
- nextCommands: blockers.length === 0 ? [`vgx setup rollback --backup ${backupPath} --yes`] : ['Resolve blockers, then rerun rollback preview.'],
84
+ nextCommands: blockers.length === 0 ? [`vgxness setup rollback --backup ${backupPath} --yes`] : ['Resolve blockers, then rerun rollback preview.'],
85
85
  },
86
86
  };
87
87
  }
@@ -133,7 +133,7 @@ export function applyRollbackConfigBackup(input) {
133
133
  targetPath,
134
134
  ...(preRollbackBackup === undefined ? {} : { preRollbackBackupPath: preRollbackBackup.backupPath, preRollbackBackup }),
135
135
  backup: preview.value.backup,
136
- nextCommands: ['vgx doctor', 'Restart OpenCode and verify the vgxness MCP server is visible.'],
136
+ nextCommands: ['vgxness doctor', 'Restart OpenCode and verify the vgxness MCP server is visible.'],
137
137
  },
138
138
  };
139
139
  }
@@ -74,7 +74,7 @@ function storeStatus(result) {
74
74
  status: 'blocked',
75
75
  path: '',
76
76
  blocker: result.error.message,
77
- recovery: 'Run `vgx doctor` and verify the configured local memory path is writable.',
77
+ recovery: 'Run `vgxness doctor` and verify the configured local memory path is writable.',
78
78
  };
79
79
  }
80
80
  function mcpStatus(result, storeReadiness) {
@@ -178,17 +178,17 @@ function verificationSummary(environment, project, providers, agents, mcp) {
178
178
  }
179
179
  function nextAction(store, mcp, defaults, providers, project) {
180
180
  if (store.status !== 'ready') {
181
- return { command: 'vgx doctor', reason: `Local store is blocked: ${store.blocker ?? 'local store is unavailable'}` };
181
+ return { command: 'vgxness doctor', reason: `Local store is blocked: ${store.blocker ?? 'local store is unavailable'}` };
182
182
  }
183
183
  if (defaults.status !== 'ready') {
184
184
  if (defaults.blocker?.startsWith('No project selected') === true) {
185
185
  return {
186
- command: 'vgx setup status --project <project>',
186
+ command: 'vgxness setup status --project <project>',
187
187
  reason: defaults.nextAction ?? 'Select a project to verify project-scoped setup checks.',
188
188
  };
189
189
  }
190
190
  return {
191
- command: 'vgx agents seed --scope project',
191
+ command: 'vgxness agents seed --scope project',
192
192
  reason: `Default context is blocked: ${defaults.blocker ?? 'default context is unavailable'}`,
193
193
  };
194
194
  }
@@ -201,8 +201,8 @@ function nextAction(store, mcp, defaults, providers, project) {
201
201
  reason: `Provider MCP status is not ready; review the Providers section for provider-specific preview/install guidance (${providerSummary}).`,
202
202
  };
203
203
  }
204
- return { command: 'vgx runs list', reason: 'Project setup is ready; continue with normal vgxness usage.' };
204
+ return { command: 'vgxness runs list', reason: 'Project setup is ready; continue with normal vgxness usage.' };
205
205
  }
206
206
  function setupStatusCommand(project) {
207
- return project === undefined ? 'vgx setup status' : `vgx setup status --project ${project}`;
207
+ return project === undefined ? 'vgxness setup status' : `vgxness setup status --project ${project}`;
208
208
  }
@@ -78,11 +78,11 @@ function setupPlanFromOpenCode(input) {
78
78
  severity: 'blocking',
79
79
  message: input.opencode.message,
80
80
  ...(input.opencode.targetPath === undefined ? {} : { targetPath: input.opencode.targetPath }),
81
- recovery: 'Inspect the OpenCode config, resolve the conflict, then rerun `vgx setup plan`.',
81
+ recovery: 'Inspect the OpenCode config, resolve the conflict, then rerun `vgxness setup plan`.',
82
82
  },
83
83
  ],
84
84
  backupsPlanned: [],
85
- nextCommands: ['vgx setup plan', 'vgxness mcp doctor opencode'],
85
+ nextCommands: ['vgxness setup plan', 'vgxness mcp doctor opencode'],
86
86
  };
87
87
  }
88
88
  return {
@@ -115,7 +115,7 @@ function setupPlanFromOpenCode(input) {
115
115
  },
116
116
  ]
117
117
  : [],
118
- nextCommands: ['vgx setup apply --yes', 'vgx doctor', 'Restart OpenCode and verify the vgxness MCP server is visible.'],
118
+ nextCommands: ['vgxness setup apply --yes', 'vgxness doctor', 'Restart OpenCode and verify the vgxness MCP server is visible.'],
119
119
  };
120
120
  }
121
121
  function resolveSetupDatabase(input) {