vgxness 1.3.0 → 1.3.1
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 +16 -16
- package/dist/cli/commands/interactive-entrypoint-dispatcher.js +4 -4
- package/dist/cli/commands/setup-dispatcher.js +4 -4
- package/dist/cli/doctor-renderer.js +1 -1
- package/dist/cli/sdd-renderer.js +7 -7
- package/dist/cli/setup-status-renderer.js +1 -0
- package/dist/cli/tui/main-menu/main-menu-read-model.js +8 -0
- package/dist/cli/tui/main-menu/main-menu-render-shape.js +14 -1
- package/dist/cli/tui/opentui/code/index.js +4 -4
- package/dist/cli/tui/opentui/main-menu/screen.js +6 -0
- package/dist/cli/tui/opentui/setup/screen.js +1 -1
- package/dist/cli/tui/opentui/setup/smoke.js +1 -1
- package/dist/cli/tui/setup/setup-tui-read-model.js +3 -3
- package/dist/cli/tui/setup/setup-tui-render-shape.js +8 -9
- package/dist/cli/tui/setup/setup-tui-state.js +1 -1
- package/dist/code/runtime/sdd-context.js +2 -2
- package/dist/mcp/validation.js +6 -2
- package/dist/orchestrator/natural-language-planner.js +1 -1
- package/dist/sdd/sdd-workflow-service.js +1 -1
- package/dist/setup/backup-rollback-service.js +2 -2
- package/dist/setup/setup-lifecycle-service.js +6 -6
- package/dist/setup/setup-plan.js +3 -3
- package/dist/verification/verification-plan-service.js +1 -1
- package/docs/architecture.md +39 -38
- package/docs/cli.md +134 -127
- package/docs/funcionamiento-del-sistema.md +16 -16
- package/docs/harness-gap-analysis.md +15 -1
- package/docs/prd.md +10 -10
- package/docs/vgxcode.md +20 -9
- package/docs/vgxness-code.md +6 -4
- package/package.json +1 -1
- package/dist/cli/guided-main-menu.js +0 -470
- package/dist/cli/setup-wizard-read-model.js +0 -72
- package/dist/cli/setup-wizard-renderer.js +0 -155
- 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
|
-
|
|
135
|
+
vgxness init
|
|
136
136
|
```
|
|
137
137
|
|
|
138
|
-
In non-TTY shells, `
|
|
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
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
156
|
+
vgxness setup apply --yes
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
`
|
|
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
|
-
- `
|
|
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 `
|
|
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
|
-
|
|
178
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 `
|
|
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
|
|
|
@@ -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 `
|
|
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: `
|
|
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: `
|
|
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: `
|
|
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:
|
|
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:
|
|
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: ['
|
|
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 `
|
|
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 `
|
|
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}`,
|
package/dist/cli/sdd-renderer.js
CHANGED
|
@@ -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 : `
|
|
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 ?? `
|
|
31
|
-
`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
|
-
? `
|
|
40
|
-
: `
|
|
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:
|
|
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:
|
|
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 = [
|
|
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
|
|
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('
|
|
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 `
|
|
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: ['
|
|
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 ?? ['
|
|
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) => `
|
|
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 ?? '
|
|
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
|
-
|
|
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.' : '
|
|
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 `
|
|
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, '
|
|
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
|
|
162
|
-
return vm.nextCommands.
|
|
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 `
|
|
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 {
|
package/dist/mcp/validation.js
CHANGED
|
@@ -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
|
-
|
|
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 : `
|
|
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: `
|
|
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 ? [`
|
|
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: ['
|
|
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 `
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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 ? '
|
|
207
|
+
return project === undefined ? 'vgxness setup status' : `vgxness setup status --project ${project}`;
|
|
208
208
|
}
|
package/dist/setup/setup-plan.js
CHANGED
|
@@ -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 `
|
|
81
|
+
recovery: 'Inspect the OpenCode config, resolve the conflict, then rerun `vgxness setup plan`.',
|
|
82
82
|
},
|
|
83
83
|
],
|
|
84
84
|
backupsPlanned: [],
|
|
85
|
-
nextCommands: ['
|
|
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: ['
|
|
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) {
|
|
@@ -21,7 +21,7 @@ const templates = {
|
|
|
21
21
|
},
|
|
22
22
|
cli: {
|
|
23
23
|
rationale: ['CLI changes affect TypeScript dispatch/rendering paths and user-visible behavior.', 'Only typecheck is currently allowlisted; CLI execution remains manual/copy-only.'],
|
|
24
|
-
recommendations: [typecheckRecommendation(), manualRecommendation('manual-cli-smoke', 'Smoke-test CLI command manually', 'Use
|
|
24
|
+
recommendations: [typecheckRecommendation(), manualRecommendation('manual-cli-smoke', 'Smoke-test CLI command manually', 'Use bun run cli:bun -- <command> as copy-only text for an operator-selected CLI scenario.', 'bun run cli:bun -- <command>')],
|
|
25
25
|
manualChecks: [manualCheck('review-cli-output', 'Review CLI output shape', 'Confirm human output is concise and JSON output remains structured where applicable.')],
|
|
26
26
|
},
|
|
27
27
|
mcp: {
|