vgxness 1.9.1 → 1.9.2
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 +8 -3
- package/dist/agents/agent-activation-service.js +13 -4
- package/dist/agents/agent-registry-service.js +8 -2
- package/dist/agents/agent-seed-upgrade-service.js +231 -0
- package/dist/agents/boot-upgrade.js +59 -0
- package/dist/agents/canonical-agent-projection.js +7 -0
- package/dist/agents/manager-profile-overlay-service.js +14 -0
- package/dist/agents/repositories/agent-seed-history.js +128 -0
- package/dist/cli/commands/mcp-dispatcher.js +7 -0
- package/dist/cli/dispatcher.js +2 -0
- 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 +22 -5
- package/dist/mcp/provider-status.js +3 -7
- package/dist/mcp/schema.js +18 -2
- package/dist/mcp/stdio-server.js +2 -0
- package/dist/mcp/validation.js +38 -2
- package/dist/memory/sqlite/migrations/016_agent_seed_history.sql +15 -0
- package/dist/runs/schema.js +4 -0
- package/dist/sdd/schema.js +12 -0
- package/dist/sdd/sdd-workflow-service.js +43 -2
- package/docs/architecture.md +8 -0
- package/docs/cli.md +5 -5
- package/docs/contributing.md +1 -1
- package/docs/glossary.md +1 -1
- package/docs/mcp.md +2 -2
- 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
|
@@ -62,7 +62,7 @@ export async function installClaudeCodeMcpClient(input) {
|
|
|
62
62
|
if (!mcpWrite.ok)
|
|
63
63
|
return refusal('post_write_validation_failed', mcpWrite.error.message, plan, server, writtenPaths, backups);
|
|
64
64
|
writtenPaths.push(mcpWrite.value);
|
|
65
|
-
for (const agent of expectedClaudeCodeRenderedAgents(input.cwd)) {
|
|
65
|
+
for (const agent of expectedClaudeCodeRenderedAgents(input.cwd, { effectiveManagerInstructions: input.effectiveManagerInstructions })) {
|
|
66
66
|
const target = plan.targets.find((item) => item.kind === 'agent-file' && item.path === agent.path);
|
|
67
67
|
if (target?.action !== 'create' && target?.action !== 'update-vgxness')
|
|
68
68
|
continue;
|
|
@@ -140,7 +140,7 @@ async function applyUserInstall(input, plan, server, writtenPaths, backups) {
|
|
|
140
140
|
if (!mcpWrite.ok)
|
|
141
141
|
return refusal('post_write_validation_failed', mcpWrite.error.message, plan, server, writtenPaths, backups);
|
|
142
142
|
writtenPaths.push(mcpWrite.value);
|
|
143
|
-
for (const agent of expectedClaudeCodeRenderedUserAgents(input.cwd, input.env)) {
|
|
143
|
+
for (const agent of expectedClaudeCodeRenderedUserAgents(input.cwd, input.env, { effectiveManagerInstructions: input.effectiveManagerInstructions })) {
|
|
144
144
|
const target = plan.targets.find((item) => item.kind === 'agent-file' && item.path === agent.path);
|
|
145
145
|
if (target?.action !== 'create' && target?.action !== 'update-vgxness')
|
|
146
146
|
continue;
|
|
@@ -32,7 +32,9 @@ export function callVgxTool(call, services) {
|
|
|
32
32
|
case 'vgxness_sdd_save_artifact':
|
|
33
33
|
return auditedEnvelope(validated.tool, services.sdd.saveArtifact(validated.input), services, sddSaveAuditPayload(validated.input));
|
|
34
34
|
case 'vgxness_sdd_accept_artifact':
|
|
35
|
-
return auditedEnvelope(validated.tool, services.sdd.acceptArtifact(
|
|
35
|
+
return auditedEnvelope(validated.tool, services.sdd.acceptArtifact(validated.input), services, sddAcceptanceAuditPayload(validated.input));
|
|
36
|
+
case 'vgxness_sdd_reopen_artifact':
|
|
37
|
+
return auditedEnvelope(validated.tool, services.sdd.reopenArtifact(validated.input), services, sddReopenAuditPayload(validated.input));
|
|
36
38
|
case 'vgxness_sdd_get_artifact':
|
|
37
39
|
return toEnvelope(validated.tool, services.sdd.getArtifact(validated.input));
|
|
38
40
|
case 'vgxness_sdd_list_artifacts':
|
|
@@ -117,10 +119,6 @@ export function callVgxTool(call, services) {
|
|
|
117
119
|
}
|
|
118
120
|
return errorEnvelope('validation_failed', 'Tool dispatch is not implemented');
|
|
119
121
|
}
|
|
120
|
-
function toAcceptArtifactServiceInput(input) {
|
|
121
|
-
const note = input.note ?? input.notes ?? input.rationale;
|
|
122
|
-
return note === undefined ? input : { ...input, note };
|
|
123
|
-
}
|
|
124
122
|
function auditedEnvelope(tool, result, services, audit) {
|
|
125
123
|
if (result.ok && audit.runId !== undefined) {
|
|
126
124
|
services.runs.appendEvent({
|
|
@@ -171,6 +169,24 @@ function sddAcceptanceAuditPayload(input) {
|
|
|
171
169
|
}),
|
|
172
170
|
};
|
|
173
171
|
}
|
|
172
|
+
function sddReopenAuditPayload(input) {
|
|
173
|
+
return {
|
|
174
|
+
runId: input.runId,
|
|
175
|
+
title: 'Audit: sdd-artifact-reopened',
|
|
176
|
+
relatedType: 'sdd-artifact',
|
|
177
|
+
relatedId: `${input.change}:${input.phase}`,
|
|
178
|
+
payload: (value) => ({
|
|
179
|
+
eventType: 'sdd-artifact-reopened',
|
|
180
|
+
project: input.project,
|
|
181
|
+
change: input.change,
|
|
182
|
+
phase: input.phase,
|
|
183
|
+
topicKey: value.topicKey,
|
|
184
|
+
artifactId: value.id,
|
|
185
|
+
reopenedBy: { type: 'human', id: input.reopenedBy.id },
|
|
186
|
+
...(input.agentId === undefined ? {} : { agentId: input.agentId }),
|
|
187
|
+
}),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
174
190
|
function sddSaveAuditPayload(input) {
|
|
175
191
|
return {
|
|
176
192
|
runId: input.runId,
|
|
@@ -237,6 +253,7 @@ export function createVgxMcpControlPlane(options = {}) {
|
|
|
237
253
|
let closed = false;
|
|
238
254
|
return {
|
|
239
255
|
callVgxTool: (tool, input) => callVgxTool({ tool, input }, services),
|
|
256
|
+
database,
|
|
240
257
|
close: () => {
|
|
241
258
|
if (closed)
|
|
242
259
|
return;
|
|
@@ -221,16 +221,12 @@ function claudeProjectMemoryPathStatus(state) {
|
|
|
221
221
|
function compactPaths(paths, mode) {
|
|
222
222
|
if (mode === 'verbose')
|
|
223
223
|
return paths;
|
|
224
|
-
return paths.map((path) => path.status
|
|
225
|
-
? { ...path, detail: `${path.label}: pass` }
|
|
226
|
-
: path.status === 'not-configured'
|
|
227
|
-
? { ...path, detail: `${path.label}: not configured` }
|
|
228
|
-
: path);
|
|
224
|
+
return paths.map((path) => ({ label: path.label, path: path.path, status: path.status }));
|
|
229
225
|
}
|
|
230
226
|
function compactMcpEntry(entry, mode) {
|
|
231
|
-
if (mode === 'verbose'
|
|
227
|
+
if (mode === 'verbose')
|
|
232
228
|
return entry;
|
|
233
|
-
return {
|
|
229
|
+
return { configured: entry.configured, status: entry.status, serverName: entry.serverName };
|
|
234
230
|
}
|
|
235
231
|
function compactSdd(sdd, mode) {
|
|
236
232
|
if (mode === 'verbose')
|
package/dist/mcp/schema.js
CHANGED
|
@@ -9,6 +9,7 @@ export const SUPPORTED_VGX_MCP_TOOL_NAMES = [
|
|
|
9
9
|
'vgxness_sdd_get_readiness',
|
|
10
10
|
'vgxness_sdd_save_artifact',
|
|
11
11
|
'vgxness_sdd_accept_artifact',
|
|
12
|
+
'vgxness_sdd_reopen_artifact',
|
|
12
13
|
'vgxness_sdd_get_artifact',
|
|
13
14
|
'vgxness_sdd_list_artifacts',
|
|
14
15
|
'vgxness_sdd_next',
|
|
@@ -49,6 +50,7 @@ export const EXPOSED_VGX_MCP_TOOL_NAMES = [
|
|
|
49
50
|
'sdd_get_readiness',
|
|
50
51
|
'sdd_save_artifact',
|
|
51
52
|
'sdd_accept_artifact',
|
|
53
|
+
'sdd_reopen_artifact',
|
|
52
54
|
'sdd_get_artifact',
|
|
53
55
|
'sdd_list_artifacts',
|
|
54
56
|
'sdd_next',
|
|
@@ -148,8 +150,22 @@ export const VGX_MCP_TOOL_INPUT_SCHEMAS = {
|
|
|
148
150
|
}),
|
|
149
151
|
acceptedAt: z.string().min(1).optional(),
|
|
150
152
|
note: z.string().min(1).optional(),
|
|
151
|
-
|
|
152
|
-
|
|
153
|
+
runId: z.string().min(1).optional(),
|
|
154
|
+
agentId: z.string().min(1).optional(),
|
|
155
|
+
})
|
|
156
|
+
.passthrough(),
|
|
157
|
+
vgxness_sdd_reopen_artifact: z
|
|
158
|
+
.object({
|
|
159
|
+
project: z.string().min(1),
|
|
160
|
+
change: z.string().min(1),
|
|
161
|
+
phase: z.enum(sddPhases),
|
|
162
|
+
reopenedBy: z.object({
|
|
163
|
+
type: z.literal('human'),
|
|
164
|
+
id: z.string().min(1),
|
|
165
|
+
displayName: z.string().min(1).optional(),
|
|
166
|
+
}),
|
|
167
|
+
reopenedAt: z.string().min(1).optional(),
|
|
168
|
+
note: z.string().min(1).optional(),
|
|
153
169
|
runId: z.string().min(1).optional(),
|
|
154
170
|
agentId: z.string().min(1).optional(),
|
|
155
171
|
})
|
package/dist/mcp/stdio-server.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { runBootAgentSeedUpgrade } from '../agents/boot-upgrade.js';
|
|
3
4
|
import { createVgxMcpControlPlane } from './control-plane.js';
|
|
4
5
|
import { EXPOSED_VGX_MCP_TOOL_NAMES, toInternalVgxMcpToolName, VGX_MCP_TOOL_INPUT_SCHEMAS, } from './schema.js';
|
|
5
6
|
export async function startVgxMcpStdioServer(options = {}) {
|
|
6
7
|
const controlPlane = createVgxMcpControlPlane(options.databasePath === undefined ? {} : { databasePath: options.databasePath });
|
|
8
|
+
runBootAgentSeedUpgrade(controlPlane.database);
|
|
7
9
|
const mcpServer = new McpServer({ name: 'vgxness', version: '0.1.0' });
|
|
8
10
|
const transport = new StdioServerTransport();
|
|
9
11
|
let closed = false;
|
package/dist/mcp/validation.js
CHANGED
|
@@ -42,6 +42,8 @@ export function validateVgxMcpToolCall(call) {
|
|
|
42
42
|
return validationSuccess(tool.value, validateSddSaveArtifactInput(input, tool.value));
|
|
43
43
|
case 'vgxness_sdd_accept_artifact':
|
|
44
44
|
return validationSuccess(tool.value, validateSddAcceptArtifactInput(input, tool.value));
|
|
45
|
+
case 'vgxness_sdd_reopen_artifact':
|
|
46
|
+
return validationSuccess(tool.value, validateSddReopenArtifactInput(input, tool.value));
|
|
45
47
|
case 'vgxness_sdd_get_artifact':
|
|
46
48
|
return validationSuccess(tool.value, validateSddGetArtifactInput(input, tool.value));
|
|
47
49
|
case 'vgxness_sdd_list_artifacts':
|
|
@@ -312,7 +314,7 @@ function validateSddSaveArtifactInput(input, tool) {
|
|
|
312
314
|
return { ok: true, value: { ...base.value, phase: phase.value, content: content.value } };
|
|
313
315
|
}
|
|
314
316
|
function validateSddAcceptArtifactInput(input, tool) {
|
|
315
|
-
const record = inputRecord(input, tool, ['project', 'change', 'phase', 'acceptedBy', 'acceptedAt', 'note', '
|
|
317
|
+
const record = inputRecord(input, tool, ['project', 'change', 'phase', 'acceptedBy', 'acceptedAt', 'note', 'runId', 'agentId']);
|
|
316
318
|
if (!record.ok)
|
|
317
319
|
return record;
|
|
318
320
|
const base = readProjectAndChange(record.value, tool);
|
|
@@ -340,7 +342,41 @@ function validateSddAcceptArtifactInput(input, tool) {
|
|
|
340
342
|
if (displayName.value !== undefined)
|
|
341
343
|
acceptedBy.displayName = displayName.value;
|
|
342
344
|
const result = { ...base.value, phase: phase.value, acceptedBy };
|
|
343
|
-
const copied = copyOptionalLimitedStrings(result, record.value, tool, ['acceptedAt', 'note', '
|
|
345
|
+
const copied = copyOptionalLimitedStrings(result, record.value, tool, ['acceptedAt', 'note', 'runId', 'agentId'], undefined);
|
|
346
|
+
if (!copied.ok)
|
|
347
|
+
return copied;
|
|
348
|
+
return { ok: true, value: result };
|
|
349
|
+
}
|
|
350
|
+
function validateSddReopenArtifactInput(input, tool) {
|
|
351
|
+
const record = inputRecord(input, tool, ['project', 'change', 'phase', 'reopenedBy', 'reopenedAt', 'note', 'runId', 'agentId']);
|
|
352
|
+
if (!record.ok)
|
|
353
|
+
return record;
|
|
354
|
+
const base = readProjectAndChange(record.value, tool);
|
|
355
|
+
if (!base.ok)
|
|
356
|
+
return base;
|
|
357
|
+
const phase = readPhase(record.value, tool);
|
|
358
|
+
if (!phase.ok)
|
|
359
|
+
return phase;
|
|
360
|
+
const reopenedByRecord = asRecord(record.value.reopenedBy, tool, 'reopenedBy is required');
|
|
361
|
+
if (!reopenedByRecord.ok)
|
|
362
|
+
return reopenedByRecord;
|
|
363
|
+
const reopenedByExtra = Object.keys(reopenedByRecord.value).find((key) => !['type', 'id', 'displayName'].includes(key));
|
|
364
|
+
if (reopenedByExtra !== undefined)
|
|
365
|
+
return validationFailure(`Unexpected field: reopenedBy.${reopenedByExtra}`, tool);
|
|
366
|
+
const type = readRequiredOneOf(reopenedByRecord.value, 'type', ['human'], tool);
|
|
367
|
+
if (!type.ok)
|
|
368
|
+
return type;
|
|
369
|
+
const id = readNonEmptyString(reopenedByRecord.value, 'id', tool);
|
|
370
|
+
if (!id.ok)
|
|
371
|
+
return id;
|
|
372
|
+
const displayName = readOptionalNonEmptyString(reopenedByRecord.value, 'displayName', tool);
|
|
373
|
+
if (!displayName.ok)
|
|
374
|
+
return displayName;
|
|
375
|
+
const reopenedBy = { type: type.value, id: id.value };
|
|
376
|
+
if (displayName.value !== undefined)
|
|
377
|
+
reopenedBy.displayName = displayName.value;
|
|
378
|
+
const result = { ...base.value, phase: phase.value, reopenedBy };
|
|
379
|
+
const copied = copyOptionalLimitedStrings(result, record.value, tool, ['reopenedAt', 'note', 'runId', 'agentId'], undefined);
|
|
344
380
|
if (!copied.ok)
|
|
345
381
|
return copied;
|
|
346
382
|
return { ok: true, value: result };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
CREATE TABLE agent_seed_history (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
applied_at TEXT NOT NULL,
|
|
4
|
+
from_version INTEGER,
|
|
5
|
+
to_version INTEGER NOT NULL,
|
|
6
|
+
agent_name TEXT NOT NULL,
|
|
7
|
+
project TEXT NOT NULL,
|
|
8
|
+
scope TEXT NOT NULL,
|
|
9
|
+
outcome TEXT NOT NULL,
|
|
10
|
+
reason TEXT,
|
|
11
|
+
source TEXT NOT NULL
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE INDEX idx_agent_seed_history_applied_at ON agent_seed_history(applied_at);
|
|
15
|
+
CREATE INDEX idx_agent_seed_history_project_scope_name ON agent_seed_history(project, scope, agent_name);
|
package/dist/runs/schema.js
CHANGED
package/dist/sdd/schema.js
CHANGED
|
@@ -30,10 +30,22 @@ export const SddArtifactAcceptanceRecordSchema = z
|
|
|
30
30
|
note: z.string().optional(),
|
|
31
31
|
})
|
|
32
32
|
.strict();
|
|
33
|
+
export const SddArtifactReopenRecordSchema = z
|
|
34
|
+
.object({
|
|
35
|
+
actor: z.object({
|
|
36
|
+
type: z.literal('human'),
|
|
37
|
+
id: z.string().min(1),
|
|
38
|
+
displayName: z.string().min(1).optional(),
|
|
39
|
+
}),
|
|
40
|
+
reopenedAt: z.string().min(1),
|
|
41
|
+
note: z.string().optional(),
|
|
42
|
+
})
|
|
43
|
+
.strict();
|
|
33
44
|
export const SddArtifactMetadataSchema = z
|
|
34
45
|
.object({
|
|
35
46
|
status: SddArtifactStatusSchema,
|
|
36
47
|
acceptance: SddArtifactAcceptanceRecordSchema.optional(),
|
|
48
|
+
reopen: SddArtifactReopenRecordSchema.optional(),
|
|
37
49
|
supersededByTopicKey: z.string().min(1).optional(),
|
|
38
50
|
updatedAt: z.string().min(1).optional(),
|
|
39
51
|
})
|
|
@@ -175,7 +175,7 @@ export class SddWorkflowService {
|
|
|
175
175
|
if (status === 'accepted')
|
|
176
176
|
return validationFailure('Cannot overwrite an accepted SDD artifact; supersede it under a new topic key.');
|
|
177
177
|
if (status === 'rejected')
|
|
178
|
-
return validationFailure('Rejected SDD artifact must be re-opened
|
|
178
|
+
return validationFailure('Rejected SDD artifact must be re-opened via SddWorkflowService.reopenArtifact before saving.');
|
|
179
179
|
if (status === 'superseded')
|
|
180
180
|
return validationFailure('Cannot overwrite a superseded SDD artifact.');
|
|
181
181
|
}
|
|
@@ -198,7 +198,7 @@ export class SddWorkflowService {
|
|
|
198
198
|
const existingEnvelope = normalizeSddArtifact(existing.value);
|
|
199
199
|
const existingStatus = existingEnvelope.metadata.status;
|
|
200
200
|
if (existingStatus === 'rejected')
|
|
201
|
-
return validationFailure('Rejected SDD artifact must be re-opened
|
|
201
|
+
return validationFailure('Rejected SDD artifact must be re-opened via SddWorkflowService.reopenArtifact before accepting.');
|
|
202
202
|
if (existingStatus === 'superseded')
|
|
203
203
|
return validationFailure('Cannot accept a superseded SDD artifact; create a new artifact under a different topic key instead.');
|
|
204
204
|
const acceptance = {
|
|
@@ -223,6 +223,47 @@ export class SddWorkflowService {
|
|
|
223
223
|
},
|
|
224
224
|
}, this.context);
|
|
225
225
|
}
|
|
226
|
+
reopenArtifact(input) {
|
|
227
|
+
const validated = this.validatePhaseInput(input);
|
|
228
|
+
if (!validated.ok)
|
|
229
|
+
return validated;
|
|
230
|
+
if (input.reopenedBy === undefined)
|
|
231
|
+
return validationFailure('SDD artifact reopen requires an explicit human actor');
|
|
232
|
+
if (input.reopenedBy.type !== 'human')
|
|
233
|
+
return validationFailure('SDD artifact reopen must be performed by a human actor');
|
|
234
|
+
if (input.reopenedBy.id === undefined || input.reopenedBy.id.trim().length === 0)
|
|
235
|
+
return validationFailure('SDD artifact reopen human actor id must not be empty');
|
|
236
|
+
const topicKey = sddTopicKey(validated.value.change, validated.value.phase);
|
|
237
|
+
const existing = this.memory.getArtifact(validated.value.project, topicKey, this.context);
|
|
238
|
+
if (!existing.ok)
|
|
239
|
+
return existing;
|
|
240
|
+
const existingEnvelope = normalizeSddArtifact(existing.value);
|
|
241
|
+
const existingStatus = existingEnvelope.metadata.status;
|
|
242
|
+
if (existingStatus !== 'rejected')
|
|
243
|
+
return validationFailure(`SDD artifact reopen is only valid for rejected artifacts (current status: ${existingStatus}).`);
|
|
244
|
+
const reopenedAt = input.reopenedAt ?? new Date().toISOString();
|
|
245
|
+
const reopenRecord = {
|
|
246
|
+
actor: {
|
|
247
|
+
type: 'human',
|
|
248
|
+
id: input.reopenedBy.id,
|
|
249
|
+
...(input.reopenedBy.displayName === undefined ? {} : { displayName: input.reopenedBy.displayName }),
|
|
250
|
+
},
|
|
251
|
+
reopenedAt,
|
|
252
|
+
...(input.note === undefined ? {} : { note: input.note }),
|
|
253
|
+
};
|
|
254
|
+
return this.memory.saveArtifact({
|
|
255
|
+
project: existing.value.project,
|
|
256
|
+
topicKey: existing.value.topicKey,
|
|
257
|
+
phase: existing.value.phase,
|
|
258
|
+
content: existing.value.content,
|
|
259
|
+
metadata: {
|
|
260
|
+
...existingEnvelope.metadata,
|
|
261
|
+
status: 'draft',
|
|
262
|
+
reopen: reopenRecord,
|
|
263
|
+
updatedAt: reopenedAt,
|
|
264
|
+
},
|
|
265
|
+
}, this.context);
|
|
266
|
+
}
|
|
226
267
|
getArtifact(input) {
|
|
227
268
|
const validated = this.validatePhaseInput(input);
|
|
228
269
|
if (!validated.ok)
|
package/docs/architecture.md
CHANGED
|
@@ -91,6 +91,14 @@ Gentle-AI/`gentle-pi` are strong references for the configurator and agent-behav
|
|
|
91
91
|
| `Adapter` | Translator between the neutral `vgxness` model and a provider-specific config/runtime. |
|
|
92
92
|
| `PermissionPolicy` | Rules defining what an agent may do, what requires approval, and what must be denied. |
|
|
93
93
|
|
|
94
|
+
### Agent registry self-healing
|
|
95
|
+
|
|
96
|
+
The canonical agent manifest in `src/agents/canonical-agent-manifest.ts` is the source of truth for built-in agents (1 manager + 10 SDD subagents). At every CLI/MCP boot, `src/agents/boot-upgrade.ts` reconciles the live `agents` table with that manifest via `src/agents/agent-seed-upgrade-service.ts`: missing rows are created, drifted rows (changed `vgxnessPromptContractVersion`, instructions, adapters, or description) are overwritten, and matches are recorded as noop. Each non-noop outcome is appended to the `agent_seed_history` table for audit. Operators can opt out with `VGXNESS_SKIP_AGENT_SEED_AUTO_UPGRADE=1`. This eliminates the long-standing drift between the canonical prompt contract and stored agent rows after a version bump.
|
|
97
|
+
|
|
98
|
+
### Manager overlay parity across providers
|
|
99
|
+
|
|
100
|
+
A user-saved `manager_profile_overlay` flows to both providers symmetrically. OpenCode consults the overlay inside `OpenCodeManagerPayloadService.applyManagerOverlayWhenAvailable` (`src/providers/opencode/manager-payload.ts:152-156`), which calls `ManagerProfileOverlayService.resolveEffectiveManager` before producing the OpenCode manager payload. Claude Code was previously canonical-only; the fix routes the overlay through `withEffectiveManagerInstructions` (`src/agents/canonical-agent-projection.ts`) into the render path (`expectedClaudeCodeRenderedAgents` / `expectedClaudeCodeRenderedUserAgents`), with the caller (`mcp install claude` in `src/cli/commands/mcp-dispatcher.ts`) computing the effective instructions via `computeEffectiveManagerInstructions(database)` and passing them into `installClaudeCodeMcpClient`. As a result, `vgxness mcp install claude` writes the user's customized instructions into `.claude/agents/vgxness-manager.md` instead of silently falling back to canonical.
|
|
101
|
+
|
|
94
102
|
## Storage model
|
|
95
103
|
|
|
96
104
|
`vgxness` should keep local storage split by scope.
|
package/docs/cli.md
CHANGED
|
@@ -24,7 +24,7 @@ vgx --help
|
|
|
24
24
|
vgxness mcp start --db <temp-memory.sqlite> # then call verification_plan with { changeType: 'mcp' }
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
`vgxness setup plan` and `vgxness setup status` are human-readable and
|
|
27
|
+
`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 the selected SQLite store is needed. Pass `--json` when you need parseable automation output. The MCP plan does not write provider config. Installed-package setup plans should use `vgxness mcp start` and must not mention `npm run cli`, `tsx`, or repository-relative source paths.
|
|
28
28
|
|
|
29
29
|
Only apply the OpenCode user/global config after reviewing the plan (use `--scope project` only when you intentionally want project config):
|
|
30
30
|
|
|
@@ -63,7 +63,7 @@ vgxness sdd next --project <project> --change <change>
|
|
|
63
63
|
vgxness setup rollback --backup <path>
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
`setup plan`, `setup status`, and non-TTY `init` planning
|
|
66
|
+
`setup plan`, `setup status`, and non-TTY `init` planning do not write provider config. Local VGXNESS store initialization may occur when the selected SQLite store is needed. They are human-readable by default; pass `--json` when you need parseable automation output. With the default global database, the OpenCode MCP command is `vgxness mcp start`; for custom/project-local DBs it includes `--db <path>`. The default OpenCode target is `$HOME/.config/opencode/opencode.json`; pass `--scope project` to opt into `<workspace>/.opencode/opencode.json`. `setup apply --yes` is the explicit OpenCode provider-config write path. `setup rollback --backup <path>` validates a VGXNESS/OpenCode backup such as `opencode.json.backup-<timestamp>`, creates a pre-rollback backup of the current target when present, restores the selected backup byte-for-byte, and recommends `vgxness doctor`.
|
|
67
67
|
|
|
68
68
|
`vgxness init` prompts in English when stdin/stdout are TTYs: project name, DB location, provider, OpenCode scope, install mode, then shows the plan and asks `Apply this setup? Type "yes" to continue:`. Any answer other than `yes` exits successfully without writes. In CI/non-TTY without `--yes`, `init` returns the read-only plan and never waits for input. `vgxness doctor`, `vgxness sdd status`, `vgxness sdd next`, `vgxness sdd get-artifact`, and `vgxness sdd list-artifacts` are also human-readable by default; use `--json` for scripts.
|
|
69
69
|
|
|
@@ -112,7 +112,7 @@ Release-candidate checklist, without publishing:
|
|
|
112
112
|
|
|
113
113
|
1. `bun install --frozen-lockfile` completes on a clean checkout.
|
|
114
114
|
2. `bun run check:bun-lock` passes.
|
|
115
|
-
3. `bun run verify:typecheck`, `bun run verify:test`, and `bun run verify:bun-sqlite` pass.
|
|
115
|
+
3. `bun run verify:typecheck`, `bun run verify:test`, `bun run verify:test:bun-storage`, and `bun run verify:bun-sqlite` pass.
|
|
116
116
|
4. `bun run package:bun:evidence -- --require-pass` passes on supported CI OSes.
|
|
117
117
|
5. Uploaded JSON shows `status: pass`, artifact/install smoke pass, no retired scripts, no `package-lock.json`, `publicationAttempted: false`, and `releaseReadiness.status: pass`.
|
|
118
118
|
6. Version, release notes, proprietary license boundary, and rollback criteria are reviewed.
|
|
@@ -312,7 +312,7 @@ bun run cli:bun -- <workflow> run --project <name> --intent <text> [--phase <nam
|
|
|
312
312
|
bun run cli:bun -- <workflow> execute --run-id <id> --confirm [--override-escalation] [--workspace <path>] [--db <path>] [--executor safe-non-dispatching|provider|command]
|
|
313
313
|
```
|
|
314
314
|
|
|
315
|
-
`preview` is read-only: it returns the workflow registry plus optional planner output, does not open or write the database, does not create runs, does not call providers, does not edit files, and does not write provider config. Use it to choose between `quickfix`, `debug`, `sdd`, or another workflow before recording state.
|
|
315
|
+
`preview` is read-only: it returns the workflow registry plus optional planner output, does not open or write the database, does not create runs, does not call providers, does not edit files, and does not write provider config. Use it to choose between `quickfix`, `debug`, `sdd`, or another workflow before recording state. Other status/plan surfaces may open or initialize the selected VGXNESS SQLite store; that local store state is separate from provider config.
|
|
316
316
|
|
|
317
317
|
`run` records the selected workflow intent and a `workflow-run-planned` checkpoint in the local SQLite store. It selects or validates an agent, stores the run id, and reports any planner recommendation such as SDD escalation. It does not dispatch providers, edit files, write provider config, create subagents, or mutate SDD artifacts.
|
|
318
318
|
|
|
@@ -437,7 +437,7 @@ A rejected approval is recorded in the run audit trail and prevents the matching
|
|
|
437
437
|
|
|
438
438
|
## MCP setup preview and doctor
|
|
439
439
|
|
|
440
|
-
Use this flow to manually verify MCP readiness after implementation. Setup preview
|
|
440
|
+
Use this flow to manually verify MCP readiness after implementation. Setup preview does **not** install anything, create `.opencode/` or `.claude/`, or write provider/user/global config. Local VGXNESS store initialization may occur when a command needs the selected SQLite store.
|
|
441
441
|
|
|
442
442
|
```bash
|
|
443
443
|
bun run cli:bun -- mcp setup --preview --provider opencode --db <path>
|
package/docs/contributing.md
CHANGED
|
@@ -69,7 +69,7 @@ The configurator/setup plane (rendering/installing provider config) is separate
|
|
|
69
69
|
|
|
70
70
|
These rules are non-negotiable. The harness is loaded with capability; do not remove these guards.
|
|
71
71
|
|
|
72
|
-
- Read-only/preview commands must
|
|
72
|
+
- Read-only/preview commands must not mutate provider config or external tool state. Setup plans, MCP setup previews, OpenCode previews, workflow previews, and status views must not write provider config or call providers. Local VGXNESS store initialization may occur when a command needs the selected SQLite store.
|
|
73
73
|
- Provider config writes require explicit consent (`--yes` or equivalent confirmed flow) plus backup/rollback behavior.
|
|
74
74
|
- Do not create or write `openspec/`. SDD artifacts are stored through the local SQLite artifact service under canonical topic keys `sdd/{change}/{phase}`.
|
|
75
75
|
- Human acceptance is distinct from artifact presence. Do not infer acceptance from generated content or saved drafts. The runtime rejects `acceptedBy.type !== 'human'`.
|
package/docs/glossary.md
CHANGED
|
@@ -64,7 +64,7 @@ A permission resolution: `allow`, `ask`, or `deny`. For SDD-phase gating the mat
|
|
|
64
64
|
|
|
65
65
|
## Dry-run
|
|
66
66
|
|
|
67
|
-
A read-only preview. Setup plans, MCP setup previews, OpenCode previews, workflow previews, and status views are dry-runs by contract
|
|
67
|
+
A read-only preview. Setup plans, MCP setup previews, OpenCode previews, workflow previews, and status views are dry-runs by contract for provider config and external tools: they must not write provider config or call providers. Local VGXNESS store initialization may occur when a command needs the selected SQLite store.
|
|
68
68
|
|
|
69
69
|
## Eval target
|
|
70
70
|
|
package/docs/mcp.md
CHANGED
|
@@ -20,7 +20,7 @@ All tools:
|
|
|
20
20
|
| `vgxness_sdd_ready` | Check whether a specific phase is ready. | `project`, `change`, `phase`; optional `runId`, `agentId` | Returns structured `SddReadiness` with `blockedPrerequisites`. |
|
|
21
21
|
| `vgxness_sdd_get_readiness` | Same as `ready` with explicit output shape. | same as `ready` | |
|
|
22
22
|
| `vgxness_sdd_save_artifact` | Persist phase content under canonical topic key `sdd/{change}/{phase}`. | `project`, `change`, `phase`, `content` | Saving does not imply acceptance. |
|
|
23
|
-
| `vgxness_sdd_accept_artifact` | Record explicit human acceptance for a phase. | `project`, `change`, `phase`, `acceptedBy` (`{type:"human", id, displayName?}`); optional `acceptedAt`, `note`, `
|
|
23
|
+
| `vgxness_sdd_accept_artifact` | Record explicit human acceptance for a phase. | `project`, `change`, `phase`, `acceptedBy` (`{type:"human", id, displayName?}`); optional `acceptedAt`, `note`, `runId`, `agentId` | `acceptedBy.type` must be `"human"`. Runtime rejects agent or anonymous acceptance. Only `note` is accepted; `notes` and `rationale` are rejected as unexpected fields. |
|
|
24
24
|
| `vgxness_sdd_get_artifact` | Read one full artifact. | `project`, `change`, `phase`; optional `payloadMode` (`compact`/`verbose`) | |
|
|
25
25
|
| `vgxness_sdd_list_artifacts` | List all artifacts for a change in canonical phase order. | `project`, `change`; optional `payloadMode` | |
|
|
26
26
|
| `vgxness_sdd_cockpit` | Aggregate per-phase status, blockers, and recommended next action. | `project`, `change` | Returns `SddCockpit` with `aggregateBlockers` of kinds `missing-topic-key`, `unaccepted-phase`, `legacy-artifact`, `readiness`. |
|
|
@@ -117,7 +117,7 @@ Recording a phase with explicit human acceptance:
|
|
|
117
117
|
```text
|
|
118
118
|
vgxness_sdd_save_artifact { project, change, phase: "proposal", content: "..." }
|
|
119
119
|
# human opens the harness and runs:
|
|
120
|
-
vgxness_sdd_accept_artifact { project, change, phase: "proposal", acceptedBy: { type: "human", id: "uziel" },
|
|
120
|
+
vgxness_sdd_accept_artifact { project, change, phase: "proposal", acceptedBy: { type: "human", id: "uziel" }, note: "Reviewed proposal." }
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
Running a planned operation:
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Auditoría de salud del proyecto VGXNESS v1.9.1
|
|
2
|
+
|
|
3
|
+
## Resumen v1.9.1
|
|
4
|
+
|
|
5
|
+
VGXNESS v1.9.1 fue validado exitosamente como CLI/MCP control plane local-first, con runtime instalado basado en Bun, almacenamiento SQLite local y gobernanza SDD con aceptación humana explícita. Esta auditoría es la fuente canónica para la evidencia v1.9.1; si los conteos o comandos cambian, actualiza este documento en vez de duplicar la matriz en otros docs.
|
|
6
|
+
|
|
7
|
+
## Evidencia oficial validada
|
|
8
|
+
|
|
9
|
+
- VGXNESS v1.9.1 validado exitosamente.
|
|
10
|
+
- MCP expone 38 tools tipadas.
|
|
11
|
+
- Inventario de tests: 106 test files.
|
|
12
|
+
- Validación oficial aprobada:
|
|
13
|
+
- `bun run verify:typecheck`
|
|
14
|
+
- `bun run verify:test` con 437 pass, 0 fail
|
|
15
|
+
- `bun run verify:test:bun-storage`
|
|
16
|
+
- `bun run verify:bun-sqlite`
|
|
17
|
+
- `bun run package:bun:evidence` con `releaseReadiness: pass`
|
|
18
|
+
|
|
19
|
+
## Matriz de validación
|
|
20
|
+
|
|
21
|
+
| Superficie | Evidencia v1.9.1 | Taxonomía | Resultado esperado |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| Typecheck | `bun run verify:typecheck` | `test-run` | TypeScript estricto compila sin errores. |
|
|
24
|
+
| Node tests | `bun run verify:test` | `test-run` | Suite Node pasa; evidencia validada: 437 pass, 0 fail. |
|
|
25
|
+
| Bun storage tests | `bun run verify:test:bun-storage` | `test-run/local-store` | Tests storage-backed pasan vía runner oficial bajo Bun. |
|
|
26
|
+
| Bun SQLite probe | `bun run verify:bun-sqlite` | `test-run/local-store` | `bun:sqlite` aplica migraciones en DB temporal y valida integridad. |
|
|
27
|
+
| Package evidence | `bun run package:bun:evidence` | `package evidence` | Evidencia de paquete sin publicar; `releaseReadiness: pass`. |
|
|
28
|
+
| MCP schema/tools | `docs/mcp.md` + `SUPPORTED_VGX_MCP_TOOL_NAMES` | `governance/read model` | 38 tools documentadas; schema y tabla deben mantenerse sincronizados. |
|
|
29
|
+
| Test inventory | Inventario v1.9.1 | `test-run` | 106 test files como evidencia versionada. |
|
|
30
|
+
| Setup/provider status | `setup plan/status`, provider status/doctor/change-plan | `read-only/no provider writes` | No escriben provider config; pueden leer o inicializar el store local de VGXNESS si hace falta. |
|
|
31
|
+
| Provider previews | MCP setup preview, OpenCode preview, agent render | `read-only/provider-preview` | Preview sin ejecutar proveedores ni escribir `.opencode/`, `.claude/` o config global. |
|
|
32
|
+
| SDD workflow | `sdd status/ready/get/list/next/save/accept` | `governance/read model` | Artefactos en SQLite bajo `sdd/{change}/{phase}`; aceptación humana explícita. |
|
|
33
|
+
| Runs/preflight | `run_start`, `run_preflight`, resume inspect/gate | `guarded apply` | Operaciones riesgosas pasan por preflight/approval antes de ejecución. |
|
|
34
|
+
| Memory/session local state | Memory, sessions, cockpit | `local-store possible` | Estado durable vive en SQLite local; no implica provider config writes. |
|
|
35
|
+
| Workflow executor | Workflow preview/run/execute + allowlist | `requires explicit consent` | Preview no muta; ejecución requiere confirmación y comandos allowlisted. |
|
|
36
|
+
| Package runtime Bun | Bins `vgxness`/`vgx` y MCP instalado | `package evidence` | Runtime instalado usa wrapper Bun y evidencia de paquete sin publicación. |
|
|
37
|
+
|
|
38
|
+
## Taxonomía de seguridad
|
|
39
|
+
|
|
40
|
+
- `docs-only`: documentación sin cambios de runtime.
|
|
41
|
+
- `test-run`: verificación local o CI que puede consumir CPU/IO pero no cambia el contrato de producto.
|
|
42
|
+
- `test-run/local-store`: tests/probes que crean o usan storage local temporal.
|
|
43
|
+
- `package evidence`: inspección de artefacto/install smoke sin publicar.
|
|
44
|
+
- `read-only/no provider writes`: no escribe configuración de proveedor, aunque puede abrir o preparar estado local de VGXNESS.
|
|
45
|
+
- `read-only/provider-preview`: produce planes o previews sin instalar hooks, ejecutar proveedores ni escribir provider config.
|
|
46
|
+
- `local-store possible`: puede leer/escribir SQLite local de VGXNESS por diseño del comando.
|
|
47
|
+
- `governance/read model`: estado SDD/runs/memory consultable, con aceptación humana separada de la presencia del artefacto.
|
|
48
|
+
- `guarded apply`: operación mutante detrás de preflight, approval y auditoría.
|
|
49
|
+
- `requires explicit consent`: requiere `--yes`, confirmación equivalente o aprobación humana registrada.
|
|
50
|
+
- `future/not implemented`: documentado como trabajo futuro, no como alcance actual.
|
|
51
|
+
|
|
52
|
+
## Read-only, provider config y local store
|
|
53
|
+
|
|
54
|
+
En esta auditoría, “read-only” debe leerse con precisión operacional: una superficie puede ser read-only respecto de proveedor y workspace, pero aun así abrir, leer o preparar el store local de VGXNESS. La regla canónica es:
|
|
55
|
+
|
|
56
|
+
> No provider config writes; local VGXNESS store initialization may occur.
|
|
57
|
+
|
|
58
|
+
Esto distingue tres planos:
|
|
59
|
+
|
|
60
|
+
1. **Provider config**: `.opencode/`, `opencode.json`, `.claude/`, `.mcp.json`, `CLAUDE.md` y archivos equivalentes. Escribirlos requiere consentimiento explícito y backup/rollback cuando aplique.
|
|
61
|
+
2. **Local VGXNESS store**: SQLite local para memoria, sesiones, runs, SDD artifacts, agentes, skills y perfiles. Algunos comandos pueden abrir o inicializar este store.
|
|
62
|
+
3. **Workspace/source**: archivos del repo y artefactos de código. Este cambio es docs-only y no cambia runtime, permisos, approvals, provider setup ni packaging.
|
|
63
|
+
|
|
64
|
+
## Comandos oficiales de validación
|
|
65
|
+
|
|
66
|
+
Validación oficial completa para v1.9.1:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
bun run verify:typecheck
|
|
70
|
+
bun run verify:test
|
|
71
|
+
bun run verify:test:bun-storage
|
|
72
|
+
bun run verify:bun-sqlite
|
|
73
|
+
bun run package:bun:evidence
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Para release-readiness, el package evidence debe requerir pase explícito:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bun run package:bun:evidence -- --require-pass
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Notas sobre tests storage-backed
|
|
83
|
+
|
|
84
|
+
Los tests storage-backed no deben documentarse como invocaciones genéricas directas de `node --test`. Usa los runners oficiales porque preparan el runtime correcto, paths temporales y expectativas de Bun/SQLite:
|
|
85
|
+
|
|
86
|
+
- `bun run verify:test:bun-storage` para tests storage-backed bajo Bun.
|
|
87
|
+
- `bun run verify:bun-sqlite` para el probe SQLite real con `bun:sqlite`.
|
|
88
|
+
|
|
89
|
+
Node.js sigue siendo tooling de desarrollo/build/test para TypeScript, `node:test` y scripts auxiliares, pero el storage runtime soportado es Bun.
|
|
90
|
+
|
|
91
|
+
## Riesgos y mitigaciones
|
|
92
|
+
|
|
93
|
+
| Riesgo | Mitigación |
|
|
94
|
+
|---|---|
|
|
95
|
+
| Duplicar la matriz en README u otros docs y crear drift. | Mantener este archivo como fuente canónica; README solo resume y enlaza. |
|
|
96
|
+
| Prometer “no mutation” absoluta donde puede inicializarse SQLite local. | Usar wording preciso: no provider config writes; local VGXNESS store initialization may occur. |
|
|
97
|
+
| Confundir package evidence con publicación. | Package evidence no publica; publishing requiere proceso humano explícito separado. |
|
|
98
|
+
| Tratar aceptación SDD como presencia de artifact. | Mantener aceptación humana explícita como requisito independiente. |
|
|
99
|
+
| Ejecutar storage tests con runner incorrecto. | Documentar runners oficiales Bun para storage-backed tests. |
|
|
100
|
+
| Expandir esta auditoría hacia refactors P1/P2. | Mantener P1/P2 bajo future work solamente. |
|
|
101
|
+
|
|
102
|
+
## Fuera de alcance
|
|
103
|
+
|
|
104
|
+
- Cambios de runtime, approvals, preflight, permisos, SDD acceptance o provider setup.
|
|
105
|
+
- Cambios de package metadata, scripts, packaging o publicación.
|
|
106
|
+
- Escritura de provider config o creación de `.opencode/`, `.claude/` u `openspec/`.
|
|
107
|
+
- Refactors de MCP control-plane, SDD workflow, runs, storage o CLI.
|
|
108
|
+
- Nuevos comandos de health audit o nuevos MCP tools.
|
|
109
|
+
|
|
110
|
+
## Future work P1/P2
|
|
111
|
+
|
|
112
|
+
Estos puntos son notas futuras (`future/not implemented`), no alcance de v1.9.1:
|
|
113
|
+
|
|
114
|
+
- Modularizar MCP control-plane.
|
|
115
|
+
- Separar SDD projections/read models.
|
|
116
|
+
- Unificar lenguaje de guarded apply/Claude.
|
|
117
|
+
- Crear un comando/reporte integrado de health audit.
|
|
118
|
+
|
|
119
|
+
## Cómo actualizar esta auditoría
|
|
120
|
+
|
|
121
|
+
1. Revalidar los comandos oficiales y registrar conteos nuevos solo si fueron medidos.
|
|
122
|
+
2. Si cambia el número de MCP tools, actualizar `SUPPORTED_VGX_MCP_TOOL_NAMES` y `docs/mcp.md` en el mismo cambio.
|
|
123
|
+
3. Si cambia el inventario de tests, actualizar esta evidencia versionada y evitar duplicar conteos en README.
|
|
124
|
+
4. Si cambia la semántica de setup/provider preview/status, revisar wording de provider config vs local store.
|
|
125
|
+
5. Si cambian runners o package evidence, actualizar `README.md`, `docs/cli.md` y `docs/contributing.md` según corresponda.
|
|
126
|
+
6. No marcar esta auditoría ni artefactos SDD como aceptados salvo aceptación humana explícita.
|
package/docs/providers.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
VGXNESS is provider-agnostic at the core: the registry stores provider-neutral definitions and adapters translate them into provider-specific config and runtime behavior. This document covers the two adapter layers: the **control-plane adapter** (OpenCode primary plus supported secondary Claude Code support) and the **code-runtime provider adapter** (OpenAI-compatible + fake).
|
|
4
4
|
|
|
5
|
-
## Status (v1.
|
|
5
|
+
## Status (v1.9.1)
|
|
6
6
|
|
|
7
7
|
| Provider | Control plane | Code runtime | Notes |
|
|
8
8
|
|---|---|---|---|
|
|
@@ -44,7 +44,7 @@ vgxness agents render --provider json --project vgxness --name apply-agent
|
|
|
44
44
|
|
|
45
45
|
### Claude Code support
|
|
46
46
|
|
|
47
|
-
Claude Code is supported as a secondary, non-default control-plane target.
|
|
47
|
+
Claude Code is supported as a secondary, non-default control-plane target. Status, doctor, setup plan, and change-plan surfaces can inspect or preview Claude targets without Claude Code installed and without writing provider config. Local VGXNESS store initialization may occur when the selected SQLite store is needed.
|
|
48
48
|
|
|
49
49
|
Claude scopes are canonicalized to `local`, `project`, and `user`; VGXNESS compatibility aliases `personal` and legacy `global` map to Claude `user` with warnings. MCP registration is represented as structured config/argv, for example `claude mcp add --scope user vgxness -- vgxness mcp start`; no shell strings are generated. For user/global apply, VGXNESS narrowly merges only `mcpServers.vgxness` in `~/.claude.json`, preserves unknown keys, backs up existing files, and does not manage auth/session data. Status/doctor/change-plan are read-only and do not execute Claude Code.
|
|
50
50
|
|
|
@@ -128,13 +128,13 @@ Deterministic, offline. Used by `test/code/` and `bun run smoke:opentui-code` to
|
|
|
128
128
|
|
|
129
129
|
Provider install and doctor flows live in `src/mcp/client-install-opencode.ts` and `src/mcp/provider-doctor.ts` and are exposed through the MCP server and the CLI:
|
|
130
130
|
|
|
131
|
-
- `vgxness mcp install opencode --plan` —
|
|
131
|
+
- `vgxness mcp install opencode --plan` — plan that never writes provider config; local VGXNESS store initialization may occur when the selected SQLite store is needed.
|
|
132
132
|
- `vgxness mcp install opencode --yes` — explicit write path; creates a backup first.
|
|
133
133
|
- `vgxness mcp doctor opencode` — JSON report of provider health.
|
|
134
134
|
- `vgxness provider status` / `vgxness provider doctor` (planned CLI) — same shape through the operator surface.
|
|
135
135
|
- `vgxness setup rollback --backup <path>` — restores a previous OpenCode config byte-for-byte after validation.
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
Provider config writes happen only through `apply` with explicit consent. Plans, status, doctor, change-plan, and previews do not write provider config; local VGXNESS store initialization may occur when the selected SQLite store is needed.
|
|
138
138
|
|
|
139
139
|
## Safety boundary
|
|
140
140
|
|
package/docs/safety.md
CHANGED
|
@@ -132,7 +132,7 @@ Retry policy evaluation is separate from execution. `vgxness_run_resume_gate` ev
|
|
|
132
132
|
|
|
133
133
|
## Safety boundaries (enforced everywhere)
|
|
134
134
|
|
|
135
|
-
- Read-only/preview commands must
|
|
135
|
+
- Read-only/preview commands must not mutate provider config or external tool state: setup plans, MCP setup previews, OpenCode previews, workflow previews, status views, and the natural-language orchestrator preview never write provider config, call providers, or install global memory. Local VGXNESS store initialization may occur when a command needs the selected SQLite store.
|
|
136
136
|
- Provider config writes (`opencode.json`, `.opencode/`, `.claude/`, `CLAUDE.md`) require explicit consent (`--yes` or an equivalent confirmed flow) plus backup/rollback behavior.
|
|
137
137
|
- The control plane and the code runtime do not create or write `openspec/`. SDD artifacts are stored through the local SQLite artifact service under canonical topic keys.
|
|
138
138
|
- Human acceptance is distinct from artifact presence: `vgxness_sdd_accept_artifact` records explicit human-only acceptance; saving a draft never implies acceptance.
|