vgxness 1.9.2 → 1.9.3
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 +9 -4
- package/dist/agents/agent-resolver.js +33 -3
- package/dist/agents/canonical-agent-manifest.js +39 -18
- package/dist/agents/canonical-agent-projection.js +31 -4
- package/dist/cli/cli-help.js +14 -3
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/interactive-entrypoint-dispatcher.js +8 -0
- package/dist/cli/commands/memory-sdd-dispatcher.js +71 -5
- package/dist/cli/commands/status-dispatcher.js +130 -0
- package/dist/cli/commands/workflow-dispatcher.js +11 -5
- package/dist/cli/dispatcher.js +9 -1
- package/dist/cli/product-resume-renderer.js +32 -0
- package/dist/cli/product-status-renderer.js +74 -0
- package/dist/cli/sdd-renderer.js +80 -3
- package/dist/code/cli/code-command.js +7 -4
- package/dist/code/reporting/summary.js +4 -1
- package/dist/code/runtime/code-runtime.js +27 -4
- package/dist/code/runtime/sdd-context.js +18 -2
- package/dist/governance/governance-report-builder.js +18 -7
- package/dist/mcp/claude-code-agent-config.js +10 -4
- package/dist/mcp/control-plane.js +56 -0
- package/dist/mcp/provider-status.js +86 -81
- package/dist/mcp/schema.js +25 -7
- package/dist/mcp/stdio-server.js +4 -0
- package/dist/mcp/validation.js +39 -3
- package/dist/resume/product-resume.js +166 -0
- package/dist/runs/repositories/runs.js +12 -1
- package/dist/runs/run-service.js +62 -5
- package/dist/sdd/schema.js +8 -0
- package/dist/sdd/sdd-continuation-plan.js +81 -0
- package/dist/sdd/sdd-workflow-service.js +103 -16
- package/dist/skills/skill-resolver.js +21 -4
- package/dist/status/product-status.js +117 -0
- package/docs/architecture.md +1 -1
- package/docs/cli.md +33 -8
- package/docs/code-runtime.md +3 -0
- package/docs/glossary.md +1 -1
- package/docs/mcp.md +18 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ This package is proprietary software. The npm package ships inspectable JavaScri
|
|
|
8
8
|
|
|
9
9
|
OpenCode is the primary supported provider. Other providers remain preview/manual only. Provider config writes require explicit CLI confirmation.
|
|
10
10
|
|
|
11
|
-
VGXNESS v1.9.1 has a canonical project health audit with validated evidence: 38 MCP tools, 106 test files, and the official Bun validation path passing, including package evidence with `releaseReadiness: pass`. See [Project health audit v1.9.1](./docs/project-health-audit-v1.9.1.md) for the versioned matrix and safety taxonomy.
|
|
11
|
+
VGXNESS v1.9.1 has a canonical project health audit with validated evidence: 38 MCP tools, 106 test files, and the official Bun validation path passing, including package evidence with `releaseReadiness: pass`. Current unreleased builds expose 41 MCP tools after adding read-only SDD/run recovery parity. See [Project health audit v1.9.1](./docs/project-health-audit-v1.9.1.md) for the versioned matrix and safety taxonomy.
|
|
12
12
|
|
|
13
13
|
## Requirements
|
|
14
14
|
|
|
@@ -144,7 +144,9 @@ In non-TTY shells, `vgxness init` prints the same read-only setup plan instead o
|
|
|
144
144
|
vgxness setup plan
|
|
145
145
|
vgxness setup apply --yes
|
|
146
146
|
vgxness doctor
|
|
147
|
-
vgxness
|
|
147
|
+
vgxness status --project <project> --change <change>
|
|
148
|
+
vgxness next --project <project> --change <change>
|
|
149
|
+
vgxness sdd continue --project <project> --change <change>
|
|
148
150
|
```
|
|
149
151
|
|
|
150
152
|
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:
|
|
@@ -159,7 +161,9 @@ Apply only after reviewing the plan:
|
|
|
159
161
|
vgxness setup apply --yes
|
|
160
162
|
```
|
|
161
163
|
|
|
162
|
-
`vgxness setup plan` and `vgxness setup status` are human-readable and do not write provider config by default; local VGXNESS store initialization may occur when a command needs the selected SQLite store. `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.
|
|
164
|
+
`vgxness setup plan` and `vgxness setup status` are human-readable and do not write provider config by default; local VGXNESS store initialization may occur when a command needs the selected SQLite store. `vgxness doctor`, `vgxness status`, `vgxness next`, `vgxness sdd status`, `vgxness sdd next`, `vgxness sdd continue`, 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.
|
|
165
|
+
|
|
166
|
+
The SDD happy path is `status` -> `next` -> `sdd continue` -> `code sdd` or `resume` -> `accept-artifact` or `reopen-artifact`. `sdd continue`, top-level `status`/`next`, and `resume` are advisory/read-only surfaces; related interrupted run hints and resume candidates help the operator choose the next command but do not execute providers or retry runs. Draft-run suggestions are planning-only: human acceptance is still required, and `apply-progress` remains gated.
|
|
163
167
|
|
|
164
168
|
## Code runtime (`vgxness code`)
|
|
165
169
|
|
|
@@ -181,8 +185,9 @@ Edits, shell, network, git mutations, SDD persistence, and memory saves route th
|
|
|
181
185
|
- Setup/status TUI surfaces are preview-oriented; run copied commands explicitly when you choose to act.
|
|
182
186
|
- SDD artifacts are SQLite-backed through VGXNESS services. Do not create or write `openspec/`.
|
|
183
187
|
- `vgxness sdd accept-artifact` records explicit human-only acceptance; saving a draft never implies acceptance.
|
|
188
|
+
- `vgxness sdd reopen-artifact` is the explicit path from a rejected artifact back to draft before revision.
|
|
184
189
|
- OpenCode is the primary supported provider; other providers are preview/manual extension points.
|
|
185
|
-
- VGXNESS exposes
|
|
190
|
+
- VGXNESS exposes 41 typed MCP tools across SDD, memory, sessions, agents, skills, runs, providers, and verification. See [MCP tools](./docs/mcp.md).
|
|
186
191
|
|
|
187
192
|
## Main menu entrypoint
|
|
188
193
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeSddPhaseInput } from '../sdd/schema.js';
|
|
1
2
|
export class AgentResolver {
|
|
2
3
|
loadAgents;
|
|
3
4
|
constructor(loadAgents) {
|
|
@@ -58,8 +59,10 @@ function normalizeInput(input) {
|
|
|
58
59
|
const desiredCapabilities = normalizeList(input.desiredCapabilities ?? []);
|
|
59
60
|
const taskDescription = normalizeText(input.taskDescription);
|
|
60
61
|
const intent = normalizeText(input.intent);
|
|
62
|
+
const phase = input.phase === undefined ? undefined : (isSddWorkflow(input.workflow) ? (normalizeSddPhaseInput(input.phase) ?? input.phase) : input.phase);
|
|
61
63
|
return {
|
|
62
64
|
...input,
|
|
65
|
+
...(phase !== undefined ? { phase } : {}),
|
|
63
66
|
...(taskDescription !== undefined ? { taskDescription } : {}),
|
|
64
67
|
...(intent !== undefined ? { intent } : {}),
|
|
65
68
|
desiredCapabilities,
|
|
@@ -143,7 +146,7 @@ function workflowMatches(agent, input) {
|
|
|
143
146
|
return [...matches.broad, ...matches.phaseOnly, ...matches.exactPhase];
|
|
144
147
|
}
|
|
145
148
|
function workflowSignalMatches(agent, input) {
|
|
146
|
-
const requested =
|
|
149
|
+
const requested = workflowRequestedSignals(input)
|
|
147
150
|
.filter((value) => value !== undefined)
|
|
148
151
|
.map(normalizeKey);
|
|
149
152
|
if (requested.length === 0)
|
|
@@ -154,17 +157,41 @@ function workflowSignalMatches(agent, input) {
|
|
|
154
157
|
const matches = { broad: [], phaseOnly: [], exactPhase: [] };
|
|
155
158
|
for (const agentWorkflow of agent.workflows) {
|
|
156
159
|
const normalizedWorkflow = normalizeKey(agentWorkflow);
|
|
157
|
-
|
|
160
|
+
const comparableWorkflow = canonicalSddWorkflowTargetKey(agentWorkflow);
|
|
161
|
+
if (!requested.includes(normalizedWorkflow) && !requested.includes(comparableWorkflow) && !sddApplyAliasMatches(agentWorkflow, input))
|
|
158
162
|
continue;
|
|
159
|
-
if (exact !== undefined && normalizedWorkflow === exact)
|
|
163
|
+
if (exact !== undefined && (normalizedWorkflow === exact || comparableWorkflow === exact))
|
|
160
164
|
matches.exactPhase.push(agentWorkflow);
|
|
161
165
|
else if (phase !== undefined && normalizedWorkflow === phase)
|
|
162
166
|
matches.phaseOnly.push(agentWorkflow);
|
|
167
|
+
else if (sddApplyAliasMatches(agentWorkflow, input))
|
|
168
|
+
matches.exactPhase.push(agentWorkflow);
|
|
163
169
|
else
|
|
164
170
|
matches.broad.push(agentWorkflow);
|
|
165
171
|
}
|
|
166
172
|
return matches;
|
|
167
173
|
}
|
|
174
|
+
function canonicalSddWorkflowTargetKey(workflow) {
|
|
175
|
+
const normalized = normalizeKey(workflow);
|
|
176
|
+
const separator = normalized.indexOf(':');
|
|
177
|
+
if (separator <= 0)
|
|
178
|
+
return normalized;
|
|
179
|
+
const workflowName = normalized.slice(0, separator);
|
|
180
|
+
const phase = normalized.slice(separator + 1);
|
|
181
|
+
if (workflowName !== 'sdd')
|
|
182
|
+
return normalized;
|
|
183
|
+
return `${workflowName}:${normalizeSddPhaseInput(phase) ?? phase}`;
|
|
184
|
+
}
|
|
185
|
+
function workflowRequestedSignals(input) {
|
|
186
|
+
return [input.workflow, input.phase, input.workflow !== undefined && input.phase !== undefined ? `${input.workflow}:${input.phase}` : undefined];
|
|
187
|
+
}
|
|
188
|
+
function sddApplyAliasMatches(agentWorkflow, input) {
|
|
189
|
+
if (input.phase === undefined || normalizeKey(input.phase) !== 'apply')
|
|
190
|
+
return false;
|
|
191
|
+
if (input.workflow !== undefined && !isSddWorkflow(input.workflow))
|
|
192
|
+
return false;
|
|
193
|
+
return normalizeKey(agentWorkflow) === 'sdd:apply-progress';
|
|
194
|
+
}
|
|
168
195
|
function phaseSemanticMatchesFor(agent, input) {
|
|
169
196
|
const workflow = input.workflow !== undefined ? normalizeKey(input.workflow) : undefined;
|
|
170
197
|
if (workflow !== undefined && workflow !== 'sdd')
|
|
@@ -220,6 +247,9 @@ function normalizeText(value) {
|
|
|
220
247
|
function normalizeKey(value) {
|
|
221
248
|
return value.trim().toLowerCase();
|
|
222
249
|
}
|
|
250
|
+
function isSddWorkflow(workflow) {
|
|
251
|
+
return workflow?.trim().toLowerCase() === 'sdd';
|
|
252
|
+
}
|
|
223
253
|
function tokenize(value) {
|
|
224
254
|
const seen = new Set();
|
|
225
255
|
return value
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { canonicalBehaviorContractVersion } from '../behavior/behavior-contract-manifest.js';
|
|
2
2
|
export const canonicalDefaultAgentName = 'vgxness-manager';
|
|
3
|
-
export const
|
|
3
|
+
export const canonicalOpenCodeDefaultModel = 'openai/gpt-5.5';
|
|
4
|
+
export const canonicalOpenCodeManagerReasoningEffort = 'high';
|
|
5
|
+
export const canonicalPromptContractVersion = 9;
|
|
4
6
|
export const canonicalSddSubagentNames = [
|
|
5
7
|
'vgxness-sdd-explore',
|
|
6
8
|
'vgxness-sdd-propose',
|
|
@@ -76,13 +78,13 @@ function managerDefinition() {
|
|
|
76
78
|
builtIn: true,
|
|
77
79
|
name: canonicalDefaultAgentName,
|
|
78
80
|
description: 'Coordinates VGXNESS MCP state and SDD sub-agents while routing Tier 0-2 lightweight work, Tier 3 preflight validation, and Tier 4 formal SDD.',
|
|
79
|
-
instructions: { kind: 'inline', value:
|
|
81
|
+
instructions: { kind: 'inline', value: registryManagerInstructionsV9 },
|
|
80
82
|
capabilities: ['sdd-orchestration', 'agent-routing', 'mcp-coordination', 'project-local-automation'],
|
|
81
83
|
permissions: { read: 'allow', edit: 'ask', shell: 'ask', git: 'ask', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' },
|
|
82
84
|
memory: { scopes: ['project'] },
|
|
83
85
|
workflows: ['explore', 'quickfix', 'plan', 'build', 'debug', 'sdd', 'agent-seeding', 'opencode-install'],
|
|
84
86
|
skills: ['vgxness-sdd-manager'],
|
|
85
|
-
adapters: { opencode: { model:
|
|
87
|
+
adapters: { opencode: { model: canonicalOpenCodeDefaultModel, config: { options: { reasoningEffort: canonicalOpenCodeManagerReasoningEffort, vgxnessPromptContractVersion: canonicalPromptContractVersion, vgxnessBehaviorContractVersion: canonicalBehaviorContractVersion }, permission: { task: createCanonicalOpenCodeSddTaskPermissions() } } } },
|
|
86
88
|
providerSupport: commonSupport(),
|
|
87
89
|
};
|
|
88
90
|
}
|
|
@@ -101,7 +103,7 @@ function subagentDefinition(name) {
|
|
|
101
103
|
memory: { scopes: ['project'] },
|
|
102
104
|
workflows: data.workflows,
|
|
103
105
|
skills: data.skills,
|
|
104
|
-
adapters: { opencode: { model:
|
|
106
|
+
adapters: { opencode: { model: canonicalOpenCodeDefaultModel, config: { hidden: true, options: { vgxnessPromptContractVersion: canonicalPromptContractVersion, vgxnessBehaviorContractVersion: canonicalBehaviorContractVersion } } } },
|
|
105
107
|
providerSupport: commonSupport(),
|
|
106
108
|
};
|
|
107
109
|
}
|
|
@@ -114,12 +116,17 @@ export function createCanonicalOpenCodeSddSubagentPrompt(name) {
|
|
|
114
116
|
const contract = subagentData[name].phaseContract;
|
|
115
117
|
return `${common}\n\nPhase contract: ${contract}\n\nSDD governance v1: SDD artifact acceptance is human-only. Do not mark, describe, or persist generated phase output as accepted unless the user explicitly accepts it or an MCP acceptance record shows a human actor. Before advancing phases, use VGXNESS MCP readiness/status tools so draft, rejected, superseded, or legacy artifacts are not treated as accepted prerequisites. For risky VGX-managed side effects, use VGXNESS run preflight/reporting and include runId, phase, and agent context when available. OpenCode native/provider tools are audit-only and non-hard-blocking in governance v1; do not claim they are hard-blocked by OpenCode config.\n\nProvider-native daily progression: daily SDD progression happens inside OpenCode through conversation, VGXNESS MCP, and hidden SDD subagents. Do not instruct the user to run terminal SDD phase commands for normal daily flow. Return phase output, decisions, changed files, and evidence so the manager can persist artifacts and advance through MCP. Preserve confirmation/preflight requirements for apply, verify, init, archive, edits, shell, git, provider-tool, secrets, destructive, privileged, or ambiguous operations.`;
|
|
116
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Provider runtime prompt for generated provider managers.
|
|
121
|
+
* This feeds the OpenCode default config and Claude generated agent files; it is
|
|
122
|
+
* intentionally separate from registry/seed instructions below.
|
|
123
|
+
*/
|
|
117
124
|
export const canonicalOpenCodeManagerPrompt = `# VGXNESS Manager - compact SDD orchestrator
|
|
118
125
|
|
|
119
|
-
Bind only to the primary \`vgxness-manager\` agent. Executor agents
|
|
126
|
+
Bind only to the primary \`vgxness-manager\` agent. Executor agents use their own prompts.
|
|
120
127
|
|
|
121
128
|
## Role
|
|
122
|
-
Coordinate SDD; keep chat thin, use VGXNESS MCP as durable state, delegate to the smallest exact hidden SDD subagent,
|
|
129
|
+
Coordinate SDD; keep chat thin, use VGXNESS MCP as durable state, delegate to the smallest exact hidden SDD subagent, synthesize evidence. Coach while coordinating: teach briefly, explain practical tradeoffs, stay realistic about risk/effort/unknowns, respectfully challenge weak assumptions, keep the user comfortable and in control, avoid lectures or unnecessary verbosity.
|
|
123
130
|
|
|
124
131
|
## Non-negotiable governance
|
|
125
132
|
- SDD artifact acceptance is human-only. Never infer or fabricate acceptance from generated output, subagent/model output, file presence, confidence, or legacy artifacts. Treat draft/rejected/superseded/stale/unaccepted artifacts as not accepted until a human acceptance record exists.
|
|
@@ -127,9 +134,8 @@ Coordinate SDD; keep chat thin, use VGXNESS MCP as durable state, delegate to th
|
|
|
127
134
|
- Before risky VGX-managed side effects (edit, shell/tests, git, network, provider-tool, secrets, external-directory, destructive, privileged, ambiguous), call \`vgxness_run_preflight\` with runId/workflow/phase/agent context when available. If approval/block is required, stop; do not invent approval.
|
|
128
135
|
- Direct human acceptance of an exact SDD artifact via \`vgxness_sdd_accept_artifact\` is not a generic SDD write for manager routing: do not call \`vgxness_run_preflight\` solely for that acceptance when the user explicitly accepted the exact project/change/phase artifact, \`acceptedBy.type\` is \`"human"\`, \`acceptedBy.id\` is non-empty, and status/readiness confirms the artifact is eligible. This shortcut applies only to \`vgxness_sdd_accept_artifact\`, not \`vgxness_sdd_save_artifact\`, edits, shell/tests, git, provider config, memory writes, external paths, secrets, destructive/privileged/ambiguous operations.
|
|
129
136
|
- OpenCode native/provider tools are governance-v1 audit-only/non-hard-blocking. Report warnings; do not say native OpenCode tools are hard-blocked by config.
|
|
130
|
-
- Do not mutate provider/global OpenCode config
|
|
131
|
-
- Do not
|
|
132
|
-
- Do not change model or reasoning effort.
|
|
137
|
+
- Do not mutate provider/global OpenCode config. Do not write to \`openspec/\`. Do not publish packages unless explicitly requested. Never revert/overwrite unrelated user work. Preserve \`permission.task\` deny-by-default with only exact known SDD subagents allowed.
|
|
138
|
+
- Do not change provider model/reasoning config unless explicitly requested.
|
|
133
139
|
|
|
134
140
|
## Flexible governance routing
|
|
135
141
|
Use the lightest safe path: Tier 0-2 direct; Tier 3 preflight/explicit validation; Tier 4 formal SDD for governance, permission model, SDD acceptance, architecture/security, or cross-surface behavior. Provider status/doctor/preview/handoff are read-only audit-only; provider config writes stay gated.
|
|
@@ -138,26 +144,41 @@ Use the lightest safe path: Tier 0-2 direct; Tier 3 preflight/explicit validatio
|
|
|
138
144
|
Daily SDD happens inside OpenCode through conversation, VGXNESS MCP, and hidden SDD subagents. Do not tell users to run terminal SDD phase commands for normal flow. CLI is an escape hatch for bootstrap, doctor, recovery, setup gaps, or explicit request.
|
|
139
145
|
|
|
140
146
|
## MCP playbook
|
|
141
|
-
- For starting, resuming, or recovering context: prefer \`vgxness_context_cockpit
|
|
142
|
-
- SDD artifacts: list/read with \`vgxness_sdd_get_artifact\`/\`vgxness_sdd_list_artifacts\`;
|
|
143
|
-
- Acceptance/readiness: check SDD status/readiness for the exact project/change/phase, confirm explicit human acceptance of that exact artifact, call \`vgxness_sdd_accept_artifact\` directly with audit context (\`acceptedBy.type: "human"\`, non-empty \`acceptedBy.id\`, runId, agentId
|
|
147
|
+
- For starting, resuming, or recovering context: prefer \`vgxness_context_cockpit\`; treat \`vgxness_session_restore\` as one signal, not truth. For ending, pausing, handing off, or compacting: \`vgxness_session_close\` with current session id and actor \`manager\`; if no id, do not invent one and summarize.
|
|
148
|
+
- SDD artifacts: guide state with \`vgxness_sdd_next\`/\`vgxness_sdd_cockpit\`; list/read with \`vgxness_sdd_get_artifact\`/\`vgxness_sdd_list_artifacts\`; prefer \`payloadMode: "compact"\` so the primary context stays clean; use verbose only when required, preferably inside the delegated phase subagent. Save with \`vgxness_sdd_save_artifact\` only after the appropriate flow. Use \`vgxness_sdd_reopen_artifact\` only for rejected artifacts returning to draft, with explicit human actor/audit context. SDD artifacts are not generic memory.
|
|
149
|
+
- Acceptance/readiness: check SDD status/readiness for the exact project/change/phase, confirm explicit human acceptance of that exact artifact, call \`vgxness_sdd_accept_artifact\` directly with audit context (\`acceptedBy.type: "human"\`, non-empty \`acceptedBy.id\`, runId, agentId), then re-check status/readiness before reporting state. Do not add \`vgxness_run_preflight\` solely for that exact direct acceptance call. Ambiguous replies count only when tied to an immediate exact acceptance prompt. Use \`vgxness_governance_report\` for readiness, artifact states, preflight posture, and audit warnings.
|
|
144
150
|
- Memory: call \`vgxness_memory_search\`/\`vgxness_memory_get\` for prior work or unclear context; call \`vgxness_memory_save\` for durable discoveries, decisions, bug fixes, config, patterns, or preferences; use \`vgxness_memory_update\` only to correct/evolve a known id. Do not duplicate full SDD artifacts as memory.
|
|
145
151
|
- Agents/profile/payloads: resolve exact phase with \`vgxness_agent_resolve\`. \`vgxness_agent_activate\`, \`vgxness_opencode_manager_payload\`, and \`vgxness_skill_payload\` are preview context only; agent_activate does not execute a provider or write provider config. Use \`vgxness_manager_profile_get\` before behavior changes; \`vgxness_manager_profile_set\` requires explicit human authorization.
|
|
146
|
-
- Runs: use \`vgxness_run_start\`/\`vgxness_run_list\`/\`vgxness_run_get\` for
|
|
147
|
-
- Provider diagnostics: \`vgxness_provider_status
|
|
152
|
+
- Runs/recovery: use \`vgxness_run_start\`/\`vgxness_run_list\`/\`vgxness_run_get\` for run work; checkpoint with \`vgxness_run_checkpoint\`, preflight with \`vgxness_run_preflight\`, and close with \`vgxness_run_finalize\`. Unknown runId: \`vgxness_run_resume_candidates\`. For interrupted runs, inspect with \`vgxness_run_resume_inspect\`, then call \`vgxness_run_resume_gate\` with approvalId from pendingApprovals/inspect before advice; never pass runId as approvalId
|
|
153
|
+
- Provider diagnostics: \`vgxness_provider_status\`/\`vgxness_provider_doctor\` are read-only reports.
|
|
148
154
|
|
|
149
155
|
## Minimum flows
|
|
150
156
|
- Simple answer: inline; memory only for prior context; no run by default.
|
|
151
|
-
- Proposal/spec/design/tasks: status/next -> readiness ->
|
|
152
|
-
- Apply/verify: require prerequisites ->
|
|
153
|
-
- Config/provider/prompt change: inspect manager/profile or payload first; persistent changes
|
|
157
|
+
- Proposal/spec/design/tasks: status/next -> readiness -> prerequisites -> exact subagent -> delegate -> persist by governance.
|
|
158
|
+
- Apply/verify: require prerequisites -> artifacts -> exact subagent -> start/recover run -> preflight writes/shell/git/tests -> delegate -> checkpoint -> save -> finalize.
|
|
159
|
+
- Config/provider/prompt change: inspect manager/profile or payload first; persistent changes need explicit human authorization.
|
|
160
|
+
- Recovery: MCP first. Continue: use \`vgxness_sdd_continue\`; read-only/advisory: no provider execution, run creation, artifact mutation, provider config/openspec writes, or acceptance/apply-progress bypass. CLI \`vgxness sdd continue\` is human fallback only. \`vgxness resume --project\` is for candidate runs; \`vgxness code sdd ... --draft-run\` is a planning-only path, never for apply-progress.
|
|
154
161
|
|
|
155
162
|
## Delegation thresholds
|
|
156
163
|
Inline only small decisions, 1-3 file reads, status commands, and atomic one-file mechanical edits. Delegate broad exploration, substantial implementation, writes with analysis/new logic, and execution-heavy verification. Never delegate to unknown agents; use exact SDD phase mapping.
|
|
157
164
|
|
|
158
165
|
## Output
|
|
159
166
|
Be concise: delegated work, results, files/decisions, evidence/tests, risks, next step.`;
|
|
160
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Registry/seed instructions for the manager agent definition.
|
|
169
|
+
* These feed the canonical manifest, checked-in seed, boot upgrade, registry
|
|
170
|
+
* render baselines, and manager profile overlay baselines; they are
|
|
171
|
+
* intentionally distinct from the provider runtime prompt above.
|
|
172
|
+
*/
|
|
173
|
+
const registryManagerInstructionsV9 = [
|
|
174
|
+
'You are the VGXNESS SDD coordinator, not a monolithic executor. Coach briefly while coordinating: explain useful tradeoffs, be realistic about risks and unknowns, respectfully challenge weak assumptions with better options, keep the user comfortable and in control, and stay concise.',
|
|
175
|
+
'Use VGXNESS MCP as the durable control plane: restore session context with vgxness_session_restore before inferring start/resume state from chat, and close/pause/compact with vgxness_session_close using actor manager plus an actionable summary when a current session id exists.',
|
|
176
|
+
'Check SDD status/next/ready/cockpit, read prerequisites with sdd_get_artifact or sdd_list_artifacts, use public sdd_continue/internal vgxness_sdd_continue first for advisory read-only continuation plans, use sdd_reopen_artifact only for rejected artifacts returning to draft with explicit human actor/audit context, save accepted phase output with sdd_save_artifact, search/get/save/update memory only for reusable knowledge, resolve exact SDD subagents before substantial phase work, use runs/checkpoints/preflight/finalize for significant implementation or verification, use run_resume_candidates for unknown runId, inspect interrupted runs by runId with run_resume_inspect, then call run_resume_gate with approvalId from pendingApprovals/inspect; never pass runId as approvalId; use vgxness_provider_status for configured/phase/next questions plus vgxness_provider_doctor for read-only OpenCode MCP/manager health.',
|
|
177
|
+
'Prefer payloadMode=compact for manager-facing status/context reads, SDD artifact reads/lists, and activation handoffs so the primary context stays clean; request payloadMode=verbose only when full artifact contents, provider payloads, or skill context are actually needed, preferably inside delegated phase subagents.',
|
|
178
|
+
'MCP sdd_continue must not execute providers, create runs, mutate artifacts, write provider config/openspec, bypass human acceptance, or treat draft-run as apply-progress.',
|
|
179
|
+
'CLI is an escape hatch for bootstrap, doctor, rollback, recovery, MCP unavailable/setup missing, or explicit user request; do not tell users to run terminal SDD phase commands for normal daily flow. CLI vgxness sdd continue is a human/manual fallback only; vgxness resume --project is for candidate runs, and vgxness code sdd ... --draft-run is planning-only.',
|
|
180
|
+
'OpenCode native/provider tools are governance-v1 audit-only/non-hard-blocking; report warnings, never say they are hard-blocked by config.',
|
|
181
|
+
].join(' ');
|
|
161
182
|
const subagentData = {
|
|
162
183
|
'vgxness-sdd-explore': { seedDescription: 'Investigates codebase context and identifies options before proposals.', seedInstructions: 'You are the explore phase executor, not the orchestrator. Do not delegate. Explore repository evidence for the requested SDD change. Do not implement code changes. Return concise findings, risks, and recommended next artifacts.', capabilities: ['sdd-exploration', 'codebase-research', 'discovery'], permissions: { read: 'allow', edit: 'deny', shell: 'ask', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:explore'], skills: ['vgxness-sdd-explore'], phaseContract: 'Investigate codebase context, constraints, options, and risks. Do not implement code changes. Return findings and recommended next artifacts.' },
|
|
163
184
|
'vgxness-sdd-propose': { seedDescription: 'Creates focused change proposals from exploration findings.', seedInstructions: 'You are the proposal phase executor, not the orchestrator. Do not delegate. Create a focused SDD proposal from exploration evidence. Do not implement code changes. Identify scope, tradeoffs, non-goals, and acceptance direction.', capabilities: ['sdd-proposal', 'proposal-planning', 'scope-definition'], permissions: { read: 'allow', edit: 'deny', shell: 'deny', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:proposal'], skills: ['vgxness-sdd-proposal'], phaseContract: 'Create or refine a focused SDD proposal from exploration evidence. Do not implement code changes. Include scope, tradeoffs, non-goals, and acceptance direction.' },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canonicalAgentManifest, canonicalDefaultAgentName, canonicalOpenCodeManagerPrompt, canonicalPromptContractVersion, canonicalSddSubagentNames, createCanonicalOpenCodeSddSubagentPrompt, createCanonicalOpenCodeSddTaskPermissions, validateCanonicalAgentManifest, } from './canonical-agent-manifest.js';
|
|
1
|
+
import { canonicalAgentManifest, canonicalDefaultAgentName, canonicalOpenCodeManagerReasoningEffort, canonicalOpenCodeManagerPrompt, canonicalPromptContractVersion, canonicalSddSubagentNames, createCanonicalOpenCodeSddSubagentPrompt, createCanonicalOpenCodeSddTaskPermissions, validateCanonicalAgentManifest, } from './canonical-agent-manifest.js';
|
|
2
2
|
export function canonicalManifestValidationErrors(manifest = canonicalAgentManifest) {
|
|
3
3
|
const validation = validateCanonicalAgentManifest(manifest);
|
|
4
4
|
return validation.ok ? [] : validation.errors;
|
|
@@ -19,10 +19,10 @@ export function projectCanonicalAgentManifestToOpenCode(manifest = canonicalAgen
|
|
|
19
19
|
description: 'VGXNESS SDD Manager - coordinates MCP state and SDD sub-agents, avoids inline execution when delegation is safer',
|
|
20
20
|
mode: 'primary',
|
|
21
21
|
...(manager.adapters?.opencode?.model !== undefined ? { model: manager.adapters.opencode.model } : {}),
|
|
22
|
-
options: { reasoningEffort:
|
|
23
|
-
permission: { task: createCanonicalOpenCodeSddTaskPermissions() },
|
|
22
|
+
options: { reasoningEffort: canonicalOpenCodeManagerReasoningEffort, vgxnessPromptContractVersion: canonicalPromptContractVersion },
|
|
23
|
+
permission: openCodePermissionsFor(manager, { task: createCanonicalOpenCodeSddTaskPermissions() }),
|
|
24
24
|
prompt: canonicalOpenCodeManagerPrompt,
|
|
25
|
-
reasoningEffort:
|
|
25
|
+
reasoningEffort: canonicalOpenCodeManagerReasoningEffort,
|
|
26
26
|
tools: { bash: true, delegate: true, delegation_list: true, delegation_read: true, edit: true, read: true, write: true },
|
|
27
27
|
variant: '',
|
|
28
28
|
},
|
|
@@ -38,6 +38,7 @@ export function projectCanonicalAgentManifestToOpenCode(manifest = canonicalAgen
|
|
|
38
38
|
...(subagent.adapters?.opencode?.model !== undefined ? { model: subagent.adapters.opencode.model } : {}),
|
|
39
39
|
options: { vgxnessPromptContractVersion: canonicalPromptContractVersion },
|
|
40
40
|
prompt: createCanonicalOpenCodeSddSubagentPrompt(name),
|
|
41
|
+
permission: openCodePermissionsFor(subagent),
|
|
41
42
|
tools: { bash: true, edit: true, read: true, write: true },
|
|
42
43
|
};
|
|
43
44
|
}
|
|
@@ -112,6 +113,32 @@ function assertValidCanonicalManifest(manifest) {
|
|
|
112
113
|
if (errors.length > 0)
|
|
113
114
|
throw new Error(`Invalid canonical agent manifest: ${errors.join('; ')}`);
|
|
114
115
|
}
|
|
116
|
+
function openCodePermissionsFor(agent, additional = {}) {
|
|
117
|
+
const adapterPermission = asRecord(agent.adapters?.opencode?.config?.permission);
|
|
118
|
+
return { ...adapterPermission, ...additional, ...mapCanonicalPermissionsToOpenCode(agent.permissions) };
|
|
119
|
+
}
|
|
120
|
+
function mapCanonicalPermissionsToOpenCode(permissions) {
|
|
121
|
+
const mapped = {};
|
|
122
|
+
if (permissions === undefined)
|
|
123
|
+
return mapped;
|
|
124
|
+
for (const [canonical, openCode] of openCodePermissionMappings) {
|
|
125
|
+
const decision = permissions[canonical];
|
|
126
|
+
if (decision !== undefined)
|
|
127
|
+
mapped[openCode] = decision;
|
|
128
|
+
}
|
|
129
|
+
return mapped;
|
|
130
|
+
}
|
|
131
|
+
function asRecord(value) {
|
|
132
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
133
|
+
return {};
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
const openCodePermissionMappings = [
|
|
137
|
+
['read', 'read'],
|
|
138
|
+
['edit', 'edit'],
|
|
139
|
+
['shell', 'bash'],
|
|
140
|
+
['external-directory', 'external_directory'],
|
|
141
|
+
];
|
|
115
142
|
function toSeedAgent(agent) {
|
|
116
143
|
const seed = {
|
|
117
144
|
name: agent.name,
|
package/dist/cli/cli-help.js
CHANGED
|
@@ -6,6 +6,9 @@ Global flags:
|
|
|
6
6
|
--version, -v Print the installed package version.
|
|
7
7
|
|
|
8
8
|
Areas:
|
|
9
|
+
status [--project <name>] [--change <id>] [--db <path>] [--json]
|
|
10
|
+
next [--project <name>] [--change <id>] [--db <path>] [--json]
|
|
11
|
+
resume [--project <name>] [--run-id <id>] [--db <path>] [--json]
|
|
9
12
|
init [--project <name>] [--provider opencode|claude|none] [--scope user|project] [--db global|project-local|custom|<path>] [--db-path <path>] [--mode mcp-only|mcp-plus-agents] [--json]
|
|
10
13
|
setup plan [--project <name>] [--provider opencode|claude|none] [--scope user|project] [--db global|project-local|custom|<path>] [--db-path <path>] [--mode mcp-only|mcp-plus-agents] [--json]
|
|
11
14
|
setup apply --yes [--project <name>] [--provider opencode|claude|none] [--scope user|project] [--db global|project-local|custom|<path>] [--db-path <path>] [--mode mcp-only|mcp-plus-agents]
|
|
@@ -16,6 +19,10 @@ Areas:
|
|
|
16
19
|
verification plan --type docs-only|test-only|cli|mcp|sdd-storage|provider-setup|package-release|workflow-runs [--json]
|
|
17
20
|
verification report save --project <name> --change <id> --file <report.json> [--db <path>] [--json]
|
|
18
21
|
verification report get --project <name> --change <id> [--db <path>] [--json]
|
|
22
|
+
Status answers "where am I?" with the human front-door cockpit.
|
|
23
|
+
Next answers "what should I do now?" with a shorter next-action view.
|
|
24
|
+
Resume answers "how do I continue interrupted work?" with run inspection guidance.
|
|
25
|
+
Without --change or --run-id they stay orientation-only and do not open local memory; with --change or --run-id they read SQLite read-only. Pass --json for automation.
|
|
19
26
|
Setup plan/init default to human-readable read-only output; pass --json for automation. Setup apply writes OpenCode config only with --yes and uses the global user DB plus mcp-plus-agents by default.
|
|
20
27
|
Setup status defaults to human-readable read-only output; pass --json for automation. It never writes provider config or executes providers.
|
|
21
28
|
Doctor defaults to human-readable output; pass --json for automation.
|
|
@@ -38,8 +45,8 @@ Areas:
|
|
|
38
45
|
code plan "<task>" [--json|--events-jsonl] [--max-source-bytes <n>] [--provider fake|openai-compatible] [--model <id>] [--stream] [--transcript off|summary|full] [--memory off|ask|auto]
|
|
39
46
|
code craft-preview "<task>" [--events-jsonl] [--provider fake|openai-compatible] [--model <id>] [--stream]
|
|
40
47
|
code craft "<task>" [--json|--events-jsonl --approval-channel stdio] [--max-source-bytes <n>] [--provider fake|openai-compatible] [--model <id>] [--stream] [--approval-policy ask|allow|deny] [--verification none|suggest|run|repair] [--transcript off|summary|full] [--memory off|ask|auto]
|
|
41
|
-
code sdd <change> <phase> [--json] [--save-artifact] [--provider fake|openai-compatible] [--model <id>] [--stream] [--verification none|suggest|run|repair] [--transcript off|summary|full] [--memory off|ask|auto]
|
|
42
|
-
VGXNESS Code inspect and plan are native read-only repository flows. Craft is bounded edit-capable work with approval-gated edits and shell verification; craft JSONL approvals require explicit --approval-channel stdio. SDD mode follows phase-specific artifact boundaries and saves only with --save-artifact.
|
|
48
|
+
code sdd <change> <phase> [--json] [--save-artifact] [--draft-run] [--provider fake|openai-compatible] [--model <id>] [--stream] [--verification none|suggest|run|repair] [--transcript off|summary|full] [--memory off|ask|auto]
|
|
49
|
+
VGXNESS Code inspect and plan are native read-only repository flows. Craft is bounded edit-capable work with approval-gated edits and shell verification; craft JSONL approvals require explicit --approval-channel stdio. SDD mode follows phase-specific artifact boundaries and saves only with --save-artifact. --draft-run lets planning phases use draft prerequisites only; human acceptance is still required and apply-progress remains gated.
|
|
43
50
|
|
|
44
51
|
orchestrator preview --project <name> --intent <text> [--change <id>] [--db <path>]
|
|
45
52
|
Orchestrator preview classifies natural-language requests only; it never executes providers, edits files, records runs, or writes provider config.
|
|
@@ -103,16 +110,20 @@ Areas:
|
|
|
103
110
|
|
|
104
111
|
sdd status --project <name> --change <id> [--json]
|
|
105
112
|
sdd next --project <name> --change <id> [--json]
|
|
113
|
+
sdd continue --project <name> --change <id> [--db <path>] [--json]
|
|
106
114
|
sdd cockpit --project <name> --change <id> [--json]
|
|
107
115
|
sdd ready --project <name> --change <id> --phase <phase>
|
|
108
116
|
sdd save-artifact --project <name> --change <id> --phase <phase> --content <text>
|
|
109
117
|
sdd accept-artifact --project <name> --change <id> --phase <phase> --actor <human-id> [--display-name <name>] [--note <text>] [--accepted-at <iso>] [--json] [--db <path>]
|
|
118
|
+
sdd reopen-artifact --project <name> --change <id> --phase <phase> --actor <human-id> [--display-name <name>] [--note <text>] [--json] [--db <path>]
|
|
110
119
|
sdd get-artifact --project <name> --change <id> --phase <phase> [--json] [--db <path>]
|
|
111
120
|
sdd list-artifacts --project <name> --change <id> [--json] [--db <path>]
|
|
112
121
|
SDD artifact reads use the selected local SQLite memory store via --db, VGXNESS_DB_PATH, or the global default.
|
|
113
|
-
SDD status, next, get-artifact, and list-artifacts default to human-readable output; pass --json for existing automation shapes.
|
|
122
|
+
SDD status, next, continue, get-artifact, and list-artifacts default to human-readable output; pass --json for existing automation shapes.
|
|
123
|
+
SDD continue is a read-only continuation planner; it never executes providers, mutates artifacts, creates runs, writes provider config, or creates openspec/.
|
|
114
124
|
SDD cockpit defaults to human-readable read-only output; pass --json for metadata-only artifact summaries.
|
|
115
125
|
SDD accept-artifact records explicit human-only acceptance; save-artifact remains draft-only and never implies acceptance. --accepted-at requires a timezone and is normalized to UTC ISO. Human output is default; pass --json for content-free success output.
|
|
126
|
+
SDD reopen-artifact records explicit human-only reopening of rejected artifacts only, moving them back to draft so they can be edited and accepted again.
|
|
116
127
|
sdd export --project <name> --change <id> [--file <package.json>]
|
|
117
128
|
sdd import --project <name> --change <id> --file <package.json> [--write] [--overwrite]
|
|
118
129
|
|
|
@@ -3,6 +3,7 @@ export { runCodeCliCommand, runDefaultInteractiveEntrypoint } from './interactiv
|
|
|
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';
|
|
6
|
+
export { runProductNextCommand, runProductResumeCommand, runProductStatusCommand } from './status-dispatcher.js';
|
|
6
7
|
export { applySetupPlanInput, collectRunDetails, collectRunInsights, createSetupLifecycleService, promptSetupWizard, readSetupStatus, runInitCommand, runSetupApplyCommand, runSetupBackupCommand, runSetupLifecycleCommand, runSetupPlanCommand, runSetupRollbackCommand, runSetupTuiCommand, setupMcpEvidence, setupPlanInputFromFlags, } from './setup-dispatcher.js';
|
|
7
8
|
export { runWorkflowExecuteCommand, runWorkflowPreviewCommand, runWorkflowRunCommand } from './workflow-dispatcher.js';
|
|
8
9
|
export { runVerificationPlanCommand, runVerificationReportCommand } from './verification-dispatcher.js';
|
|
@@ -69,6 +69,12 @@ export async function runCodeCliCommand(parsed, environment) {
|
|
|
69
69
|
return usageFailure('--approval-channel stdio is supported only for code craft --events-jsonl');
|
|
70
70
|
if (eventsJsonl && command !== 'inspect' && command !== 'plan' && command !== 'craft-preview' && approvalChannel.value !== 'stdio')
|
|
71
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 draftRunFlag = parsed.flags['draft-run'];
|
|
73
|
+
if (draftRunFlag !== undefined && command !== 'sdd')
|
|
74
|
+
return usageFailure('--draft-run is supported only for code sdd');
|
|
75
|
+
if (draftRunFlag !== undefined && draftRunFlag !== true)
|
|
76
|
+
return usageFailure('--draft-run does not accept a value; use --draft-run for code sdd draft mode');
|
|
77
|
+
const sddRuntimeMode = draftRunFlag === true ? 'draft-run' : undefined;
|
|
72
78
|
const maxSourceBytes = optionalNumberFlag(parsed.flags, 'max-source-bytes');
|
|
73
79
|
if (!maxSourceBytes.ok)
|
|
74
80
|
return resultFailure(maxSourceBytes);
|
|
@@ -109,6 +115,7 @@ export async function runCodeCliCommand(parsed, environment) {
|
|
|
109
115
|
...(approvalPolicy.value === undefined ? {} : { approvalPolicy: approvalPolicy.value }),
|
|
110
116
|
...(verificationMode.value === undefined ? {} : { verificationMode: verificationMode.value }),
|
|
111
117
|
...(transcriptMode.value === undefined ? {} : { transcriptMode: transcriptMode.value }),
|
|
118
|
+
...(sddRuntimeMode === undefined ? {} : { sddRuntimeMode }),
|
|
112
119
|
});
|
|
113
120
|
}
|
|
114
121
|
const selectedDatabasePath = databasePathFor(parsed.flags, environment);
|
|
@@ -135,6 +142,7 @@ export async function runCodeCliCommand(parsed, environment) {
|
|
|
135
142
|
env: environment.env,
|
|
136
143
|
eventsJsonl,
|
|
137
144
|
persistArtifact: parsed.flags['save-artifact'] === true || parsed.flags.persist === true,
|
|
145
|
+
...(sddRuntimeMode === undefined ? {} : { sddRuntimeMode }),
|
|
138
146
|
...(maxSourceBytes.value !== undefined ? { maxSourceBytes: maxSourceBytes.value } : {}),
|
|
139
147
|
...(approvalPolicy.value === undefined ? {} : { approvalPolicy: approvalPolicy.value }),
|
|
140
148
|
...(verificationMode.value === undefined ? {} : { verificationMode: verificationMode.value }),
|
|
@@ -6,14 +6,15 @@ import { planMemoryImportDryRun, validateMemoryImportPackage, writeMemoryImportO
|
|
|
6
6
|
import { MemoryService } from '../../memory/memory-service.js';
|
|
7
7
|
import { createNaturalLanguagePlan } from '../../orchestrator/natural-language-planner.js';
|
|
8
8
|
import { OpenCodeInjectionPreviewService } from '../../providers/opencode/injection-preview.js';
|
|
9
|
+
import { RunService } from '../../runs/run-service.js';
|
|
9
10
|
import { ArtifactPortabilityService } from '../../sdd/artifact-portability-service.js';
|
|
10
|
-
import {
|
|
11
|
+
import { normalizeSddArtifact, normalizeSddPhaseInput, sddPhases } from '../../sdd/schema.js';
|
|
11
12
|
import { SddWorkflowService } from '../../sdd/sdd-workflow-service.js';
|
|
12
13
|
import { SkillRegistryService } from '../../skills/skill-registry-service.js';
|
|
13
14
|
import { acceptedAtFlag, databasePathSelectionFor, optionalNumberFlag, optionalScopeFlag, optionalStringFlag, optionalTrimmedFlag, requiredFlag, requiredTrimmedFlag, scopeFlag, } from '../cli-flags.js';
|
|
14
15
|
import { okText, usageFailure, validationFailure } from '../cli-help.js';
|
|
15
16
|
import { formatMemoryImportValidationErrors, jsonResult, openCliDatabase, readJsonFile, resultFailure, validateMemoryImportMode, writeJsonFile, } from '../cli-helpers.js';
|
|
16
|
-
import { renderSddArtifactAccepted, renderSddCockpit, renderSddArtifactDetail, renderSddArtifactList, renderSddNext, renderSddStatus, } from '../sdd-renderer.js';
|
|
17
|
+
import { renderSddArtifactAccepted, renderSddArtifactReopened, renderSddCockpit, renderSddArtifactDetail, renderSddArtifactList, renderSddContinuationPlan, renderSddNext, renderSddStatus, sddContinuationPlanFrom, } from '../sdd-renderer.js';
|
|
17
18
|
export function runMemoryCommand(command, parsed, database) {
|
|
18
19
|
const handlers = createMemoryToolHandlers({ service: new MemoryService(database), config: { localMemoryEnabled: true } });
|
|
19
20
|
const context = { actor: 'cli' };
|
|
@@ -122,6 +123,26 @@ export function runSddCommand(command, parsed, database, environment) {
|
|
|
122
123
|
return jsonResult(next);
|
|
123
124
|
return okText(renderSddNext({ project: project.value, decision: next.value }));
|
|
124
125
|
}
|
|
126
|
+
if (command === 'continue') {
|
|
127
|
+
const next = service.getNext({ project: project.value, change: change.value });
|
|
128
|
+
if (!next.ok)
|
|
129
|
+
return jsonResult(next);
|
|
130
|
+
const cockpit = service.getCockpit({ project: project.value, change: change.value });
|
|
131
|
+
if (!cockpit.ok)
|
|
132
|
+
return jsonResult(cockpit);
|
|
133
|
+
const explicitDatabasePath = optionalStringFlag(parsed.flags, 'db');
|
|
134
|
+
const relatedRun = new RunService(database).findRelatedInterruptedSddRun({ project: project.value, change: change.value });
|
|
135
|
+
if (!relatedRun.ok)
|
|
136
|
+
return jsonResult(relatedRun);
|
|
137
|
+
const plan = sddContinuationPlanFrom({
|
|
138
|
+
project: project.value,
|
|
139
|
+
next: next.value,
|
|
140
|
+
cockpit: cockpit.value,
|
|
141
|
+
...(relatedRun.value === undefined ? {} : { relatedRunContext: relatedRun.value }),
|
|
142
|
+
...(explicitDatabasePath === undefined ? {} : { explicitDatabasePath }),
|
|
143
|
+
});
|
|
144
|
+
return parsed.flags.json === true ? jsonResult({ ok: true, value: plan }) : okText(renderSddContinuationPlan(plan));
|
|
145
|
+
}
|
|
125
146
|
if (command === 'cockpit') {
|
|
126
147
|
const cockpit = service.getCockpit({ project: project.value, change: change.value });
|
|
127
148
|
if (!cockpit.ok || parsed.flags.json === true)
|
|
@@ -159,7 +180,8 @@ export function runSddCommand(command, parsed, database, environment) {
|
|
|
159
180
|
return resultFailure(note);
|
|
160
181
|
if (!acceptedAt.ok)
|
|
161
182
|
return resultFailure(acceptedAt);
|
|
162
|
-
|
|
183
|
+
const canonicalPhase = normalizeSddPhaseInput(phase.value);
|
|
184
|
+
if (canonicalPhase === undefined)
|
|
163
185
|
return resultFailure(validationFailure(`Unknown SDD phase: ${phase.value}. Expected one of: ${sddPhases.join(', ')}`));
|
|
164
186
|
const acceptedBy = {
|
|
165
187
|
type: 'human',
|
|
@@ -169,7 +191,7 @@ export function runSddCommand(command, parsed, database, environment) {
|
|
|
169
191
|
const accepted = service.acceptArtifact({
|
|
170
192
|
project: project.value,
|
|
171
193
|
change: change.value,
|
|
172
|
-
phase:
|
|
194
|
+
phase: canonicalPhase,
|
|
173
195
|
acceptedBy,
|
|
174
196
|
acceptedAt: acceptedAt.value,
|
|
175
197
|
...(note.value === undefined ? {} : { note: note.value }),
|
|
@@ -179,7 +201,7 @@ export function runSddCommand(command, parsed, database, environment) {
|
|
|
179
201
|
const view = {
|
|
180
202
|
project: accepted.value.project,
|
|
181
203
|
change: change.value,
|
|
182
|
-
phase:
|
|
204
|
+
phase: canonicalPhase,
|
|
183
205
|
topicKey: accepted.value.topicKey,
|
|
184
206
|
artifactId: accepted.value.id,
|
|
185
207
|
status: 'accepted',
|
|
@@ -189,6 +211,50 @@ export function runSddCommand(command, parsed, database, environment) {
|
|
|
189
211
|
};
|
|
190
212
|
return parsed.flags.json === true ? jsonResult({ ok: true, value: view }) : okText(renderSddArtifactAccepted(view));
|
|
191
213
|
}
|
|
214
|
+
if (command === 'reopen-artifact') {
|
|
215
|
+
const phase = requiredTrimmedFlag(parsed.flags, 'phase');
|
|
216
|
+
const actor = requiredTrimmedFlag(parsed.flags, 'actor');
|
|
217
|
+
const displayName = optionalTrimmedFlag(parsed.flags, 'display-name');
|
|
218
|
+
const note = optionalTrimmedFlag(parsed.flags, 'note');
|
|
219
|
+
if (!phase.ok)
|
|
220
|
+
return resultFailure(phase);
|
|
221
|
+
if (!actor.ok)
|
|
222
|
+
return resultFailure(actor);
|
|
223
|
+
if (!displayName.ok)
|
|
224
|
+
return resultFailure(displayName);
|
|
225
|
+
if (!note.ok)
|
|
226
|
+
return resultFailure(note);
|
|
227
|
+
const canonicalPhase = normalizeSddPhaseInput(phase.value);
|
|
228
|
+
if (canonicalPhase === undefined)
|
|
229
|
+
return resultFailure(validationFailure(`Unknown SDD phase: ${phase.value}. Expected one of: ${sddPhases.join(', ')}`));
|
|
230
|
+
const reopenedBy = {
|
|
231
|
+
type: 'human',
|
|
232
|
+
id: actor.value,
|
|
233
|
+
displayName: displayName.value ?? actor.value,
|
|
234
|
+
};
|
|
235
|
+
const reopened = service.reopenArtifact({
|
|
236
|
+
project: project.value,
|
|
237
|
+
change: change.value,
|
|
238
|
+
phase: canonicalPhase,
|
|
239
|
+
reopenedBy,
|
|
240
|
+
...(note.value === undefined ? {} : { note: note.value }),
|
|
241
|
+
});
|
|
242
|
+
if (!reopened.ok)
|
|
243
|
+
return resultFailure(reopened);
|
|
244
|
+
const normalized = normalizeSddArtifact(reopened.value);
|
|
245
|
+
const view = {
|
|
246
|
+
project: reopened.value.project,
|
|
247
|
+
change: change.value,
|
|
248
|
+
phase: canonicalPhase,
|
|
249
|
+
topicKey: reopened.value.topicKey,
|
|
250
|
+
artifactId: reopened.value.id,
|
|
251
|
+
status: normalized.metadata.status,
|
|
252
|
+
reopenedBy,
|
|
253
|
+
reopenedAt: normalized.metadata.reopen?.reopenedAt ?? normalized.metadata.updatedAt ?? reopened.value.updatedAt,
|
|
254
|
+
...(note.value === undefined ? {} : { note: note.value }),
|
|
255
|
+
};
|
|
256
|
+
return parsed.flags.json === true ? jsonResult({ ok: true, value: view }) : okText(renderSddArtifactReopened(view));
|
|
257
|
+
}
|
|
192
258
|
if (command === 'get-artifact') {
|
|
193
259
|
const phase = requiredFlag(parsed.flags, 'phase');
|
|
194
260
|
if (!phase.ok)
|