vgxness 1.2.1 → 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 +20 -19
- package/dist/cli/cli-help.js +4 -7
- package/dist/cli/commands/index.js +1 -1
- package/dist/cli/commands/interactive-entrypoint-dispatcher.js +150 -0
- package/dist/cli/commands/setup-dispatcher.js +11 -8
- package/dist/cli/dispatcher.js +1 -8
- package/dist/cli/doctor-renderer.js +1 -1
- package/dist/cli/index.js +0 -0
- package/dist/cli/sdd-renderer.js +7 -7
- package/dist/cli/setup-status-renderer.js +1 -0
- package/dist/cli/tui/main-menu/index.js +0 -1
- package/dist/cli/tui/main-menu/main-menu-controller.js +0 -2
- package/dist/cli/tui/main-menu/main-menu-read-model.js +10 -8
- package/dist/cli/tui/main-menu/main-menu-render-shape.js +19 -2
- package/dist/cli/tui/main-menu/main-menu-state.js +1 -1
- package/dist/cli/tui/opentui/code/index.js +210 -0
- package/dist/cli/tui/opentui/code/screen.js +107 -0
- package/dist/cli/tui/opentui/code/smoke.js +32 -0
- package/dist/cli/tui/opentui/main-menu/index.js +3 -0
- package/dist/cli/tui/opentui/main-menu/renderer.js +68 -0
- package/dist/cli/tui/opentui/main-menu/screen.js +68 -0
- package/dist/cli/tui/opentui/main-menu/smoke.js +17 -0
- package/dist/cli/tui/opentui/main-menu/view.js +8 -0
- package/dist/cli/tui/opentui/setup/index.js +3 -0
- package/dist/cli/tui/opentui/setup/renderer.js +87 -0
- package/dist/cli/tui/opentui/setup/screen.js +170 -0
- package/dist/cli/tui/opentui/setup/smoke.js +42 -0
- package/dist/cli/tui/opentui/setup/view.js +12 -0
- package/dist/cli/tui/setup/setup-tui-input.js +43 -0
- package/dist/cli/tui/setup/setup-tui-read-model.js +4 -4
- package/dist/cli/tui/setup/setup-tui-render-shape.js +9 -10
- package/dist/cli/tui/setup/setup-tui-state.js +1 -1
- package/dist/cli/tui/setup/setup-tui-view-helpers.js +46 -0
- package/dist/cli/tui/visual/index.js +0 -2
- package/dist/code/runtime/sdd-context.js +2 -2
- package/dist/code/tui/approval-actions.js +33 -0
- package/dist/code/tui/prompt-mode.js +11 -0
- package/dist/code/tui/runtime-events.js +320 -0
- package/dist/mcp/validation.js +6 -2
- package/dist/orchestrator/natural-language-planner.js +1 -1
- package/dist/sdd/sdd-workflow-service.js +1 -25
- package/dist/setup/backup-rollback-service.js +2 -2
- package/dist/setup/providers/antigravity-setup-adapter.js +1 -1
- package/dist/setup/providers/claude-setup-adapter.js +2 -2
- package/dist/setup/providers/custom-setup-adapter.js +1 -1
- package/dist/setup/providers/opencode-setup-adapter.js +3 -3
- 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 +43 -42
- package/docs/cli.md +141 -133
- package/docs/funcionamiento-del-sistema.md +22 -23
- package/docs/harness-gap-analysis.md +15 -1
- package/docs/prd.md +14 -14
- package/docs/vgxcode.md +87 -0
- package/docs/vgxness-code.md +6 -4
- package/package.json +5 -6
- package/dist/cli/commands/dashboard-dispatcher.js +0 -560
- package/dist/cli/dashboard-operational-read-models.js +0 -428
- package/dist/cli/dashboard-renderer.js +0 -158
- package/dist/cli/dashboard-screen-renderers.js +0 -256
- package/dist/cli/dashboard-tui-read-model.js +0 -73
- package/dist/cli/dashboard-tui-state.js +0 -314
- package/dist/cli/guided-main-menu.js +0 -470
- package/dist/cli/interactive-dashboard.js +0 -34
- 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/dist/cli/tui/dashboard/dashboard-adapter.js +0 -4
- package/dist/cli/tui/main-menu/main-menu-app.js +0 -28
- package/dist/cli/tui/render-ink-app.js +0 -10
- package/dist/cli/tui/setup/screens/applying-screen.js +0 -6
- package/dist/cli/tui/setup/screens/cancellation-screen.js +0 -6
- package/dist/cli/tui/setup/screens/error-recovery-screen.js +0 -6
- package/dist/cli/tui/setup/screens/final-confirmation-screen.js +0 -6
- package/dist/cli/tui/setup/screens/opencode-details-screen.js +0 -10
- package/dist/cli/tui/setup/screens/plan-review-screen.js +0 -6
- package/dist/cli/tui/setup/screens/project-database-screen.js +0 -6
- package/dist/cli/tui/setup/screens/provider-screen.js +0 -7
- package/dist/cli/tui/setup/screens/result-screen.js +0 -16
- package/dist/cli/tui/setup/screens/screen-components.js +0 -103
- package/dist/cli/tui/setup/screens/welcome-screen.js +0 -6
- package/dist/cli/tui/setup/setup-tui-app.js +0 -113
- package/dist/cli/tui/visual/choice-list.js +0 -10
- package/dist/cli/tui/visual/layout.js +0 -10
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ VGXNESS is an installable CLI and MCP control plane for guided AI-agent workflow
|
|
|
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. Other providers remain preview/manual only.
|
|
9
|
+
OpenCode is the primary supported provider. Other providers remain preview/manual only. Provider config writes require explicit CLI confirmation.
|
|
10
10
|
|
|
11
11
|
## Requirements
|
|
12
12
|
|
|
@@ -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,28 +153,29 @@ 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
|
|
|
163
163
|
- Preview, status, and plan commands are read-only.
|
|
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
|
-
For scripts, use
|
|
174
|
+
For scripts, use explicit read-only commands with an explicit project:
|
|
175
175
|
|
|
176
176
|
```bash
|
|
177
|
-
|
|
177
|
+
vgxness setup status --project <name>
|
|
178
|
+
vgxness sdd status --project <name> --change <change>
|
|
178
179
|
```
|
|
179
180
|
|
|
180
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:
|
|
@@ -187,7 +188,7 @@ vgxness mcp install opencode --yes
|
|
|
187
188
|
## Verify
|
|
188
189
|
|
|
189
190
|
```bash
|
|
190
|
-
|
|
191
|
+
vgxness doctor
|
|
191
192
|
vgxness mcp doctor opencode
|
|
192
193
|
vgxness setup status
|
|
193
194
|
```
|
|
@@ -199,10 +200,10 @@ Restart OpenCode after applying config and verify that the `vgxness` MCP server
|
|
|
199
200
|
OpenCode applies create a backup before merging existing config. Restore one with:
|
|
200
201
|
|
|
201
202
|
```bash
|
|
202
|
-
|
|
203
|
+
vgxness setup rollback --backup <path>
|
|
203
204
|
```
|
|
204
205
|
|
|
205
|
-
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.
|
|
206
207
|
|
|
207
208
|
Common issues:
|
|
208
209
|
|
package/dist/cli/cli-help.js
CHANGED
|
@@ -91,14 +91,11 @@ Areas:
|
|
|
91
91
|
subagents list --parent-agent-id <id>
|
|
92
92
|
subagents get --id <id> | --project <name> --name <name> [--scope project|personal]
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
No args without a TTY prints static safe guidance and exits 0 without reading dashboard status or opening project state.
|
|
98
|
-
Dashboard menu: Installation, Status, Agents, Skills, Memory, SDD, Runs, Approvals, Permissions, Settings. Menu: ↑/↓ or j/k, Enter, 1-9/0. Section: b/Esc/Backspace back, r, ?, q.
|
|
99
|
-
Dashboardinteractive may launch without --project; Installation remains available and project-scoped checks are deferred while project screens render project-required recovery states.
|
|
94
|
+
No args in an interactive TTY opens the OpenTUI main menu.
|
|
95
|
+
No args without a TTY prints static safe setup guidance and exits 0 without opening project state.
|
|
96
|
+
Setup TUI may launch without --project; Installation remains available and project-scoped checks are deferred while project screens render project-required recovery states.
|
|
100
97
|
Provider setup support: OpenCode supported primary; Claude preview-only; Antigravity placeholder; Custom/future extension point.
|
|
101
|
-
|
|
98
|
+
Provider config writes/install/apply are external-only and require explicit confirmation.
|
|
102
99
|
|
|
103
100
|
sdd status --project <name> --change <id> [--json]
|
|
104
101
|
sdd next --project <name> --change <id> [--json]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { runAgentCommand, runSkillCommand, runSubagentCommand } from './agent-skill-dispatcher.js';
|
|
2
|
-
export { runCodeCliCommand,
|
|
2
|
+
export { runCodeCliCommand, runDefaultInteractiveEntrypoint } from './interactive-entrypoint-dispatcher.js';
|
|
3
3
|
export { runDoctorAliasCommand, runMcpDoctorCommand, runMcpDoctorOpenCodeCommand, runMcpInstallCommand, runMcpSetupCommand } from './mcp-dispatcher.js';
|
|
4
4
|
export { runMemoryCommand, runMemoryImportCommand, runOpenCodeCommand, runOrchestratorCommand, runSddCommand } from './memory-sdd-dispatcher.js';
|
|
5
5
|
export { runApprovalsCommand, runPermissionsCommand, runRunsCommand } from './run-permission-dispatcher.js';
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { runCodeCommand } from '../../code/cli/code-command.js';
|
|
2
|
+
import { InMemoryRunGateway } from '../../code/runtime/gateways.js';
|
|
3
|
+
import { MemoryServiceCodeGateway } from '../../code/runtime/memory-service-gateway.js';
|
|
4
|
+
import { RunsCodeRunGateway } from '../../code/runtime/runs-code-run-gateway.js';
|
|
5
|
+
import { SddWorkflowGateway } from '../../code/runtime/sdd-workflow-gateway.js';
|
|
6
|
+
import { MemoryService } from '../../memory/memory-service.js';
|
|
7
|
+
import { RunService } from '../../runs/run-service.js';
|
|
8
|
+
import { SddWorkflowService } from '../../sdd/sdd-workflow-service.js';
|
|
9
|
+
import { codeApprovalPolicyFlag, codeMemoryPolicyFlag, codeTranscriptModeFlag, codeVerificationModeFlag, databasePathFor, optionalNumberFlag, optionalStringFlag, } from '../cli-flags.js';
|
|
10
|
+
import { okText, usageFailure, validationFailure } from '../cli-help.js';
|
|
11
|
+
import { openCliDatabase, resultFailure } from '../cli-helpers.js';
|
|
12
|
+
import { canRunInteractiveTui } from '../tui/terminal-capabilities.js';
|
|
13
|
+
import { runSetupTuiCommand } from './setup-dispatcher.js';
|
|
14
|
+
function defaultNoTtyGuidance() {
|
|
15
|
+
return ([
|
|
16
|
+
'VGXNESS main menu requires a TTY; no provider config was written.',
|
|
17
|
+
'Next: rerun `vgxness` in an interactive terminal, run `vgxness init --plan`, or run `vgxness setup plan` for read-only installation guidance.',
|
|
18
|
+
].join('\n') + '\n');
|
|
19
|
+
}
|
|
20
|
+
function guidanceForMainMenuResult(result) {
|
|
21
|
+
if (result.type === 'show-doctor-guidance')
|
|
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
|
+
if (result.type === 'show-sdd-guidance')
|
|
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
|
+
if (result.type === 'show-advanced-cli')
|
|
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
|
+
if (result.type === 'exit')
|
|
28
|
+
return 'Exited main menu; no provider config was written.\n';
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
async function renderDefaultMainMenu(environment, onResult) {
|
|
32
|
+
const { renderOpenTuiMainMenu } = await import('../tui/opentui/main-menu/renderer.js');
|
|
33
|
+
await renderOpenTuiMainMenu({
|
|
34
|
+
stdin: environment.stdin,
|
|
35
|
+
stdout: environment.stdout,
|
|
36
|
+
onResult,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
export async function runDefaultInteractiveEntrypointWithMainMenu(environment, input = {}) {
|
|
40
|
+
if (!canRunInteractiveTui(environment.stdin, environment.stdout))
|
|
41
|
+
return okText(defaultNoTtyGuidance());
|
|
42
|
+
let selected;
|
|
43
|
+
await (input.renderMainMenu ?? ((onResult) => renderDefaultMainMenu(environment, onResult)))((result) => {
|
|
44
|
+
selected = result;
|
|
45
|
+
});
|
|
46
|
+
const result = selected ?? { type: 'exit' };
|
|
47
|
+
if (result.type === 'open-setup')
|
|
48
|
+
return (input.setupTui ?? runSetupTuiCommand)(environment);
|
|
49
|
+
return okText(guidanceForMainMenuResult(result) ?? 'No provider config was written.\n');
|
|
50
|
+
}
|
|
51
|
+
function codeApprovalChannelFlag(flags) {
|
|
52
|
+
const value = optionalStringFlag(flags, 'approval-channel');
|
|
53
|
+
if (value === undefined)
|
|
54
|
+
return { ok: true, value: undefined };
|
|
55
|
+
return value === 'stdio' ? { ok: true, value } : validationFailure('--approval-channel must be stdio');
|
|
56
|
+
}
|
|
57
|
+
export async function runDefaultInteractiveEntrypoint(environment) {
|
|
58
|
+
return runDefaultInteractiveEntrypointWithMainMenu(environment);
|
|
59
|
+
}
|
|
60
|
+
export async function runCodeCliCommand(parsed, environment) {
|
|
61
|
+
const [, command] = parsed.positionals;
|
|
62
|
+
if (command !== 'inspect' && command !== 'plan' && command !== 'craft' && command !== 'craft-preview' && command !== 'sdd')
|
|
63
|
+
return usageFailure(`Unknown code command: ${command ?? ''}`.trim());
|
|
64
|
+
const eventsJsonl = parsed.flags['events-jsonl'] === true;
|
|
65
|
+
const approvalChannel = codeApprovalChannelFlag(parsed.flags);
|
|
66
|
+
if (!approvalChannel.ok)
|
|
67
|
+
return resultFailure(approvalChannel);
|
|
68
|
+
if (approvalChannel.value === 'stdio' && (command !== 'craft' || !eventsJsonl))
|
|
69
|
+
return usageFailure('--approval-channel stdio is supported only for code craft --events-jsonl');
|
|
70
|
+
if (eventsJsonl && command !== 'inspect' && command !== 'plan' && command !== 'craft-preview' && approvalChannel.value !== 'stdio')
|
|
71
|
+
return usageFailure('code craft --events-jsonl requires --approval-channel stdio; JSONL without approvals is currently supported only for read-only inspect, plan, and craft-preview');
|
|
72
|
+
const maxSourceBytes = optionalNumberFlag(parsed.flags, 'max-source-bytes');
|
|
73
|
+
if (!maxSourceBytes.ok)
|
|
74
|
+
return resultFailure(maxSourceBytes);
|
|
75
|
+
const output = parsed.flags.json === true || optionalStringFlag(parsed.flags, 'output') === 'json' ? 'json' : 'human';
|
|
76
|
+
const approvalPolicy = codeApprovalPolicyFlag(parsed.flags);
|
|
77
|
+
if (!approvalPolicy.ok)
|
|
78
|
+
return resultFailure(approvalPolicy);
|
|
79
|
+
const verificationMode = codeVerificationModeFlag(parsed.flags);
|
|
80
|
+
if (!verificationMode.ok)
|
|
81
|
+
return resultFailure(verificationMode);
|
|
82
|
+
const transcriptMode = codeTranscriptModeFlag(parsed.flags);
|
|
83
|
+
if (!transcriptMode.ok)
|
|
84
|
+
return resultFailure(transcriptMode);
|
|
85
|
+
const memoryPolicy = codeMemoryPolicyFlag(parsed.flags);
|
|
86
|
+
if (!memoryPolicy.ok)
|
|
87
|
+
return resultFailure(memoryPolicy);
|
|
88
|
+
const provider = optionalStringFlag(parsed.flags, 'provider');
|
|
89
|
+
const model = optionalStringFlag(parsed.flags, 'model');
|
|
90
|
+
if (eventsJsonl) {
|
|
91
|
+
if (approvalChannel.value === 'stdio' && (environment.stdin === undefined || environment.stdout === undefined))
|
|
92
|
+
return resultFailure(validationFailure('--approval-channel stdio requires CLI stdin and stdout streams'));
|
|
93
|
+
return await runCodeCommand({
|
|
94
|
+
command,
|
|
95
|
+
args: parsed.positionals.slice(2),
|
|
96
|
+
cwd: environment.cwd,
|
|
97
|
+
output,
|
|
98
|
+
runGateway: new InMemoryRunGateway(),
|
|
99
|
+
project: optionalStringFlag(parsed.flags, 'project') ?? 'vgxness',
|
|
100
|
+
...(provider === undefined ? {} : { provider }),
|
|
101
|
+
...(model === undefined ? {} : { model }),
|
|
102
|
+
stream: parsed.flags.stream === true,
|
|
103
|
+
env: environment.env,
|
|
104
|
+
eventsJsonl,
|
|
105
|
+
memoryPolicy: 'off',
|
|
106
|
+
...(approvalChannel.value === undefined ? {} : { approvalChannel: approvalChannel.value }),
|
|
107
|
+
...(approvalChannel.value === 'stdio' ? { approvalDecisionInput: environment.stdin, eventOutput: environment.stdout } : {}),
|
|
108
|
+
...(maxSourceBytes.value !== undefined ? { maxSourceBytes: maxSourceBytes.value } : {}),
|
|
109
|
+
...(approvalPolicy.value === undefined ? {} : { approvalPolicy: approvalPolicy.value }),
|
|
110
|
+
...(verificationMode.value === undefined ? {} : { verificationMode: verificationMode.value }),
|
|
111
|
+
...(transcriptMode.value === undefined ? {} : { transcriptMode: transcriptMode.value }),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
const selectedDatabasePath = databasePathFor(parsed.flags, environment);
|
|
115
|
+
if (!selectedDatabasePath.ok)
|
|
116
|
+
return resultFailure(selectedDatabasePath);
|
|
117
|
+
const opened = openCliDatabase(selectedDatabasePath.value);
|
|
118
|
+
if (!opened.ok)
|
|
119
|
+
return resultFailure(opened);
|
|
120
|
+
try {
|
|
121
|
+
const runs = new RunService(opened.value);
|
|
122
|
+
const memory = new MemoryService(opened.value);
|
|
123
|
+
return await runCodeCommand({
|
|
124
|
+
command,
|
|
125
|
+
args: parsed.positionals.slice(2),
|
|
126
|
+
cwd: environment.cwd,
|
|
127
|
+
output,
|
|
128
|
+
runGateway: new RunsCodeRunGateway(runs),
|
|
129
|
+
sddGateway: new SddWorkflowGateway(new SddWorkflowService(memory)),
|
|
130
|
+
memoryGateway: new MemoryServiceCodeGateway(memory),
|
|
131
|
+
project: optionalStringFlag(parsed.flags, 'project') ?? 'vgxness',
|
|
132
|
+
...(provider === undefined ? {} : { provider }),
|
|
133
|
+
...(model === undefined ? {} : { model }),
|
|
134
|
+
stream: parsed.flags.stream === true,
|
|
135
|
+
env: environment.env,
|
|
136
|
+
eventsJsonl,
|
|
137
|
+
persistArtifact: parsed.flags['save-artifact'] === true || parsed.flags.persist === true,
|
|
138
|
+
...(maxSourceBytes.value !== undefined ? { maxSourceBytes: maxSourceBytes.value } : {}),
|
|
139
|
+
...(approvalPolicy.value === undefined ? {} : { approvalPolicy: approvalPolicy.value }),
|
|
140
|
+
...(verificationMode.value === undefined ? {} : { verificationMode: verificationMode.value }),
|
|
141
|
+
...(transcriptMode.value === undefined ? {} : { transcriptMode: transcriptMode.value }),
|
|
142
|
+
...(memoryPolicy.value === undefined ? {} : { memoryPolicy: memoryPolicy.value }),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
opened.value.close();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Re-export helpers
|
|
150
|
+
export { defaultNoTtyGuidance, };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import React from 'react';
|
|
3
2
|
import { AgentRegistryService } from '../../agents/agent-registry-service.js';
|
|
4
3
|
import { resolveAgentProfileModel } from '../../agents/profile-model-routing.js';
|
|
5
4
|
import { installOpenCodeMcpClient } from '../../mcp/client-install-opencode.js';
|
|
@@ -14,8 +13,6 @@ import { okText, usageFailure, validationFailure } from '../cli-help.js';
|
|
|
14
13
|
import { jsonResult, openCliDatabase, resultFailure } from '../cli-helpers.js';
|
|
15
14
|
import { renderSetupPlan } from '../setup-plan-renderer.js';
|
|
16
15
|
import { renderSetupStatus } from '../setup-status-renderer.js';
|
|
17
|
-
import { renderInkApp } from '../tui/render-ink-app.js';
|
|
18
|
-
import { SetupTuiApp } from '../tui/setup/setup-tui-app.js';
|
|
19
16
|
import { createDefaultSetupTuiServices } from '../tui/setup/setup-tui-services.js';
|
|
20
17
|
import { canRunInteractiveTui } from '../tui/terminal-capabilities.js';
|
|
21
18
|
function renderSetupRollbackApply(result, parsed) {
|
|
@@ -28,7 +25,7 @@ function renderSetupRollbackApply(result, parsed) {
|
|
|
28
25
|
`Target: ${result.value.targetPath}`,
|
|
29
26
|
`Restored from: ${result.value.backupPath}`,
|
|
30
27
|
...(result.value.preRollbackBackupPath === undefined ? [] : [`Pre-rollback backup: ${result.value.preRollbackBackupPath}`]),
|
|
31
|
-
'Next:
|
|
28
|
+
'Next: vgxness doctor; restart OpenCode and verify the vgxness MCP server is visible.',
|
|
32
29
|
];
|
|
33
30
|
return okText(`${lines.join('\n')}\n`);
|
|
34
31
|
}
|
|
@@ -92,7 +89,7 @@ export function runSetupRollbackCommand(parsed, environment) {
|
|
|
92
89
|
`Backup: ${result.value.backupPath}`,
|
|
93
90
|
...result.value.blockers.map((blocker) => `Blocker: ${blocker}`),
|
|
94
91
|
...result.value.warnings.map((warning) => `Warning: ${warning}`),
|
|
95
|
-
...(result.value.restorable ? [`Apply with:
|
|
92
|
+
...(result.value.restorable ? [`Apply with: vgxness setup rollback --backup ${result.value.backupPath} --yes`] : []),
|
|
96
93
|
];
|
|
97
94
|
return okText(`${lines.join('\n')}\n`);
|
|
98
95
|
}
|
|
@@ -156,7 +153,7 @@ export async function applySetupPlanInput(input, environment) {
|
|
|
156
153
|
status: 'installed',
|
|
157
154
|
plan: plan.value,
|
|
158
155
|
opencode: result,
|
|
159
|
-
nextCommands: ['
|
|
156
|
+
nextCommands: ['vgxness doctor', 'Restart OpenCode and verify the vgxness MCP server is visible.'],
|
|
160
157
|
},
|
|
161
158
|
}
|
|
162
159
|
: validationFailure(`${result.reason}: ${result.message}`);
|
|
@@ -339,7 +336,7 @@ export async function runInitCommandWithSetupTui(parsed, environment, setupTui)
|
|
|
339
336
|
}
|
|
340
337
|
export async function runSetupTuiCommand(environment, input) {
|
|
341
338
|
if (!canRunInteractiveTui(environment.stdin, environment.stdout))
|
|
342
|
-
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');
|
|
343
340
|
const selectedDatabasePath = databasePathSelectionFor({}, environment);
|
|
344
341
|
if (!selectedDatabasePath.ok)
|
|
345
342
|
return resultFailure(selectedDatabasePath);
|
|
@@ -361,7 +358,13 @@ export async function runSetupTuiCommand(environment, input) {
|
|
|
361
358
|
},
|
|
362
359
|
};
|
|
363
360
|
try {
|
|
364
|
-
|
|
361
|
+
const { renderOpenTuiSetup } = await import('../tui/opentui/setup/index.js');
|
|
362
|
+
await renderOpenTuiSetup({
|
|
363
|
+
services: createDefaultSetupTuiServices({ lifecycle, cwd: environment.cwd, env: environment.env }),
|
|
364
|
+
runtime,
|
|
365
|
+
stdin: environment.stdin,
|
|
366
|
+
stdout: environment.stdout,
|
|
367
|
+
});
|
|
365
368
|
return { exitCode: 0, stdout: '', stderr: '' };
|
|
366
369
|
}
|
|
367
370
|
finally {
|
package/dist/cli/dispatcher.js
CHANGED
|
@@ -4,7 +4,7 @@ import { isWorkflowId } from '../workflows/schema.js';
|
|
|
4
4
|
import { databasePathFor, parseArgs, requiredFlag } from './cli-flags.js';
|
|
5
5
|
import { okText, usageFailure, visibleHelpText } from './cli-help.js';
|
|
6
6
|
import { openCliDatabase, resultFailure } from './cli-helpers.js';
|
|
7
|
-
import { runAgentCommand, runApprovalsCommand, runCodeCliCommand,
|
|
7
|
+
import { runAgentCommand, runApprovalsCommand, runCodeCliCommand, runDefaultInteractiveEntrypoint, runDoctorAliasCommand, runInitCommand, runMcpDoctorCommand, runMcpInstallCommand, runMcpSetupCommand, runMemoryCommand, runMemoryImportCommand, runOpenCodeCommand, runOrchestratorCommand, runPermissionsCommand, runRunsCommand, runSddCommand, runSetupApplyCommand, runSetupLifecycleCommand, runSetupPlanCommand, runSetupRollbackCommand, runSkillCommand, runSubagentCommand, runVerificationPlanCommand, runVerificationReportCommand, runWorkflowExecuteCommand, runWorkflowPreviewCommand, runWorkflowRunCommand, } from './commands/index.js';
|
|
8
8
|
const _promptBuffers = new WeakMap();
|
|
9
9
|
const require = createRequire(import.meta.url);
|
|
10
10
|
const packageJson = require('../../package.json');
|
|
@@ -75,8 +75,6 @@ export function dispatchCli(argv, environment) {
|
|
|
75
75
|
return runOrchestratorCommand(command, parsed, opened.value);
|
|
76
76
|
if (area === 'opencode')
|
|
77
77
|
return runOpenCodeCommand(command, parsed, opened.value, environment);
|
|
78
|
-
if (area === 'dashboard')
|
|
79
|
-
return runDashboardCommand(command, parsed, opened.value, environment, databasePath);
|
|
80
78
|
return usageFailure(`Unknown command area: ${area}`);
|
|
81
79
|
}
|
|
82
80
|
finally {
|
|
@@ -91,8 +89,6 @@ export async function dispatchCliAsync(argv, environment) {
|
|
|
91
89
|
const [area, command] = parsed.positionals;
|
|
92
90
|
if (argv.length === 0)
|
|
93
91
|
return runDefaultInteractiveEntrypoint(environment);
|
|
94
|
-
if (area === 'dashboard' && command === 'interactive')
|
|
95
|
-
return runDashboardInteractiveCommand(parsed, environment);
|
|
96
92
|
if (area === 'mcp') {
|
|
97
93
|
if (!command)
|
|
98
94
|
return usageFailure('Missing command for mcp');
|
|
@@ -222,9 +218,6 @@ function validateCommand(area, command) {
|
|
|
222
218
|
if (area === 'verification') {
|
|
223
219
|
return command === 'plan' || command === 'report' ? { ok: true } : { ok: false, message: `Unknown verification command: ${command}` };
|
|
224
220
|
}
|
|
225
|
-
if (area === 'dashboard') {
|
|
226
|
-
return command === 'status' ? { ok: true } : { ok: false, message: `Unknown dashboard command: ${command}` };
|
|
227
|
-
}
|
|
228
221
|
if (area === 'code') {
|
|
229
222
|
return command === 'inspect' || command === 'plan' || command === 'craft' || command === 'sdd'
|
|
230
223
|
? { ok: true }
|
|
@@ -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/index.js
CHANGED
|
File without changes
|
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,8 +1,6 @@
|
|
|
1
1
|
export function resultForMainMenuOption(optionId) {
|
|
2
2
|
if (optionId === 'setup')
|
|
3
3
|
return { type: 'open-setup' };
|
|
4
|
-
if (optionId === 'dashboard')
|
|
5
|
-
return { type: 'open-dashboard' };
|
|
6
4
|
if (optionId === 'doctor')
|
|
7
5
|
return { type: 'show-doctor-guidance' };
|
|
8
6
|
if (optionId === 'sdd')
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tuiBadges } from '../visual/badges.js';
|
|
2
|
+
import { formatTuiFooter } from '../visual/footer.js';
|
|
2
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
|
+
];
|
|
3
10
|
const optionCopy = {
|
|
4
11
|
setup: {
|
|
5
12
|
label: 'Installation',
|
|
@@ -12,13 +19,6 @@ const optionCopy = {
|
|
|
12
19
|
'Provider writes require final confirmation; OpenCode is the only automatic provider with explicit consent.',
|
|
13
20
|
],
|
|
14
21
|
},
|
|
15
|
-
dashboard: {
|
|
16
|
-
label: 'Dashboard',
|
|
17
|
-
description: 'Inspect project health, runs, approvals, SDD, agents, and skills.',
|
|
18
|
-
badges: [tuiBadges.readOnly],
|
|
19
|
-
detailTitle: 'Interactive dashboard',
|
|
20
|
-
detailLines: ['Opens the existing read-only dashboard.', 'Dashboard navigation does not apply provider config or write OpenCode setup.'],
|
|
21
|
-
},
|
|
22
22
|
doctor: {
|
|
23
23
|
label: 'Doctor / recovery',
|
|
24
24
|
description: 'See health-check and recovery commands.',
|
|
@@ -63,8 +63,10 @@ export function buildMainMenuViewModel(state) {
|
|
|
63
63
|
contextLines: ['Choose where to go next. Installation is first; the menu itself is read-only and does not write provider config.'],
|
|
64
64
|
options,
|
|
65
65
|
detail: { title: focused.detailTitle, lines: focused.detailLines, badges: focused.badges },
|
|
66
|
+
statusSnapshot: { title: 'Status snapshot', lines: statusSnapshotLines, badges: [tuiBadges.readOnly, tuiBadges.noProviderWrites] },
|
|
66
67
|
safetyLines: [
|
|
67
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.',
|
|
68
70
|
'Installation/provider writes require final confirmation.',
|
|
69
71
|
'OpenCode is the only automatic provider path and still requires explicit consent.',
|
|
70
72
|
],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { formatBadges, tuiBadges } from '../visual/badges.js';
|
|
2
2
|
import { buildMainMenuViewModel } from './main-menu-read-model.js';
|
|
3
3
|
export function renderMainMenuShape(input) {
|
|
4
4
|
const state = input.width === undefined ? input.state : { ...input.state, viewport: { ...input.state.viewport, width: input.width } };
|
|
@@ -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,9 +23,24 @@ 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();
|
|
28
41
|
return `${line.slice(0, Math.max(0, width - 1)).trim()}…`;
|
|
29
42
|
}
|
|
43
|
+
function choiceLine(choice) {
|
|
44
|
+
const badges = formatBadges([...(choice.focused === true ? [tuiBadges.focused] : []), ...choice.badges]);
|
|
45
|
+
return `${choice.focused === true ? '›' : ' '} ${choice.label}${badges.length === 0 ? '' : ` ${badges}`} — ${choice.description}`;
|
|
46
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createTuiViewport } from '../visual/viewport.js';
|
|
2
|
-
export const mainMenuOptionIds = ['setup', '
|
|
2
|
+
export const mainMenuOptionIds = ['setup', 'doctor', 'sdd', 'advanced-cli', 'exit'];
|
|
3
3
|
export function createMainMenuState(input = {}) {
|
|
4
4
|
return {
|
|
5
5
|
focusedOptionId: input.focusedOptionId ?? 'setup',
|