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.
Files changed (85) hide show
  1. package/README.md +20 -19
  2. package/dist/cli/cli-help.js +4 -7
  3. package/dist/cli/commands/index.js +1 -1
  4. package/dist/cli/commands/interactive-entrypoint-dispatcher.js +150 -0
  5. package/dist/cli/commands/setup-dispatcher.js +11 -8
  6. package/dist/cli/dispatcher.js +1 -8
  7. package/dist/cli/doctor-renderer.js +1 -1
  8. package/dist/cli/index.js +0 -0
  9. package/dist/cli/sdd-renderer.js +7 -7
  10. package/dist/cli/setup-status-renderer.js +1 -0
  11. package/dist/cli/tui/main-menu/index.js +0 -1
  12. package/dist/cli/tui/main-menu/main-menu-controller.js +0 -2
  13. package/dist/cli/tui/main-menu/main-menu-read-model.js +10 -8
  14. package/dist/cli/tui/main-menu/main-menu-render-shape.js +19 -2
  15. package/dist/cli/tui/main-menu/main-menu-state.js +1 -1
  16. package/dist/cli/tui/opentui/code/index.js +210 -0
  17. package/dist/cli/tui/opentui/code/screen.js +107 -0
  18. package/dist/cli/tui/opentui/code/smoke.js +32 -0
  19. package/dist/cli/tui/opentui/main-menu/index.js +3 -0
  20. package/dist/cli/tui/opentui/main-menu/renderer.js +68 -0
  21. package/dist/cli/tui/opentui/main-menu/screen.js +68 -0
  22. package/dist/cli/tui/opentui/main-menu/smoke.js +17 -0
  23. package/dist/cli/tui/opentui/main-menu/view.js +8 -0
  24. package/dist/cli/tui/opentui/setup/index.js +3 -0
  25. package/dist/cli/tui/opentui/setup/renderer.js +87 -0
  26. package/dist/cli/tui/opentui/setup/screen.js +170 -0
  27. package/dist/cli/tui/opentui/setup/smoke.js +42 -0
  28. package/dist/cli/tui/opentui/setup/view.js +12 -0
  29. package/dist/cli/tui/setup/setup-tui-input.js +43 -0
  30. package/dist/cli/tui/setup/setup-tui-read-model.js +4 -4
  31. package/dist/cli/tui/setup/setup-tui-render-shape.js +9 -10
  32. package/dist/cli/tui/setup/setup-tui-state.js +1 -1
  33. package/dist/cli/tui/setup/setup-tui-view-helpers.js +46 -0
  34. package/dist/cli/tui/visual/index.js +0 -2
  35. package/dist/code/runtime/sdd-context.js +2 -2
  36. package/dist/code/tui/approval-actions.js +33 -0
  37. package/dist/code/tui/prompt-mode.js +11 -0
  38. package/dist/code/tui/runtime-events.js +320 -0
  39. package/dist/mcp/validation.js +6 -2
  40. package/dist/orchestrator/natural-language-planner.js +1 -1
  41. package/dist/sdd/sdd-workflow-service.js +1 -25
  42. package/dist/setup/backup-rollback-service.js +2 -2
  43. package/dist/setup/providers/antigravity-setup-adapter.js +1 -1
  44. package/dist/setup/providers/claude-setup-adapter.js +2 -2
  45. package/dist/setup/providers/custom-setup-adapter.js +1 -1
  46. package/dist/setup/providers/opencode-setup-adapter.js +3 -3
  47. package/dist/setup/setup-lifecycle-service.js +6 -6
  48. package/dist/setup/setup-plan.js +3 -3
  49. package/dist/verification/verification-plan-service.js +1 -1
  50. package/docs/architecture.md +43 -42
  51. package/docs/cli.md +141 -133
  52. package/docs/funcionamiento-del-sistema.md +22 -23
  53. package/docs/harness-gap-analysis.md +15 -1
  54. package/docs/prd.md +14 -14
  55. package/docs/vgxcode.md +87 -0
  56. package/docs/vgxness-code.md +6 -4
  57. package/package.json +5 -6
  58. package/dist/cli/commands/dashboard-dispatcher.js +0 -560
  59. package/dist/cli/dashboard-operational-read-models.js +0 -428
  60. package/dist/cli/dashboard-renderer.js +0 -158
  61. package/dist/cli/dashboard-screen-renderers.js +0 -256
  62. package/dist/cli/dashboard-tui-read-model.js +0 -73
  63. package/dist/cli/dashboard-tui-state.js +0 -314
  64. package/dist/cli/guided-main-menu.js +0 -470
  65. package/dist/cli/interactive-dashboard.js +0 -34
  66. package/dist/cli/setup-wizard-read-model.js +0 -72
  67. package/dist/cli/setup-wizard-renderer.js +0 -155
  68. package/dist/cli/setup-wizard-state.js +0 -82
  69. package/dist/cli/tui/dashboard/dashboard-adapter.js +0 -4
  70. package/dist/cli/tui/main-menu/main-menu-app.js +0 -28
  71. package/dist/cli/tui/render-ink-app.js +0 -10
  72. package/dist/cli/tui/setup/screens/applying-screen.js +0 -6
  73. package/dist/cli/tui/setup/screens/cancellation-screen.js +0 -6
  74. package/dist/cli/tui/setup/screens/error-recovery-screen.js +0 -6
  75. package/dist/cli/tui/setup/screens/final-confirmation-screen.js +0 -6
  76. package/dist/cli/tui/setup/screens/opencode-details-screen.js +0 -10
  77. package/dist/cli/tui/setup/screens/plan-review-screen.js +0 -6
  78. package/dist/cli/tui/setup/screens/project-database-screen.js +0 -6
  79. package/dist/cli/tui/setup/screens/provider-screen.js +0 -7
  80. package/dist/cli/tui/setup/screens/result-screen.js +0 -16
  81. package/dist/cli/tui/setup/screens/screen-components.js +0 -103
  82. package/dist/cli/tui/setup/screens/welcome-screen.js +0 -6
  83. package/dist/cli/tui/setup/setup-tui-app.js +0 -113
  84. package/dist/cli/tui/visual/choice-list.js +0 -10
  85. package/dist/cli/tui/visual/layout.js +0 -10
@@ -1,155 +0,0 @@
1
- import { badge, joinSections, renderActionLine, renderPanel } from './tui-render-helpers.js';
2
- export function renderSetupWizard(readModel, state, options = {}) {
3
- if (readModel === undefined) {
4
- return joinSections([
5
- renderPanel('Setup · Loading', [`${badge('loading')} Setup status is not loaded yet.`, 'Provider details will appear after setup status is loaded. Press r to refresh.'], { ...options, status: 'loading' }),
6
- renderFallbackProgress(state, options),
7
- ]);
8
- }
9
- return joinSections([
10
- renderSetupSummary(readModel, state, options),
11
- renderProgress(readModel.steps, state, options),
12
- renderProviderCards(readModel.providerCards, state, options),
13
- renderExternalActionsPanel(readModel.providerCards, state, options),
14
- renderPanel('Setup safety', [shortSafetySummary(readModel.safetySummary)], options),
15
- ]);
16
- }
17
- function renderSetupSummary(readModel, state, options) {
18
- const activeIndex = Math.max(0, readModel.steps.findIndex((step) => step.id === state.activeStep));
19
- const activeStep = readModel.steps[activeIndex] ?? readModel.steps[0];
20
- const title = `Setup · Step ${activeIndex + 1}/5 · ${activeStep?.label ?? 'Unknown'}`;
21
- return renderPanel(title, [
22
- `Status: ${badge(readModel.status)}`,
23
- `Summary: ${readModel.summary}`,
24
- `Project mode: ${readModel.projectMode}${readModel.project === undefined ? '' : ` (${readModel.project})`}`,
25
- 'Next safe action: review setup status here, then run any provider commands outside the TUI after review.',
26
- ], { ...options, status: readModel.status });
27
- }
28
- function renderProgress(steps, state, options) {
29
- return renderPanel('Setup steps', steps.map((step, index) => {
30
- const current = step.id === state.activeStep ? '› [current]' : ' ';
31
- const ordinal = `${index + 1}/5`;
32
- return `${current} ${ordinal} ${step.label} ${badge(step.status)} — ${step.summary}`;
33
- }), options);
34
- }
35
- function renderFallbackProgress(state, options) {
36
- const labels = ['Environment', 'Project', 'Providers', 'Agents', 'Verification'];
37
- const ids = ['environment', 'project', 'providers', 'agents', 'verification'];
38
- return renderPanel('Setup steps', labels.map((label, index) => {
39
- const current = ids[index] === state.activeStep ? '› [current]' : ' ';
40
- return `${current} ${index + 1}/5 ${label} ${badge('loading')}`;
41
- }), options);
42
- }
43
- function renderProviderCards(cards, state, options) {
44
- if (cards.length === 0)
45
- return renderPanel('Providers', ['Providers: none available yet.'], { ...options, status: 'empty' });
46
- return renderPanel('Provider cards', [...cards.map((card) => renderProviderRow(card, state)), ...renderFocusedProviderDetails(cards, state)], options);
47
- }
48
- function renderProviderRow(card, state) {
49
- const focused = state.focusedProviderId === card.id ? '› [focused]' : ' ';
50
- const selected = state.selectedProviderIds.includes(card.id) ? '[x]' : '[ ]';
51
- const support = supportLabel(card.supportLevel);
52
- const safetyLabels = setupSafetyLabels(card);
53
- return `${focused} ${selected} ${card.label} ${badge(card.status)} — ${support} ${safetyLabels.map(displaySafetyBadge).join(' ')} — ${card.summary}`;
54
- }
55
- function renderFocusedProviderDetails(cards, state) {
56
- const focusedCard = cards.find((card) => card.id === state.focusedProviderId) ?? cards[state.focusedIndex] ?? cards[0];
57
- if (focusedCard === undefined)
58
- return [];
59
- const targets = focusedCard.targets.length === 0
60
- ? 'Targets: none'
61
- : `Targets: ${focusedCard.targets.map((target) => `${target.label} (${target.kind}${target.path === undefined ? '' : `: ${target.path}`}; dashboard-write: no; no-TUI-write)`).join('; ')}`;
62
- const safetyLabels = setupSafetyLabels(focusedCard);
63
- return [
64
- '',
65
- 'Focused provider details:',
66
- ` ${focusedCard.label}: ${focusedCard.summary}`,
67
- ` Safety: ${safetyLabels.map(displaySafetyBadge).join(' ')}`,
68
- ` ${targets}`,
69
- ` Capabilities: ${focusedCard.capabilities.length === 0 ? 'none' : focusedCard.capabilities.join(', ')}`,
70
- ...renderFocusedProviderPreview(focusedCard),
71
- ...(focusedCard.guidance.length === 0 ? [] : [` Guidance: ${focusedCard.guidance.join(' ')}`]),
72
- ...(state.expandedProviderId === focusedCard.id && focusedCard.evidence.length > 0
73
- ? [' Evidence (presentational only):', ...focusedCard.evidence.map((item) => ` - ${item}`)]
74
- : []),
75
- ];
76
- }
77
- function renderFocusedProviderPreview(card) {
78
- if (card.preview === undefined)
79
- return [];
80
- return [
81
- ' Plan preview (read-only):',
82
- ` - ${card.preview.action}: ${card.preview.summary}`,
83
- ...(card.preview.targetPath === undefined ? [] : [` - Target: ${card.preview.targetPath}`]),
84
- ...(card.preview.backupRequired === undefined ? [] : [` - Backup required: ${String(card.preview.backupRequired)}`]),
85
- ...(card.preview.confirmationRequired === undefined ? [] : [` - Confirmation required: ${String(card.preview.confirmationRequired)}`]),
86
- ...(card.preview.risks.length === 0 ? [] : [` - Risks: ${card.preview.risks.join(' ')}`]),
87
- ...(card.preview.warnings.length === 0 ? [] : [` - Warnings: ${card.preview.warnings.join(' ')}`]),
88
- ];
89
- }
90
- function renderExternalActionsPanel(cards, state, options) {
91
- const focusedCard = cards.find((card) => card.id === state.focusedProviderId) ?? cards[state.focusedIndex] ?? cards[0];
92
- const focusedAction = focusedCard?.actions[0];
93
- const actionLines = cards.flatMap((card) => card.actions.flatMap((action) => renderActionLine(`${card.label}: ${action.label}`, {
94
- ...options,
95
- labels: action.safetyLabels.map(normalizeSafetyLabel),
96
- description: compactActionDescription(action.kind),
97
- })));
98
- return renderPanel('External actions', [
99
- 'Compact external-only guidance: [external] [no TUI writes]; provider config writes require confirmation outside the TUI.',
100
- ...(actionLines.length === 0 ? ['- No external actions available.'] : actionLines),
101
- ...(focusedCard === undefined || focusedAction === undefined ? [] : renderFocusedActionDetails(focusedCard, focusedAction)),
102
- ], options);
103
- }
104
- function renderFocusedActionDetails(card, action) {
105
- return [
106
- '',
107
- `Focused action details: ${card.label}: ${action.label} ${action.safetyLabels.map(displaySafetyBadge).join(' ')}`,
108
- ` Details: ${action.description.length === 0 ? `${action.kind}; run outside the TUI after review.` : action.description}`,
109
- ...(action.command === undefined || action.command.length === 0 ? [] : [` Command: ${action.command.join(' ')}`]),
110
- ];
111
- }
112
- function compactActionDescription(kind) {
113
- return `${kind}; external guidance only; no TUI writes.`;
114
- }
115
- function shortSafetySummary(items) {
116
- if (items.length === 0)
117
- return 'Read-only setup preview: [no TUI writes]; external actions are [external] and require review.';
118
- return 'Read-only setup preview: [no TUI writes]; external actions are [external] and require review outside the TUI.';
119
- }
120
- function supportLabel(level) {
121
- if (level === 'supported-primary')
122
- return 'Supported primary';
123
- if (level === 'preview-only')
124
- return 'Preview-only';
125
- if (level === 'placeholder')
126
- return 'Placeholder';
127
- if (level === 'extension-point')
128
- return 'Extension point';
129
- return 'Unsupported';
130
- }
131
- function setupSafetyLabels(card) {
132
- return unique(['No TUI writes', ...card.actions.flatMap((action) => action.safetyLabels)].map(normalizeSafetyLabel));
133
- }
134
- function unique(values) {
135
- return [...new Set(values)];
136
- }
137
- function displaySafetyBadge(value) {
138
- return badge(normalizeSafetyLabel(value));
139
- }
140
- function normalizeSafetyLabel(value) {
141
- const normalized = value.trim().toLowerCase();
142
- if (normalized === 'external')
143
- return 'external';
144
- if (normalized === 'mutating')
145
- return 'mutating';
146
- if (normalized === 'writes provider config')
147
- return 'writes provider config';
148
- if (normalized === 'no tui writes')
149
- return 'no TUI writes';
150
- if (normalized === 'requires explicit confirmation')
151
- return 'requires confirmation';
152
- if (normalized === 'no provider writes')
153
- return 'no TUI writes';
154
- return value;
155
- }
@@ -1,82 +0,0 @@
1
- export const setupWizardSteps = ['environment', 'project', 'providers', 'agents', 'verification'];
2
- export const defaultSetupProviderIds = ['opencode', 'claude', 'antigravity', 'custom'];
3
- export function createSetupWizardState(input = {}) {
4
- const selectedProviderIds = [...(input.selectedProviderIds ?? ['opencode'])];
5
- const focusedProviderId = input.focusedProviderId ?? defaultSetupProviderIds[0];
6
- return {
7
- activeStep: input.activeStep ?? 'environment',
8
- focusedIndex: clampFocus(input.focusedIndex ?? 0),
9
- projectMode: input.projectMode ?? 'none',
10
- selectedProviderIds,
11
- ...(input.selectedProject === undefined ? {} : { selectedProject: input.selectedProject }),
12
- ...(focusedProviderId === undefined ? {} : { focusedProviderId }),
13
- ...(input.expandedProviderId === undefined ? {} : { expandedProviderId: input.expandedProviderId }),
14
- };
15
- }
16
- export function setupWizardKeyFromInput(input) {
17
- if (input === 'n')
18
- return 'next';
19
- if (input === 'b')
20
- return 'back';
21
- if (input === ' ')
22
- return 'toggle';
23
- if (input === '\r' || input === '\n')
24
- return 'details';
25
- if (input === '\u001B')
26
- return 'escape';
27
- if (input === 'k' || input === '\u001B[A')
28
- return 'up';
29
- if (input === 'j' || input === '\u001B[B')
30
- return 'down';
31
- return undefined;
32
- }
33
- export function reduceSetupWizardKey(state, key) {
34
- if (key === 'next')
35
- return moveStep(state, 1);
36
- if (key === 'back')
37
- return moveStep(state, -1);
38
- if (key === 'up')
39
- return moveFocus(state, -1);
40
- if (key === 'down')
41
- return moveFocus(state, 1);
42
- if (key === 'toggle')
43
- return state.activeStep === 'providers' ? toggleFocusedProvider(state) : state;
44
- if (key === 'details')
45
- return state.activeStep === 'providers' ? toggleExpandedProvider(state) : state;
46
- if (key === 'escape')
47
- return state.expandedProviderId === undefined ? moveStep(state, -1) : withoutExpandedProvider(state);
48
- return state;
49
- }
50
- function moveStep(state, delta) {
51
- const index = setupWizardSteps.indexOf(state.activeStep);
52
- const nextIndex = Math.max(0, Math.min(index + delta, setupWizardSteps.length - 1));
53
- const activeStep = setupWizardSteps[nextIndex] ?? state.activeStep;
54
- return activeStep === state.activeStep ? state : { ...state, activeStep };
55
- }
56
- function moveFocus(state, delta) {
57
- const focusedIndex = clampFocus(state.focusedIndex + delta);
58
- if (state.activeStep !== 'providers')
59
- return focusedIndex === state.focusedIndex ? state : { ...state, focusedIndex };
60
- const focusedProviderId = defaultSetupProviderIds[focusedIndex] ?? state.focusedProviderId;
61
- return { ...state, focusedIndex, ...(focusedProviderId === undefined ? {} : { focusedProviderId }) };
62
- }
63
- function toggleFocusedProvider(state) {
64
- const providerId = state.focusedProviderId ?? defaultSetupProviderIds[state.focusedIndex];
65
- if (providerId === undefined)
66
- return state;
67
- const selected = state.selectedProviderIds.includes(providerId);
68
- return { ...state, selectedProviderIds: selected ? state.selectedProviderIds.filter((id) => id !== providerId) : [...state.selectedProviderIds, providerId] };
69
- }
70
- function toggleExpandedProvider(state) {
71
- const providerId = state.focusedProviderId ?? defaultSetupProviderIds[state.focusedIndex];
72
- if (providerId === undefined)
73
- return state;
74
- return state.expandedProviderId === providerId ? withoutExpandedProvider(state) : { ...state, expandedProviderId: providerId };
75
- }
76
- function withoutExpandedProvider(state) {
77
- const { expandedProviderId: _expandedProviderId, ...rest } = state;
78
- return rest;
79
- }
80
- function clampFocus(index) {
81
- return Math.max(0, Math.min(index, defaultSetupProviderIds.length - 1));
82
- }
@@ -1,4 +0,0 @@
1
- export const dashboardInkMigrationBoundary = {
2
- statusRendererRemainsText: true,
3
- interactiveDashboardRemainsCustom: true,
4
- };
@@ -1,28 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text, useApp, useInput, useStdout } from 'ink';
3
- import { useMemo, useState } from 'react';
4
- import { ChoiceList, createTuiViewport, ResponsiveColumns, TuiPanel, tuiBadges } from '../visual/index.js';
5
- import { mainMenuActionFromInput, reduceMainMenuState } from './main-menu-actions.js';
6
- import { buildMainMenuViewModel } from './main-menu-read-model.js';
7
- import { createMainMenuState } from './main-menu-state.js';
8
- export function MainMenuApp(props) {
9
- const { exit } = useApp();
10
- const { stdout } = useStdout();
11
- const initial = useMemo(() => props.initialState ?? createMainMenuState({ width: stdout?.columns }), [props.initialState, stdout?.columns]);
12
- const [state, setState] = useState(initial);
13
- const viewport = createTuiViewport(stdout?.columns, state.viewport.width);
14
- const visibleState = { ...state, viewport };
15
- const vm = useMemo(() => buildMainMenuViewModel(visibleState), [visibleState]);
16
- useInput((input, key) => {
17
- const action = mainMenuActionFromInput(input, key);
18
- if (action === undefined)
19
- return;
20
- const reduced = reduceMainMenuState(visibleState, action);
21
- setState(reduced.state);
22
- if (reduced.result !== undefined) {
23
- props.onResult?.(reduced.result);
24
- exit();
25
- }
26
- });
27
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: vm.title }), _jsxs(Text, { children: [vm.subtitle, " ", tuiBadges.readOnly] }), vm.contextLines.map((line) => (_jsx(Text, { children: line }, line)))] }), _jsx(ResponsiveColumns, { mode: viewport.mode, left: _jsx(TuiPanel, { title: "Menu", children: _jsx(ChoiceList, { choices: vm.options }) }), right: _jsx(TuiPanel, { title: vm.detail.title, badge: vm.detail.badges.join(' '), children: vm.detail.lines.map((line) => (_jsx(Text, { children: line }, line))) }) }), _jsx(TuiPanel, { title: "Safety", badge: tuiBadges.noProviderWrites, children: vm.safetyLines.map((line) => (_jsx(Text, { children: line }, line))) }), vm.helpLines.length === 0 ? null : (_jsx(TuiPanel, { title: "Help", badge: tuiBadges.readOnly, children: vm.helpLines.map((line) => (_jsx(Text, { children: line }, line))) })), _jsx(Text, { dimColor: true, children: vm.footer })] }));
28
- }
@@ -1,10 +0,0 @@
1
- import { render } from 'ink';
2
- export async function renderInkApp(element, options = {}) {
3
- const instance = render(element, options);
4
- try {
5
- await instance.waitUntilExit();
6
- }
7
- finally {
8
- instance.cleanup();
9
- }
10
- }
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { badgeLabels, Panel, SetupScreenFrame } from './screen-components.js';
4
- export function ApplyingScreen() {
5
- return (_jsx(SetupScreenFrame, { title: "Applying", footer: [], children: _jsxs(Panel, { title: "Applying setup", badge: { label: badgeLabels.pending }, children: [_jsx(Text, { children: "Applying confirmed OpenCode setup..." }), _jsx(Text, { children: "Waiting for the confirmed apply operation to finish." })] }) }));
6
- }
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { badgeLabels, Panel, SetupScreenFrame, setupFooterHints } from './screen-components.js';
4
- export function CancellationScreen() {
5
- return (_jsx(SetupScreenFrame, { title: "Setup cancelled", tone: "cancelled", footer: [setupFooterHints.close], children: _jsxs(Panel, { title: "Cancelled", badge: { label: badgeLabels.cancelled }, children: [_jsx(Text, { children: "Setup was not completed." }), _jsx(Text, { children: "No provider config was written." }), _jsx(Text, { children: "No agent seeding was performed." })] }) }));
6
- }
@@ -1,6 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { badgeLabels, Panel, SetupScreenFrame, setupFooterHints } from './screen-components.js';
4
- export function ErrorRecoveryScreen(props) {
5
- return (_jsx(SetupScreenFrame, { title: "Setup recovery", tone: "error", footer: [setupFooterHints.close], children: _jsxs(Panel, { title: "Error", badge: { label: badgeLabels.error }, children: [_jsxs(Text, { children: ["Error: ", props.message ?? 'Unknown setup error'] }), _jsx(Text, { children: "No unconfirmed provider config write was performed." }), _jsx(Text, { children: "Next: inspect `vgx setup plan`, resolve blockers, then retry." })] }) }));
6
- }
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { Panel, PlanSummary, SetupWorkspace, setupFooterHints } from './screen-components.js';
4
- export function FinalConfirmationScreen(props) {
5
- return (_jsx(SetupWorkspace, { title: "Final confirmation", viewModel: props.viewModel, footer: [setupFooterHints.confirmApply, setupFooterHints.back, setupFooterHints.cancel], children: _jsxs(Panel, { title: "Confirm OpenCode setup", children: [_jsx(PlanSummary, { viewModel: props.viewModel }), _jsx(Text, { children: "[warning]" }), _jsx(Text, { color: "yellow", children: "WARNING: OpenCode provider config may be modified at the target path above. Existing config is backed up when planned." }), _jsx(Text, { children: "After confirmation: run doctor, then restart OpenCode to reload MCP configuration." }), _jsx(Text, { children: "Press Enter to confirm and apply OpenCode setup, or Esc/q to cancel without writing." })] }) }));
6
- }
@@ -1,10 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { badgeLabels, ChoiceList, KeyValue, ManualNoProviderNotice, Panel, SetupWorkspace, setupFooterHints } from './screen-components.js';
4
- export function OpenCodeDetailsScreen(props) {
5
- const vm = props.viewModel;
6
- if (vm.providerLabel !== 'OpenCode') {
7
- return (_jsx(SetupWorkspace, { title: "OpenCode details", viewModel: vm, footer: [setupFooterHints.continue, setupFooterHints.back, setupFooterHints.cancel], children: _jsx(ManualNoProviderNotice, {}) }));
8
- }
9
- return (_jsx(SetupWorkspace, { title: "OpenCode details", viewModel: vm, footer: [setupFooterHints.select, setupFooterHints.continue, setupFooterHints.back, setupFooterHints.cancel], children: _jsxs(Panel, { title: "OpenCode plan", badge: { label: badgeLabels.writeAfterConfirm }, children: [_jsx(ChoiceList, { choices: vm.scopeChoices }), _jsx(ChoiceList, { choices: vm.installModeChoices }), _jsx(KeyValue, { label: "Scope", value: vm.scopeLabel }), _jsx(KeyValue, { label: "Install mode", value: vm.installModeLabel }), _jsx(KeyValue, { label: "Target config", value: vm.targetPathLabel }), _jsx(KeyValue, { label: "Action", value: vm.opencodeActionLabel }), _jsx(KeyValue, { label: "Agent readiness", value: vm.agentReadinessLabel }), _jsx(Text, { children: vm.agentReadinessDetail }), _jsx(Text, { children: "Details are preview-only here; writes require final confirmation." })] }) }));
10
- }
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { badgeLabels, Panel, PlanSummary, SetupWorkspace, setupFooterHints } from './screen-components.js';
4
- export function PlanReviewScreen(props) {
5
- return (_jsx(SetupWorkspace, { title: "Read-only plan review", viewModel: props.viewModel, footer: [setupFooterHints.finalConfirmation, setupFooterHints.back, setupFooterHints.cancel], children: _jsxs(Panel, { title: "Plan summary", badge: { label: badgeLabels.readOnly }, children: [_jsx(PlanSummary, { viewModel: props.viewModel }), _jsxs(Text, { children: ["Doctor next step: ", props.viewModel.nextCommands.find((command) => /\bdoctor\b/.test(command)) ?? 'vgx doctor'] }), _jsx(Text, { children: "Restart next step: Restart OpenCode after confirmed setup so it reloads MCP configuration." }), _jsx(Text, { children: "Review only: this screen does not write provider config." }), _jsx(Text, { children: props.viewModel.canAutoApply ? 'Press Enter to continue to final confirmation.' : 'Manual setup required; no automatic apply is available.' })] }) }));
6
- }
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ChoiceList, KeyValue, Panel, SetupWorkspace, setupFooterHints } from './screen-components.js';
3
- export function ProjectDatabaseScreen(props) {
4
- const vm = props.viewModel;
5
- return (_jsxs(SetupWorkspace, { title: "Project and database", viewModel: vm, footer: [setupFooterHints.select, setupFooterHints.continue, setupFooterHints.back, setupFooterHints.cancel], children: [_jsxs(Panel, { title: "Project", children: [_jsx(KeyValue, { label: "Project", value: vm.projectLabel }), _jsx(KeyValue, { label: "Workspace", value: vm.workspaceRootLabel })] }), _jsxs(Panel, { title: "Database", children: [_jsx(ChoiceList, { choices: vm.databaseChoices }), _jsx(KeyValue, { label: "Mode", value: vm.databaseLabel }), _jsx(KeyValue, { label: "Path", value: vm.databasePathLabel }), _jsx(KeyValue, { label: "Source", value: vm.databaseSourceLabel }), _jsx(KeyValue, { label: "Memory path explanation", value: vm.memoryPathExplanation })] })] }));
6
- }
@@ -1,7 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { ChoiceList, Panel, SetupWorkspace, setupFooterHints } from './screen-components.js';
4
- export function ProviderScreen(props) {
5
- const vm = props.viewModel;
6
- return (_jsx(SetupWorkspace, { title: "Provider", viewModel: vm, footer: [setupFooterHints.select, setupFooterHints.continue, setupFooterHints.back, setupFooterHints.cancel], children: _jsxs(Panel, { title: "Provider selection", children: [_jsx(ChoiceList, { choices: vm.providerChoices }), _jsx(Text, { children: vm.providerInstallabilityLabel }), _jsx(Text, { children: "OpenCode setup remains gated by final confirmation. Non-OpenCode/manual has no auto-apply." })] }) }));
7
- }
@@ -1,16 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { badgeLabels, KeyValue, Panel, SetupScreenFrame, setupFooterHints } from './screen-components.js';
4
- export function ResultScreen(props) {
5
- const result = props.result;
6
- if (result?.status === 'installed')
7
- return (_jsx(SetupScreenFrame, { title: "Setup complete", tone: "success", footer: [setupFooterHints.close], children: _jsxs(Panel, { title: "Installed", badge: { label: badgeLabels.success }, children: [_jsx(KeyValue, { label: "Target config", value: result.targetPath }), result.backupPath === undefined ? _jsx(Text, { children: "Backup: none created" }) : _jsx(KeyValue, { label: "Backup", value: result.backupPath }), result.warnings.map((warning) => (_jsxs(Text, { children: ["Warning: ", warning] }, warning))), resultNextCommands(props.viewModel).map((command) => (_jsxs(Text, { children: ["Next: ", command] }, command)))] }) }));
8
- if (result?.status === 'manual-required')
9
- return (_jsx(SetupScreenFrame, { title: "Manual setup", tone: "warning", footer: [setupFooterHints.close], children: _jsxs(Panel, { title: "Manual follow-up", badge: { label: badgeLabels.warning }, children: [_jsx(Text, { children: result.message }), props.viewModel.nextCommands.map((command) => (_jsxs(Text, { children: ["Next: ", command] }, command)))] }) }));
10
- return (_jsx(SetupScreenFrame, { title: "Setup result", footer: [setupFooterHints.close], children: _jsx(Panel, { title: "No write", children: _jsx(Text, { children: "No provider config write occurred." }) }) }));
11
- }
12
- function resultNextCommands(viewModel) {
13
- const filtered = viewModel.nextCommands.filter((command) => !/^vgx(?:ness)? setup apply\b/.test(command));
14
- const withDoctor = filtered.some((command) => /\bdoctor\b/.test(command)) ? filtered : [...filtered, 'vgx doctor'];
15
- return withDoctor.some((command) => /Restart OpenCode/i.test(command)) ? withDoctor : [...withDoctor, 'Restart OpenCode and verify the vgxness MCP server is visible.'];
16
- }
@@ -1,103 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from 'ink';
3
- import { formatTuiFooter } from '../../visual/footer.js';
4
- export const badgeLabels = {
5
- recommended: '[recommended]',
6
- selected: '[selected]',
7
- focused: '[focused]',
8
- warning: '[warning]',
9
- error: '[error]',
10
- writeAfterConfirm: '[will write after confirm]',
11
- readOnly: '[read-only]',
12
- manual: '[manual]',
13
- deferred: '[deferred]',
14
- cancelled: '[cancelled]',
15
- pending: '[pending]',
16
- success: '[success]',
17
- };
18
- export const setupFooterHints = {
19
- continue: { key: 'Enter', label: 'continue' },
20
- select: { key: 'Enter/Space', label: 'select focused row' },
21
- finalConfirmation: { key: 'Enter', label: 'final confirmation' },
22
- confirmApply: { key: 'Enter', label: 'confirm and apply' },
23
- help: { key: '?/h', label: 'help' },
24
- back: { key: 'Shift+Tab', label: 'back' },
25
- cancel: { key: 'q/Esc', label: 'cancel' },
26
- close: { key: 'q/Esc', label: 'close' },
27
- };
28
- export function SetupScreenFrame(props) {
29
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: props.title }), props.tone === undefined || props.tone === 'neutral' ? null : _jsx(Text, { children: toneBadge(props.tone) })] }), props.children, _jsx(Footer, { hints: props.footer ?? [setupFooterHints.continue, setupFooterHints.cancel] })] }));
30
- }
31
- export function SetupWorkspace(props) {
32
- return (_jsxs(SetupScreenFrame, { title: props.viewModel.title, ...(props.footer === undefined ? {} : { footer: props.footer }), children: [_jsxs(Panel, { title: props.viewModel.frameLabel, children: [_jsx(Text, { children: props.viewModel.progressLabel }), _jsx(Text, { children: props.viewModel.previewLabel })] }), _jsx(PreviewPane, { viewModel: props.viewModel }), props.children, _jsx(Text, { children: props.viewModel.footerSafetyLabel }), props.viewModel.helpVisible ? _jsx(HelpPanel, { lines: props.viewModel.helpLines }) : null] }));
33
- }
34
- export function Panel(props) {
35
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsxs(Text, { bold: true, children: [props.title, props.badge === undefined ? '' : ` ${props.badge.label}`] }), props.children] }));
36
- }
37
- export function Badge(props) {
38
- return _jsx(Text, { children: props.label });
39
- }
40
- export function ChoiceRow(props) {
41
- const badges = [
42
- ...(props.selected === true ? [{ label: badgeLabels.selected }] : []),
43
- ...(props.focused === true ? [{ label: badgeLabels.focused }] : []),
44
- ...(props.badges ?? []),
45
- ]
46
- .map((badge) => badge.label)
47
- .join(' ');
48
- return (_jsxs(Text, { children: [props.selected === true ? '›' : ' ', " ", props.label, badges.length === 0 ? '' : ` ${badges}`, " \u2014 ", props.description] }));
49
- }
50
- export function ChoiceList(props) {
51
- return (_jsx(Box, { flexDirection: "column", children: props.choices.map((choice) => (_jsx(ChoiceRow, { label: choice.label, description: choice.description, selected: choice.selected, focused: choice.focused, badges: choice.badges.map((label) => ({ label })) }, choice.id))) }));
52
- }
53
- export function HelpPanel(props) {
54
- return (_jsx(Panel, { title: "Help", badge: { label: badgeLabels.readOnly }, children: props.lines.map((line) => (_jsx(Text, { children: line }, line))) }));
55
- }
56
- export function PreviewPane(props) {
57
- return (_jsx(Panel, { title: "Live preview / details", badge: { label: badgeLabels.readOnly }, children: props.viewModel.previewDetailLines.map((line) => (_jsx(Text, { children: line }, line))) }));
58
- }
59
- export function Footer(props) {
60
- return _jsx(Text, { dimColor: true, children: formatFooter(props.hints, props.width ?? 80) });
61
- }
62
- export function KeyValue(props) {
63
- return (_jsxs(Text, { children: [props.label, ": ", props.value] }));
64
- }
65
- export function PlanSummary(props) {
66
- const vm = props.viewModel;
67
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(KeyValue, { label: "Readiness", value: `${vm.readinessBadge} ${vm.readinessLabel}` }), _jsx(KeyValue, { label: "Provider", value: vm.providerLabel }), _jsx(KeyValue, { label: "Database", value: vm.databaseLabel }), _jsx(KeyValue, { label: "Database path", value: vm.databasePathLabel }), _jsx(KeyValue, { label: "OpenCode scope", value: vm.scopeLabel }), _jsx(KeyValue, { label: "Install mode", value: vm.installModeLabel }), _jsx(KeyValue, { label: "Provider installability", value: vm.providerInstallabilityLabel }), _jsx(KeyValue, { label: "Agent readiness", value: vm.agentReadinessLabel }), _jsx(KeyValue, { label: "Agent detail", value: vm.agentReadinessDetail }), _jsx(KeyValue, { label: "Target config", value: vm.targetPathLabel }), _jsx(Text, { children: vm.backupLabel }), vm.plannedActions.map((action) => (_jsxs(Text, { children: ["Action: ", action.safetyBadge, " ", action.label, action.targetPathLabel === undefined ? '' : ` (${action.targetPathLabel})`] }, `action:${action.id}`))), vm.warnings.map((warning) => (_jsxs(Text, { children: ["Warning: ", warning] }, `warning:${warning}`))), vm.blockers.map((blocker) => (_jsxs(Text, { children: ["Blocked: ", blocker] }, `blocker:${blocker}`)))] }));
68
- }
69
- export function ManualNoProviderNotice() {
70
- return (_jsxs(Panel, { title: "Manual / no-provider-write mode", badge: { label: badgeLabels.manual }, children: [_jsx(Text, { children: "OpenCode-only scope and install controls are disabled because provider is Manual / none." }), _jsx(Text, { children: "Claude remains deferred/not installable in guided setup." }), _jsx(Text, { children: "No provider config will be written; use the manual next commands from the plan." })] }));
71
- }
72
- export function compactPath(path, width) {
73
- if (width <= 0 || path.length <= width)
74
- return path;
75
- const basename = path.split(/[\\/]/).filter(Boolean).pop() ?? path;
76
- if (basename.length + 4 >= width)
77
- return `.../${basename}`;
78
- const prefixWidth = Math.max(1, width - basename.length - 5);
79
- return `${path.slice(0, prefixWidth)}.../${basename}`;
80
- }
81
- export function wrapLabel(value, width) {
82
- if (width <= 0 || value.length <= width)
83
- return value;
84
- const protectedPhrases = ['final confirmation', 'confirm and apply', 'not installable', 'read-only', 'requires confirmation', 'will write after confirm', 'error', 'cancelled'];
85
- const phrase = protectedPhrases.find((candidate) => value.includes(candidate));
86
- if (phrase !== undefined)
87
- return `${value.slice(0, Math.max(0, width - phrase.length - 5)).trim()} ... ${phrase}`.trim();
88
- return `${value.slice(0, Math.max(0, width - 1)).trim()}…`;
89
- }
90
- export function formatFooter(hints, width) {
91
- return formatTuiFooter(hints, width);
92
- }
93
- function toneBadge(tone) {
94
- if (tone === 'success')
95
- return badgeLabels.success;
96
- if (tone === 'warning')
97
- return badgeLabels.warning;
98
- if (tone === 'error')
99
- return badgeLabels.error;
100
- if (tone === 'cancelled')
101
- return badgeLabels.cancelled;
102
- return '';
103
- }
@@ -1,6 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Text } from 'ink';
3
- import { Panel, SetupWorkspace, setupFooterHints } from './screen-components.js';
4
- export function WelcomeScreen(props) {
5
- return (_jsx(SetupWorkspace, { title: "Detect", viewModel: props.viewModel, footer: [setupFooterHints.continue, setupFooterHints.help, setupFooterHints.cancel], children: _jsxs(Panel, { title: "Guided installation sequence", children: [_jsx(Text, { children: "Setup welcome: global memory \u2192 provider \u2192 OpenCode details \u2192 agent readiness \u2192 preview \u2192 final confirmation \u2192 doctor/restart." }), _jsx(Text, { children: "VGXNESS Setup Assistant" }), _jsx(Text, { children: "Configure local storage and OpenCode integration with read-only previews first." }), _jsx(Text, { children: "No provider config is written until the final confirmation." })] }) }));
6
- }
@@ -1,113 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useApp, useInput } from 'ink';
3
- import { useEffect, useMemo, useState } from 'react';
4
- import { navigationIntentFromInput } from '../keymap.js';
5
- import { ApplyingScreen } from './screens/applying-screen.js';
6
- import { CancellationScreen } from './screens/cancellation-screen.js';
7
- import { ErrorRecoveryScreen } from './screens/error-recovery-screen.js';
8
- import { FinalConfirmationScreen } from './screens/final-confirmation-screen.js';
9
- import { OpenCodeDetailsScreen } from './screens/opencode-details-screen.js';
10
- import { PlanReviewScreen } from './screens/plan-review-screen.js';
11
- import { ProjectDatabaseScreen } from './screens/project-database-screen.js';
12
- import { ProviderScreen } from './screens/provider-screen.js';
13
- import { ResultScreen } from './screens/result-screen.js';
14
- import { WelcomeScreen } from './screens/welcome-screen.js';
15
- import { createSetupTuiController } from './setup-tui-controller.js';
16
- import { buildSetupTuiViewModel } from './setup-tui-read-model.js';
17
- import { createSetupTuiState } from './setup-tui-state.js';
18
- export function SetupTuiApp(props) {
19
- const { exit } = useApp();
20
- const [state, setState] = useState(props.initialState ?? createSetupTuiState({ selections: props.runtime.selections }));
21
- const viewModel = useMemo(() => buildSetupTuiViewModel(state), [state]);
22
- useEffect(() => {
23
- let active = true;
24
- void createSetupTuiController({ state, services: props.services, runtime: props.runtime })
25
- .load()
26
- .then((controller) => {
27
- if (active)
28
- setState(controller.state);
29
- });
30
- return () => {
31
- active = false;
32
- };
33
- // Load once for the mounted app; later previews flow through controller dispatch.
34
- // eslint-disable-next-line react-hooks/exhaustive-deps
35
- }, [props.runtime, props.services]);
36
- const dispatch = (action) => {
37
- void createSetupTuiController({ state, services: props.services, runtime: props.runtime })
38
- .dispatch(action)
39
- .then((controller) => {
40
- setState(controller.state);
41
- if (controller.state.screen === 'cancelled' || controller.state.screen === 'result' || controller.state.screen === 'error-recovery') {
42
- if (action.type === 'cancel')
43
- exit();
44
- }
45
- });
46
- };
47
- useInput((input, key) => {
48
- const action = setupTuiActionFromInput(input, key, state);
49
- if (action !== undefined)
50
- dispatch(action);
51
- });
52
- if (state.screen === 'welcome')
53
- return _jsx(WelcomeScreen, { viewModel: viewModel });
54
- if (state.screen === 'project-database')
55
- return _jsx(ProjectDatabaseScreen, { viewModel: viewModel });
56
- if (state.screen === 'provider')
57
- return _jsx(ProviderScreen, { viewModel: viewModel });
58
- if (state.screen === 'opencode-details')
59
- return _jsx(OpenCodeDetailsScreen, { viewModel: viewModel });
60
- if (state.screen === 'plan-review')
61
- return _jsx(PlanReviewScreen, { viewModel: viewModel });
62
- if (state.screen === 'final-confirmation')
63
- return _jsx(FinalConfirmationScreen, { viewModel: viewModel });
64
- if (state.screen === 'applying')
65
- return _jsx(ApplyingScreen, {});
66
- if (state.screen === 'cancelled')
67
- return _jsx(CancellationScreen, {});
68
- if (state.screen === 'error-recovery')
69
- return _jsx(ErrorRecoveryScreen, { message: state.error });
70
- return _jsx(ResultScreen, { result: state.result, viewModel: viewModel });
71
- }
72
- export function setupTuiActionFromInput(input, key, state) {
73
- if (key.upArrow === true)
74
- return { type: 'focus-previous-choice' };
75
- if (key.downArrow === true)
76
- return { type: 'focus-next-choice' };
77
- if (key.escape === true)
78
- return state.helpVisible ? { type: 'toggle-help' } : { type: 'cancel' };
79
- if (key.tab === true && key.shift === true)
80
- return { type: 'back' };
81
- if (key.tab === true)
82
- return { type: 'continue' };
83
- const raw = key.return === true ? '\n' : input;
84
- const intent = navigationIntentFromInput(raw);
85
- if (intent === 'cancel')
86
- return state.helpVisible ? { type: 'toggle-help' } : { type: 'cancel' };
87
- if (intent === 'help')
88
- return { type: 'toggle-help' };
89
- if (intent === 'up')
90
- return { type: 'focus-previous-choice' };
91
- if (intent === 'down')
92
- return { type: 'focus-next-choice' };
93
- if (intent === 'select')
94
- return { type: 'select-focused-choice' };
95
- if (intent === 'back')
96
- return { type: 'back' };
97
- if (intent !== 'next')
98
- return undefined;
99
- if (key.return === true && isEditableChoiceScreen(state))
100
- return { type: 'select-focused-choice' };
101
- if (state.screen === 'plan-review')
102
- return { type: 'request-apply' };
103
- if (state.screen === 'final-confirmation')
104
- return { type: 'confirm-apply' };
105
- return { type: 'continue' };
106
- }
107
- function isEditableChoiceScreen(state) {
108
- if (state.focusedChoiceId === undefined)
109
- return false;
110
- if (state.screen === 'project-database' || state.screen === 'provider')
111
- return true;
112
- return state.screen === 'opencode-details' && state.selections.provider === 'opencode';
113
- }
@@ -1,10 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Box, Text } from 'ink';
3
- import { formatBadges, tuiBadges } from './badges.js';
4
- export function choiceLine(choice) {
5
- const badges = formatBadges([...(choice.focused === true ? [tuiBadges.focused] : []), ...(choice.badges ?? [])]);
6
- return `${choice.focused === true ? '›' : ' '} ${choice.label}${badges.length === 0 ? '' : ` ${badges}`} — ${choice.description}`;
7
- }
8
- export function ChoiceList(props) {
9
- return (_jsx(Box, { flexDirection: "column", children: props.choices.map((choice) => (_jsx(Text, { children: choiceLine(choice) }, choice.id))) }));
10
- }
@@ -1,10 +0,0 @@
1
- import { jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Box, Text } from 'ink';
3
- export function TuiPanel(props) {
4
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", paddingX: 1, children: [_jsxs(Text, { bold: true, children: [props.title, props.badge === undefined ? '' : ` ${props.badge}`] }), props.children] }));
5
- }
6
- export function ResponsiveColumns(props) {
7
- if (props.mode === 'narrow')
8
- return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [props.left, props.right] }));
9
- return (_jsxs(Box, { flexDirection: "row", gap: 2, children: [props.left, props.right] }));
10
- }