vgxness 1.9.1 → 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 +15 -5
- package/dist/agents/agent-activation-service.js +13 -4
- package/dist/agents/agent-registry-service.js +8 -2
- package/dist/agents/agent-resolver.js +33 -3
- package/dist/agents/agent-seed-upgrade-service.js +231 -0
- package/dist/agents/boot-upgrade.js +59 -0
- package/dist/agents/canonical-agent-manifest.js +39 -18
- package/dist/agents/canonical-agent-projection.js +38 -4
- package/dist/agents/manager-profile-overlay-service.js +14 -0
- package/dist/agents/repositories/agent-seed-history.js +128 -0
- 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/mcp-dispatcher.js +7 -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 +11 -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/client-install-claude-code-contract.js +19 -4
- package/dist/mcp/client-install-claude-code.js +2 -2
- package/dist/mcp/control-plane.js +78 -5
- package/dist/mcp/provider-status.js +89 -88
- package/dist/mcp/schema.js +42 -8
- package/dist/mcp/stdio-server.js +6 -0
- package/dist/mcp/validation.js +77 -5
- package/dist/memory/sqlite/migrations/016_agent_seed_history.sql +15 -0
- 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/runs/schema.js +4 -0
- package/dist/sdd/schema.js +20 -0
- package/dist/sdd/sdd-continuation-plan.js +81 -0
- package/dist/sdd/sdd-workflow-service.js +146 -18
- package/dist/skills/skill-resolver.js +21 -4
- package/dist/status/product-status.js +117 -0
- package/docs/architecture.md +9 -1
- package/docs/cli.md +38 -13
- package/docs/code-runtime.md +3 -0
- package/docs/contributing.md +1 -1
- package/docs/glossary.md +2 -2
- package/docs/mcp.md +20 -6
- package/docs/project-health-audit-v1.9.1.md +126 -0
- package/docs/providers.md +4 -4
- package/docs/safety.md +1 -1
- package/package.json +1 -1
|
@@ -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
|
}
|
|
@@ -73,6 +74,13 @@ export function projectCanonicalAgentManifestToClaudeCode(manifest = canonicalAg
|
|
|
73
74
|
}
|
|
74
75
|
return { defaultAgent: canonicalDefaultAgentName, agents };
|
|
75
76
|
}
|
|
77
|
+
export function withEffectiveManagerInstructions(projection, instructions) {
|
|
78
|
+
const trimmed = instructions?.trim() ?? '';
|
|
79
|
+
if (trimmed === '')
|
|
80
|
+
return projection;
|
|
81
|
+
const agents = projection.agents.map((agent) => agent.canonicalName === projection.defaultAgent ? { ...agent, instructions: trimmed } : agent);
|
|
82
|
+
return { defaultAgent: projection.defaultAgent, agents };
|
|
83
|
+
}
|
|
76
84
|
export function projectCanonicalAgentManifestToClaudeProjectMemory(manifest = canonicalAgentManifest) {
|
|
77
85
|
assertValidCanonicalManifest(manifest);
|
|
78
86
|
return {
|
|
@@ -105,6 +113,32 @@ function assertValidCanonicalManifest(manifest) {
|
|
|
105
113
|
if (errors.length > 0)
|
|
106
114
|
throw new Error(`Invalid canonical agent manifest: ${errors.join('; ')}`);
|
|
107
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
|
+
];
|
|
108
142
|
function toSeedAgent(agent) {
|
|
109
143
|
const seed = {
|
|
110
144
|
name: agent.name,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { AgentRegistryService } from './agent-registry-service.js';
|
|
2
|
+
import { ManagerProfileOverlayRepository } from './repositories/manager-profile-overlays.js';
|
|
1
3
|
export class ManagerProfileOverlayService {
|
|
2
4
|
dependencies;
|
|
3
5
|
constructor(dependencies) {
|
|
@@ -36,3 +38,15 @@ function ok(value) {
|
|
|
36
38
|
function validationFailure(message) {
|
|
37
39
|
return { ok: false, error: { code: 'validation_failed', message } };
|
|
38
40
|
}
|
|
41
|
+
export function computeEffectiveManagerInstructions(database, project = 'vgxness', scope = 'project', managerName = 'vgxness-manager') {
|
|
42
|
+
const registry = new AgentRegistryService(database);
|
|
43
|
+
const overlays = new ManagerProfileOverlayRepository(database);
|
|
44
|
+
const service = new ManagerProfileOverlayService({ agents: registry, overlays });
|
|
45
|
+
const resolved = service.resolveEffectiveManager({ project, scope, managerName });
|
|
46
|
+
if (!resolved.ok || resolved.value.overlay === undefined)
|
|
47
|
+
return undefined;
|
|
48
|
+
const overlayInstructions = resolved.value.overlay.instructions.trim();
|
|
49
|
+
if (overlayInstructions === '')
|
|
50
|
+
return undefined;
|
|
51
|
+
return overlayInstructions;
|
|
52
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
export class AgentSeedHistoryRepository {
|
|
3
|
+
db;
|
|
4
|
+
constructor(db) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
}
|
|
7
|
+
append(input) {
|
|
8
|
+
const validation = validate(input);
|
|
9
|
+
if (!validation.ok)
|
|
10
|
+
return validation;
|
|
11
|
+
try {
|
|
12
|
+
const id = randomUUID();
|
|
13
|
+
const appliedAt = new Date().toISOString();
|
|
14
|
+
this.db.connection
|
|
15
|
+
.prepare(`
|
|
16
|
+
INSERT INTO agent_seed_history(id, applied_at, from_version, to_version, agent_name, project, scope, outcome, reason, source)
|
|
17
|
+
VALUES (@id, @appliedAt, @fromVersion, @toVersion, @agentName, @project, @scope, @outcome, @reason, @source)
|
|
18
|
+
`)
|
|
19
|
+
.run({
|
|
20
|
+
id,
|
|
21
|
+
appliedAt,
|
|
22
|
+
fromVersion: input.fromVersion,
|
|
23
|
+
toVersion: input.toVersion,
|
|
24
|
+
agentName: input.agentName,
|
|
25
|
+
project: input.project,
|
|
26
|
+
scope: input.scope,
|
|
27
|
+
outcome: input.outcome,
|
|
28
|
+
reason: input.reason ?? null,
|
|
29
|
+
source: input.source,
|
|
30
|
+
});
|
|
31
|
+
const entry = {
|
|
32
|
+
id,
|
|
33
|
+
appliedAt,
|
|
34
|
+
fromVersion: input.fromVersion,
|
|
35
|
+
toVersion: input.toVersion,
|
|
36
|
+
agentName: input.agentName,
|
|
37
|
+
project: input.project,
|
|
38
|
+
scope: input.scope,
|
|
39
|
+
outcome: input.outcome,
|
|
40
|
+
reason: input.reason ?? null,
|
|
41
|
+
source: input.source,
|
|
42
|
+
};
|
|
43
|
+
return ok(entry);
|
|
44
|
+
}
|
|
45
|
+
catch (cause) {
|
|
46
|
+
return fail('Failed to append agent_seed_history entry', cause);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
listRecent(filters = {}) {
|
|
50
|
+
try {
|
|
51
|
+
const where = [];
|
|
52
|
+
const parameters = {};
|
|
53
|
+
for (const [key, column] of [
|
|
54
|
+
['project', 'project'],
|
|
55
|
+
['scope', 'scope'],
|
|
56
|
+
['agentName', 'agent_name'],
|
|
57
|
+
]) {
|
|
58
|
+
const value = filters[key];
|
|
59
|
+
if (value !== undefined) {
|
|
60
|
+
where.push(`${column}=@${key}`);
|
|
61
|
+
parameters[key] = value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const limit = Math.max(1, Math.min(filters.limit ?? 100, 1000));
|
|
65
|
+
const rows = this.db.connection
|
|
66
|
+
.prepare(`
|
|
67
|
+
SELECT * FROM agent_seed_history
|
|
68
|
+
${where.length ? `WHERE ${where.join(' AND ')}` : ''}
|
|
69
|
+
ORDER BY applied_at DESC
|
|
70
|
+
LIMIT ${limit}
|
|
71
|
+
`)
|
|
72
|
+
.all(parameters);
|
|
73
|
+
return ok(rows.map(map));
|
|
74
|
+
}
|
|
75
|
+
catch (cause) {
|
|
76
|
+
return fail('Failed to list agent_seed_history entries', cause);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function validate(input) {
|
|
81
|
+
if (!input.project.trim())
|
|
82
|
+
return validationFailure('agent_seed_history project is required');
|
|
83
|
+
if (input.scope !== 'project' && input.scope !== 'personal')
|
|
84
|
+
return validationFailure('agent_seed_history scope is invalid');
|
|
85
|
+
if (!input.agentName.trim())
|
|
86
|
+
return validationFailure('agent_seed_history agentName is required');
|
|
87
|
+
if (!Number.isInteger(input.toVersion) || input.toVersion <= 0)
|
|
88
|
+
return validationFailure('agent_seed_history toVersion must be a positive integer');
|
|
89
|
+
if (input.fromVersion !== null && (!Number.isInteger(input.fromVersion) || input.fromVersion < 0))
|
|
90
|
+
return validationFailure('agent_seed_history fromVersion must be null or non-negative integer');
|
|
91
|
+
if (!input.source.trim())
|
|
92
|
+
return validationFailure('agent_seed_history source is required');
|
|
93
|
+
if (input.outcome !== 'created' &&
|
|
94
|
+
input.outcome !== 'upgraded' &&
|
|
95
|
+
input.outcome !== 'noop' &&
|
|
96
|
+
input.outcome !== 'overwrote-custom-instructions' &&
|
|
97
|
+
input.outcome !== 'validation_failed' &&
|
|
98
|
+
input.outcome !== 'db_error') {
|
|
99
|
+
return validationFailure(`agent_seed_history outcome is invalid: ${input.outcome}`);
|
|
100
|
+
}
|
|
101
|
+
return ok(undefined);
|
|
102
|
+
}
|
|
103
|
+
function map(row) {
|
|
104
|
+
return {
|
|
105
|
+
id: String(row.id),
|
|
106
|
+
appliedAt: String(row.applied_at),
|
|
107
|
+
fromVersion: row.from_version === null || row.from_version === undefined ? null : Number(row.from_version),
|
|
108
|
+
toVersion: Number(row.to_version),
|
|
109
|
+
agentName: String(row.agent_name),
|
|
110
|
+
project: String(row.project),
|
|
111
|
+
scope: row.scope,
|
|
112
|
+
outcome: String(row.outcome),
|
|
113
|
+
reason: row.reason === null || row.reason === undefined ? null : String(row.reason),
|
|
114
|
+
source: String(row.source),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function ok(value) {
|
|
118
|
+
return { ok: true, value };
|
|
119
|
+
}
|
|
120
|
+
function validationFailure(message) {
|
|
121
|
+
return { ok: false, error: { code: 'validation_failed', message } };
|
|
122
|
+
}
|
|
123
|
+
function fail(message, cause) {
|
|
124
|
+
const error = { code: 'validation_failed', message };
|
|
125
|
+
if (cause !== undefined)
|
|
126
|
+
error.cause = cause;
|
|
127
|
+
return { ok: false, error };
|
|
128
|
+
}
|
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,7 +6,9 @@ import { createMcpClientSetupPreview, isMcpClientSetupProvider } from '../../mcp
|
|
|
6
6
|
import { createMcpDoctorReport } from '../../mcp/doctor.js';
|
|
7
7
|
import { createOpenCodeMcpVisibilityReport } from '../../mcp/opencode-visibility.js';
|
|
8
8
|
import { resolveClaudeCodeScope } from '../../mcp/claude-code-scope.js';
|
|
9
|
+
import { computeEffectiveManagerInstructions } from '../../agents/manager-profile-overlay-service.js';
|
|
9
10
|
import { RunService } from '../../runs/run-service.js';
|
|
11
|
+
import { isTerminalRunStatus } from '../../runs/schema.js';
|
|
10
12
|
import { databasePathFor, databasePathSelectionFor, opencodeInstallScopeFlag, optionalNumberFlag, optionalStringFlag } from '../cli-flags.js';
|
|
11
13
|
import { usageFailure, validationFailure } from '../cli-help.js';
|
|
12
14
|
import { jsonResult, openCliDatabase, resultFailure } from '../cli-helpers.js';
|
|
@@ -42,6 +44,7 @@ export function runMcpInstallCommand(parsed, environment) {
|
|
|
42
44
|
return resultFailure(opened);
|
|
43
45
|
try {
|
|
44
46
|
const preflight = createClaudeCodeInstallPreflight(parsed, opened.value, environment);
|
|
47
|
+
const effectiveManagerInstructions = computeEffectiveManagerInstructions(opened.value);
|
|
45
48
|
const result = await installClaudeCodeMcpClient({
|
|
46
49
|
cwd: environment.cwd,
|
|
47
50
|
databasePath: databasePath.value.path,
|
|
@@ -50,6 +53,7 @@ export function runMcpInstallCommand(parsed, environment) {
|
|
|
50
53
|
overwriteVgxness,
|
|
51
54
|
scope: claudeScope.value,
|
|
52
55
|
preflight,
|
|
56
|
+
...(effectiveManagerInstructions === undefined ? {} : { effectiveManagerInstructions }),
|
|
53
57
|
});
|
|
54
58
|
return result.status === 'installed' ? jsonResult({ ok: true, value: result }) : resultFailure({ ok: false, error: { code: 'validation_failed', message: `${result.reason}: ${result.message}` } });
|
|
55
59
|
}
|
|
@@ -107,6 +111,9 @@ function createClaudeCodeInstallPreflight(parsed, database, environment) {
|
|
|
107
111
|
const details = service.getRun(runId);
|
|
108
112
|
if (!details.ok)
|
|
109
113
|
return details;
|
|
114
|
+
if (isTerminalRunStatus(details.value.status)) {
|
|
115
|
+
return validationFailure(`VGXNESS run ${runId} is in terminal state '${details.value.status}'; Claude Code provider config writes require a live run (created/planned/running/needs-human). Start a new run with \`vgxness run start\` and pass its --run-id.`);
|
|
116
|
+
}
|
|
110
117
|
const phase = optionalStringFlag(parsed.flags, 'phase') ?? details.value.phase;
|
|
111
118
|
const agentId = optionalStringFlag(parsed.flags, 'agent-id') ?? details.value.selectedAgentId;
|
|
112
119
|
const preflight = service.preflightOperation({
|
|
@@ -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)
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { MemoryService } from '../../memory/memory-service.js';
|
|
2
|
+
import { openMemoryDatabase } from '../../memory/sqlite/database.js';
|
|
3
|
+
import { SddWorkflowService } from '../../sdd/sdd-workflow-service.js';
|
|
4
|
+
import { buildProductStatus } from '../../status/product-status.js';
|
|
5
|
+
import { RunService } from '../../runs/run-service.js';
|
|
6
|
+
import { buildProductResume } from '../../resume/product-resume.js';
|
|
7
|
+
import { databasePathFor, optionalStringFlag, requiredFlag } from '../cli-flags.js';
|
|
8
|
+
import { jsonResult, resultFailure } from '../cli-helpers.js';
|
|
9
|
+
import { okText, usageFailure } from '../cli-help.js';
|
|
10
|
+
import { renderProductResume } from '../product-resume-renderer.js';
|
|
11
|
+
import { buildProductNext, renderProductNext, renderProductStatus } from '../product-status-renderer.js';
|
|
12
|
+
export function runProductStatusCommand(parsed, environment) {
|
|
13
|
+
const extraPositionals = rejectExtraPositionals(parsed, 'status');
|
|
14
|
+
if (extraPositionals !== undefined)
|
|
15
|
+
return extraPositionals;
|
|
16
|
+
const status = buildProductStatusForCli(parsed, environment);
|
|
17
|
+
if (!status.ok)
|
|
18
|
+
return status.value;
|
|
19
|
+
return parsed.flags.json === true ? jsonResult({ ok: true, value: status.value }) : okText(renderProductStatus(status.value));
|
|
20
|
+
}
|
|
21
|
+
export function runProductNextCommand(parsed, environment) {
|
|
22
|
+
const extraPositionals = rejectExtraPositionals(parsed, 'next');
|
|
23
|
+
if (extraPositionals !== undefined)
|
|
24
|
+
return extraPositionals;
|
|
25
|
+
const status = buildProductStatusForCli(parsed, environment);
|
|
26
|
+
if (!status.ok)
|
|
27
|
+
return status.value;
|
|
28
|
+
const next = buildProductNext(status.value);
|
|
29
|
+
return parsed.flags.json === true ? jsonResult({ ok: true, value: next }) : okText(renderProductNext(next));
|
|
30
|
+
}
|
|
31
|
+
export function runProductResumeCommand(parsed, environment) {
|
|
32
|
+
const extraPositionals = rejectExtraPositionals(parsed, 'resume');
|
|
33
|
+
if (extraPositionals !== undefined)
|
|
34
|
+
return extraPositionals;
|
|
35
|
+
const resume = buildProductResumeForCli(parsed, environment);
|
|
36
|
+
if (!resume.ok)
|
|
37
|
+
return resume.value;
|
|
38
|
+
return parsed.flags.json === true ? jsonResult({ ok: true, value: resume.value }) : okText(renderProductResume(resume.value));
|
|
39
|
+
}
|
|
40
|
+
function rejectExtraPositionals(parsed, command) {
|
|
41
|
+
const extra = parsed.positionals.slice(1);
|
|
42
|
+
return extra.length === 0 ? undefined : usageFailure(`${command} does not accept positional arguments: ${extra.join(' ')}`);
|
|
43
|
+
}
|
|
44
|
+
function buildProductStatusForCli(parsed, environment) {
|
|
45
|
+
const projectFlag = parsed.flags.project === undefined ? { ok: true, value: undefined } : requiredFlag(parsed.flags, 'project');
|
|
46
|
+
if (!projectFlag.ok)
|
|
47
|
+
return { ok: false, value: resultFailure(projectFlag) };
|
|
48
|
+
const changeFlag = parsed.flags.change === undefined ? { ok: true, value: undefined } : requiredFlag(parsed.flags, 'change');
|
|
49
|
+
if (!changeFlag.ok)
|
|
50
|
+
return { ok: false, value: resultFailure(changeFlag) };
|
|
51
|
+
const project = projectFlag.value;
|
|
52
|
+
const change = changeFlag.value;
|
|
53
|
+
if (change === undefined) {
|
|
54
|
+
const status = buildProductStatus({ cwd: environment.cwd, ...(project === undefined ? {} : { project }) });
|
|
55
|
+
return { ok: true, value: status };
|
|
56
|
+
}
|
|
57
|
+
const selectedDatabasePath = databasePathFor(parsed.flags, environment);
|
|
58
|
+
if (!selectedDatabasePath.ok)
|
|
59
|
+
return { ok: false, value: resultFailure(selectedDatabasePath) };
|
|
60
|
+
const explicitDatabasePath = optionalStringFlag(parsed.flags, 'db');
|
|
61
|
+
const opened = openMemoryDatabase({ path: selectedDatabasePath.value, readonly: true });
|
|
62
|
+
if (!opened.ok) {
|
|
63
|
+
const status = buildProductStatus({
|
|
64
|
+
cwd: environment.cwd,
|
|
65
|
+
...(project === undefined ? {} : { project }),
|
|
66
|
+
change,
|
|
67
|
+
databasePath: selectedDatabasePath.value,
|
|
68
|
+
databaseError: opened.error.message,
|
|
69
|
+
});
|
|
70
|
+
return { ok: true, value: status };
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const status = buildProductStatus({
|
|
74
|
+
cwd: environment.cwd,
|
|
75
|
+
...(project === undefined ? {} : { project }),
|
|
76
|
+
change,
|
|
77
|
+
databasePath: selectedDatabasePath.value,
|
|
78
|
+
...(explicitDatabasePath === undefined ? {} : { explicitDatabasePath }),
|
|
79
|
+
sdd: new SddWorkflowService(new MemoryService(opened.value)),
|
|
80
|
+
runs: new RunService(opened.value),
|
|
81
|
+
});
|
|
82
|
+
return { ok: true, value: status };
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
opened.value.close();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function buildProductResumeForCli(parsed, environment) {
|
|
89
|
+
const projectFlag = parsed.flags.project === undefined ? { ok: true, value: undefined } : requiredFlag(parsed.flags, 'project');
|
|
90
|
+
if (!projectFlag.ok)
|
|
91
|
+
return { ok: false, value: resultFailure(projectFlag) };
|
|
92
|
+
const runIdFlag = parsed.flags['run-id'] === undefined ? { ok: true, value: undefined } : requiredFlag(parsed.flags, 'run-id');
|
|
93
|
+
if (!runIdFlag.ok)
|
|
94
|
+
return { ok: false, value: resultFailure(runIdFlag) };
|
|
95
|
+
const project = projectFlag.value;
|
|
96
|
+
const runId = runIdFlag.value;
|
|
97
|
+
if (runId === undefined && project === undefined) {
|
|
98
|
+
const resume = buildProductResume({ cwd: environment.cwd, ...(project === undefined ? {} : { project }) });
|
|
99
|
+
return { ok: true, value: resume };
|
|
100
|
+
}
|
|
101
|
+
const selectedDatabasePath = databasePathFor(parsed.flags, environment);
|
|
102
|
+
if (!selectedDatabasePath.ok)
|
|
103
|
+
return { ok: false, value: resultFailure(selectedDatabasePath) };
|
|
104
|
+
const opened = openMemoryDatabase({ path: selectedDatabasePath.value, readonly: true });
|
|
105
|
+
if (!opened.ok) {
|
|
106
|
+
const visibleDatabasePath = runId === undefined && parsed.flags.db === undefined ? undefined : selectedDatabasePath.value;
|
|
107
|
+
const resume = buildProductResume({
|
|
108
|
+
cwd: environment.cwd,
|
|
109
|
+
...(project === undefined ? {} : { project }),
|
|
110
|
+
...(runId === undefined ? {} : { runId }),
|
|
111
|
+
...(visibleDatabasePath === undefined ? {} : { databasePath: visibleDatabasePath }),
|
|
112
|
+
databaseError: opened.error.message,
|
|
113
|
+
});
|
|
114
|
+
return { ok: true, value: resume };
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const flaggedDatabasePath = parsed.flags.db === undefined ? undefined : selectedDatabasePath.value;
|
|
118
|
+
const resume = buildProductResume({
|
|
119
|
+
cwd: environment.cwd,
|
|
120
|
+
...(project === undefined ? {} : { project }),
|
|
121
|
+
...(runId === undefined ? {} : { runId }),
|
|
122
|
+
...(flaggedDatabasePath === undefined ? {} : { databasePath: flaggedDatabasePath }),
|
|
123
|
+
runs: new RunService(opened.value),
|
|
124
|
+
});
|
|
125
|
+
return { ok: true, value: resume };
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
opened.value.close();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AgentRegistryService } from '../../agents/agent-registry-service.js';
|
|
2
|
+
import { canonicalOpenCodeDefaultModel } from '../../agents/canonical-agent-manifest.js';
|
|
2
3
|
import { createNaturalLanguagePlan } from '../../orchestrator/natural-language-planner.js';
|
|
3
4
|
import { RunService } from '../../runs/run-service.js';
|
|
4
|
-
import {
|
|
5
|
+
import { normalizeSddPhaseInput, sddPhases } from '../../sdd/schema.js';
|
|
5
6
|
import { CommandAllowlistAdapter, commandAllowlistIds } from '../../workflows/command-allowlist-adapter.js';
|
|
6
7
|
import { GuardedProviderWorkflowExecutor, operationMetadataForWorkflowExecution, SafeNonDispatchingWorkflowExecutor, workflowExecutorSafety, } from '../../workflows/workflow-executor.js';
|
|
7
8
|
import { getWorkflowDefinition, listWorkflows } from '../../workflows/workflow-registry.js';
|
|
@@ -248,11 +249,16 @@ export function runWorkflowRunCommand(workflow, parsed, database) {
|
|
|
248
249
|
const selected = getWorkflowDefinition(workflow);
|
|
249
250
|
const planner = createNaturalLanguagePlan({ project, intent: intent.value });
|
|
250
251
|
const recommended = getWorkflowDefinition(planner.workflow);
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
const phaseInput = optionalStringFlag(parsed.flags, 'phase') ?? selected.defaultPhase;
|
|
253
|
+
let phase = phaseInput;
|
|
254
|
+
if (selected.id === 'sdd') {
|
|
255
|
+
const canonicalPhase = normalizeSddPhaseInput(phaseInput);
|
|
256
|
+
if (canonicalPhase === undefined)
|
|
257
|
+
return resultFailure(validationFailure(`Unknown SDD phase: ${phaseInput}. Expected one of: ${sddPhases.join(', ')}`));
|
|
258
|
+
phase = canonicalPhase;
|
|
259
|
+
}
|
|
254
260
|
const providerAdapter = optionalStringFlag(parsed.flags, 'provider-adapter') ?? 'opencode';
|
|
255
|
-
const model = optionalStringFlag(parsed.flags, 'model') ??
|
|
261
|
+
const model = optionalStringFlag(parsed.flags, 'model') ?? canonicalOpenCodeDefaultModel;
|
|
256
262
|
const registry = new AgentRegistryService(database);
|
|
257
263
|
const explicitAgentId = optionalStringFlag(parsed.flags, 'agent-id');
|
|
258
264
|
const selectedAgent = resolveWorkflowRunAgent({
|