vgxness 1.19.5 → 1.19.7

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.
@@ -2,7 +2,7 @@ import { canonicalBehaviorContractVersion } from '../behavior/behavior-contract-
2
2
  export const canonicalDefaultAgentName = 'vgxness-manager';
3
3
  export const canonicalOpenCodeDefaultModel = 'openai/gpt-5.5';
4
4
  export const canonicalOpenCodeManagerReasoningEffort = 'high';
5
- export const canonicalPromptContractVersion = 17;
5
+ export const canonicalPromptContractVersion = 18;
6
6
  export const canonicalSddSubagentNames = [
7
7
  'vgxness-sdd-explore',
8
8
  'vgxness-sdd-propose',
@@ -140,6 +140,7 @@ export function createCanonicalOpenCodeSddMcpToolPermissions() {
140
140
  vgxness_memory_save: 'allow',
141
141
  vgxness_memory_update: 'allow',
142
142
  vgxness_skill_payload: 'allow',
143
+ vgxness_run_list: 'allow',
143
144
  vgxness_run_preflight: 'allow',
144
145
  };
145
146
  }
@@ -178,7 +179,7 @@ Use lightest safe path: T0-2 direct, T3 preflight, T4 SDD for governance/permiss
178
179
  SDD happens in OpenCode via conversation, VGXNESS MCP, and SDD subagents. No terminal SDD phase commands. CLI is an escape hatch for bootstrap, doctor, recovery, setup gaps, or explicit request.
179
180
 
180
181
  ## MCP playbook
181
- - For starting, resuming, or recovering context: use \`vgxness_resume_context\` first for generic resume/continue prompts; pass \`explicitChange\` only when the user gave an exact valid change. \`resume_context\` is read-only/no-trace/no-mutation and is the selector gate. \`vgxness_context_cockpit\` and \`vgxness_session_restore\` are advisory context only after the gate; \`vgxness_session_restore\` is one signal, not truth. Do not infer a change from \`context_cockpit.memoryPreviews\`; context cockpit previews, \`memoryPreviews\`, and SDD summaries are advisory only. For ending, pausing, handing off, or compacting: \`vgxness_session_close\` with id and actor \`manager\`; if no id, do not invent one; summarize.
182
+ - For starting, resuming, or recovering context: use \`vgxness_resume_context\` first for generic resume/continue prompts; pass \`explicitChange\` only when the user gave an exact valid change. \`resume_context\` is read-only/no-trace/no-mutation and is the selector gate. For retrospective/status prompts like "what did we do?" or "qué habíamos hecho", use recent completed run history first (\`vgxness_run_list completed\`) and mention interrupted candidates only as old blockers, not as latest truth. \`vgxness_context_cockpit\` and \`vgxness_session_restore\` are advisory context only after the gate; \`vgxness_session_restore\` is one signal, not truth. Do not infer a change from \`context_cockpit.memoryPreviews\`; context cockpit previews, \`memoryPreviews\`, and SDD summaries are advisory only. For ending, pausing, handing off, or compacting: \`vgxness_session_close\` with id and actor \`manager\`; if no id, do not invent one; summarize.
182
183
  - Bounded resume/start hard stop: for generic "continue"/"sigamos"/"continuemos"/"resume development" without an explicit user change, call \`vgxness_resume_context\` before any SDD continuation/status. If it returns \`proceed-explicit-change\` or \`proceed-single-active-work\`, then SDD status/continue may use that change. If it returns \`inspect-interrupted-run\`, call \`vgxness_run_resume_inspect\`. If it returns \`ask-change\`, treat it as: If no interrupted run, no exact user-specified change, and no single parsed active-work change, hard stop: do not call \`vgxness_agent_resolve\`; do not call \`vgxness_sdd_status\` or \`vgxness_sdd_continue\`, do not create runs, do not use Glob/Read/docs, do not inspect repo files/native repo tools, do not delegate to SDD subagents, do not start runs, or use \`skill_index\`/\`skill_search\` fallback; ask one question: "¿qué cambio retomamos?".
183
184
  - Proposal clarity: if product/business clarity is missing, run a proposal question round.
184
185
  - SDD artifacts: guide with \`vgxness_sdd_next\`/\`vgxness_sdd_cockpit\`; list/read with \`vgxness_sdd_get_artifact\`/\`vgxness_sdd_list_artifacts\`; prefer \`payloadMode: "compact"\` so primary context stays clean; use verbose only when required, preferably inside the delegated phase subagent. Save with \`vgxness_sdd_save_artifact\` after the right flow. Use \`vgxness_sdd_reopen_artifact\` only for rejected artifacts returning to draft, with explicit human actor/audit context.
@@ -212,7 +213,7 @@ Be concise.`;
212
213
  const registryManagerInstructionsV11 = [
213
214
  '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.',
214
215
  'Default to delegation for SDD phase-shaped work, repository exploration beyond one narrow lookup, implementation, verification, incident recovery, or multi-step analysis. Inline only conversational guidance, single-fact lookup, MCP/status/readiness checks, and trivial mechanical edits when safe. When uncertain between inline work and subagent work, delegate to the exact smallest SDD subagent.',
215
- 'Use VGXNESS MCP as the durable control plane: for generic resume/continue prompts call vgxness_resume_context first, pass explicitChange only when the user gave an exact valid change, and do not infer a change from context_cockpit.memoryPreviews; vgxness_context_cockpit and vgxness_session_restore are advisory context only after the gate, and context cockpit previews, memoryPreviews, and SDD summaries are advisory only. Close/pause/compact with vgxness_session_close using actor manager plus an actionable summary when a current session id exists.',
216
+ 'Use VGXNESS MCP as the durable control plane: for generic resume/continue prompts call vgxness_resume_context first, pass explicitChange only when the user gave an exact valid change, and do not infer a change from context_cockpit.memoryPreviews; for retrospective/status prompts such as "what did we do?" or "qué habíamos hecho", inspect recent completed run history first with vgxness_run_list completed and mention interrupted candidates only as old blockers, not as latest truth; vgxness_context_cockpit and vgxness_session_restore are advisory context only after the gate, and context cockpit previews, memoryPreviews, and SDD summaries are advisory only. Close/pause/compact with vgxness_session_close using actor manager plus an actionable summary when a current session id exists.',
216
217
  'For generic continue/sigamos/continuemos/resume development without an explicit user change, call vgxness_resume_context before any SDD status/continuation. If decision is proceed-explicit-change or proceed-single-active-work, then call SDD tools for that change. If inspect-interrupted-run, call vgxness_run_resume_inspect. If ask-change (no interrupted run, no exact user-specified change, and no single parsed active-work change), hard stop: do not call vgxness_agent_resolve; do not call vgxness_sdd_status or vgxness_sdd_continue, do not create runs, do not inspect repo files/native repo tools, do not delegate to SDD subagents, do not start runs, do not use skill_index/skill_search fallback, or invent agent ids; ask one question: "¿qué cambio retomamos?".',
217
218
  '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 phase output with sdd_save_artifact only by governance; inspect delegated result-envelope completeness before SDD artifact persistence or phase advancement (status, executive_summary, artifacts_examined, skill_resolution, risks, next_recommended) as prompt guidance only, not runtime parsing/rejection; when proposal is accepted, spec/design/tasks may run sequentially as draft-only autorun without extra confirmation, while acceptance remains human-only. Memory capture policy: save/update only durable, future-relevant, actionable, scoped, evidence-backed, compact, non-sensitive observations; prefer update by known id/topicKey over duplicate saves; never save full SDD artifacts, transcripts, raw logs, hidden reasoning, secrets, credentials, or sensitive user data. Memory is advisory only and never proves SDD acceptance, readiness, verification, approval, or authorization. SDD artifacts are canonical for phase deliverables/governance state. Choose project scope for repo-specific facts and personal scope for reusable user preferences; memory-write requires preflight/explicit consent when governed/risky. 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.',
218
219
  'When sdd_continue/vgxness_sdd_continue returns recommendedActions, prefer the first safe action with agentCallable true and humanOnly false; use targetTool plus suggestedArgs as the starting point, and stop for requiresHumanConfirmation, requiresProviderWriteConsent, requiresPreflight, ambiguous, destructive, privileged, external, or outside-approval actions. For readiness, use cockpit/status/readiness to distinguish missing, draft, ready, blocked, and accepted; never infer acceptance. For provider evidence, report providerEvidence.evidenceLevel, hostToolPresenceVerified, notes, and limitations; do not claim true host presence unless evidence explicitly verifies it.',
@@ -29,7 +29,8 @@ export class ResumeContextGateService {
29
29
  };
30
30
  });
31
31
  const distinctActiveWorkChanges = [...new Set(activeWorkHits.map((hit) => hit.change).filter(isString))];
32
- const decision = decide(explicitChange, interrupted.value, distinctActiveWorkChanges);
32
+ const retrospectiveStatusPrompt = isRetrospectiveStatusPrompt(input.userPrompt);
33
+ const decision = decide(explicitChange, interrupted.value, distinctActiveWorkChanges, retrospectiveStatusPrompt);
33
34
  const selectedChange = decision === 'proceed-explicit-change' ? explicitChange : decision === 'proceed-single-active-work' ? distinctActiveWorkChanges[0] : undefined;
34
35
  return {
35
36
  ok: true,
@@ -44,7 +45,7 @@ export class ResumeContextGateService {
44
45
  ...(decision === 'proceed-explicit-change' ? { selectedBy: 'explicit-change' } : {}),
45
46
  ...(decision === 'proceed-single-active-work' ? { selectedBy: 'single-active-work' } : {}),
46
47
  ...(decision === 'ask-change' ? { question: '¿qué cambio retomamos?' } : {}),
47
- nextAction: nextAction(decision),
48
+ nextAction: nextAction(decision, retrospectiveStatusPrompt),
48
49
  allowedNextTools: allowedNextTools(decision),
49
50
  prohibitedNextTools: prohibitedNextTools(decision),
50
51
  evidence: {
@@ -112,9 +113,11 @@ export class ResumeContextGateService {
112
113
  return this.dependencies.memory.searchObservationPreviewsNoTrace({ project, topicKey: 'active-work', limit });
113
114
  }
114
115
  }
115
- function decide(explicitChange, interruptedRuns, distinctActiveWorkChanges) {
116
+ function decide(explicitChange, interruptedRuns, distinctActiveWorkChanges, retrospectiveStatusPrompt) {
116
117
  if (explicitChange !== undefined)
117
118
  return 'proceed-explicit-change';
119
+ if (retrospectiveStatusPrompt)
120
+ return 'ask-change';
118
121
  const interrupted = interruptedRuns[0];
119
122
  if (interrupted !== undefined)
120
123
  return 'inspect-interrupted-run';
@@ -122,6 +125,28 @@ function decide(explicitChange, interruptedRuns, distinctActiveWorkChanges) {
122
125
  return 'proceed-single-active-work';
123
126
  return 'ask-change';
124
127
  }
128
+ function isRetrospectiveStatusPrompt(prompt) {
129
+ if (prompt === undefined)
130
+ return false;
131
+ const normalized = prompt
132
+ .normalize('NFD')
133
+ .replace(/[\u0300-\u036f]/g, '')
134
+ .toLocaleLowerCase('en-US');
135
+ return retrospectiveStatusPhrases.some((phrase) => normalized.includes(phrase));
136
+ }
137
+ const retrospectiveStatusPhrases = [
138
+ 'what did we do',
139
+ 'what happened',
140
+ 'latest completed',
141
+ 'recent work',
142
+ 'what was done',
143
+ 'last release',
144
+ 'que hicimos',
145
+ 'que habiamos hecho',
146
+ 'que se hizo',
147
+ 'ultimo trabajo',
148
+ 'ultima version',
149
+ ];
125
150
  function allowedNextTools(decision) {
126
151
  if (decision === 'inspect-interrupted-run')
127
152
  return ['vgxness_run_resume_inspect', 'vgxness_run_resume_gate'];
@@ -159,7 +184,10 @@ function prohibitedNextTools(decision) {
159
184
  ];
160
185
  return [...base, 'mutating-artifact-tools', 'vgxness_run_start'];
161
186
  }
162
- function nextAction(decision) {
187
+ function nextAction(decision, retrospectiveStatusPrompt = false) {
188
+ if (decision === 'ask-change' && retrospectiveStatusPrompt) {
189
+ return 'For retrospective/status prompts, do not treat interrupted runs as latest truth; inspect recent completed run history first, and mention interrupted candidates only as advisory blockers.';
190
+ }
163
191
  switch (decision) {
164
192
  case 'proceed-explicit-change':
165
193
  return 'Proceed with SDD read/progression tools for the explicit selectedChange only.';
@@ -0,0 +1,84 @@
1
+ export function buildResumeAfterApprovalResult(input) {
2
+ const operationKind = stringFromObject(input.executorOutput, 'operationKind') ?? operationKindFromOperation(input.operation);
3
+ const command = operationKind === 'allowlisted-command' ? extractAllowlistedCommandMetadata(input.executorOutput) : undefined;
4
+ return {
5
+ kind: 'resume-after-approval-result',
6
+ version: 1,
7
+ operationKind,
8
+ runId: input.runId,
9
+ approvalId: input.approvalId,
10
+ attemptId: input.attemptId,
11
+ permissionEventId: input.permissionEventId,
12
+ pendingExecutionEventId: input.pendingExecutionEventId,
13
+ operationFingerprint: input.operationFingerprint,
14
+ executor: input.executorName,
15
+ status: input.status,
16
+ ...(command === undefined ? {} : { command }),
17
+ error: input.error === undefined ? null : { code: input.error.code, message: input.error.message },
18
+ safety: buildSafety(input.executorOutput),
19
+ };
20
+ }
21
+ function extractAllowlistedCommandMetadata(output) {
22
+ if (!isObject(output))
23
+ return undefined;
24
+ const command = isObject(output.command) ? output.command : output;
25
+ const commandId = stringField(command.commandId) ?? stringField(output.commandId);
26
+ const argv = stringArray(command.argv) ?? stringArray(output.argv);
27
+ if (commandId === undefined || argv === undefined)
28
+ return undefined;
29
+ const result = { commandId, argv };
30
+ setOptionalNumberOrNull(result, 'exitCode', command.exitCode);
31
+ setOptionalStringOrNull(result, 'signal', command.signal);
32
+ setOptionalBoolean(result, 'timedOut', command.timedOut);
33
+ setOptionalBoolean(result, 'outputTruncated', command.outputTruncated);
34
+ setOptionalNumber(result, 'stdoutBytes', command.stdoutBytes);
35
+ setOptionalNumber(result, 'stderrBytes', command.stderrBytes);
36
+ return result;
37
+ }
38
+ function buildSafety(output) {
39
+ const source = isObject(output) && isObject(output.command) && isObject(output.command.safety) ? output.command.safety : isObject(output) && isObject(output.safety) ? output.safety : undefined;
40
+ return {
41
+ metadataOnly: true,
42
+ rawStdoutPersisted: false,
43
+ rawStderrPersisted: false,
44
+ providerPayloadPersisted: false,
45
+ executorOutputWhitelisted: true,
46
+ ...(typeof source?.boundedProcess === 'boolean' ? { boundedProcess: source.boundedProcess } : {}),
47
+ ...(typeof source?.shellDisabled === 'boolean' ? { shellDisabled: source.shellDisabled } : {}),
48
+ ...(typeof source?.argvArrayOnly === 'boolean' ? { argvArrayOnly: source.argvArrayOnly } : {}),
49
+ ...(typeof source?.providerConfigWritesBlocked === 'boolean' ? { providerConfigWritesBlocked: source.providerConfigWritesBlocked } : {}),
50
+ ...(typeof source?.createsSandbox === 'boolean' ? { createsSandbox: source.createsSandbox } : {}),
51
+ ...(typeof source?.createsWorktree === 'boolean' ? { createsWorktree: source.createsWorktree } : {}),
52
+ };
53
+ }
54
+ function operationKindFromOperation(operation) {
55
+ return isObject(operation.input) && typeof operation.input.operationKind === 'string' ? operation.input.operationKind : 'generic-operation';
56
+ }
57
+ function stringFromObject(value, key) {
58
+ return isObject(value) ? stringField(value[key]) : undefined;
59
+ }
60
+ function stringField(value) {
61
+ return typeof value === 'string' ? value : undefined;
62
+ }
63
+ function stringArray(value) {
64
+ return Array.isArray(value) && value.every((item) => typeof item === 'string') ? value : undefined;
65
+ }
66
+ function setOptionalNumber(target, key, value) {
67
+ if (typeof value === 'number')
68
+ target[key] = value;
69
+ }
70
+ function setOptionalBoolean(target, key, value) {
71
+ if (typeof value === 'boolean')
72
+ target[key] = value;
73
+ }
74
+ function setOptionalNumberOrNull(target, key, value) {
75
+ if (typeof value === 'number' || value === null)
76
+ target[key] = value;
77
+ }
78
+ function setOptionalStringOrNull(target, key, value) {
79
+ if (typeof value === 'string' || value === null)
80
+ target[key] = value;
81
+ }
82
+ function isObject(value) {
83
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
84
+ }
@@ -7,6 +7,7 @@ import { evaluateOperationRetry as evaluateOperationRetryPolicy } from './operat
7
7
  import { AllowlistedApplyProgressCommandExecutor } from '../workflows/command-allowlist-adapter.js';
8
8
  import { RunRepository, } from './repositories/runs.js';
9
9
  import { buildRunInsights, buildRunOperatorResumePlan } from './run-insights.js';
10
+ import { buildResumeAfterApprovalResult } from './resume-after-approval-result.js';
10
11
  const preflightSafety = {
11
12
  operationExecuted: false,
12
13
  executorInvoked: false,
@@ -459,7 +460,19 @@ export class RunService {
459
460
  const executed = input.executor.execute({ runId: approval.value.runId, operation });
460
461
  if (!executed.ok) {
461
462
  const error = { code: executed.error.code, message: executed.error.message };
462
- const attempt = this.runs.completeOperationAttempt({ attemptId: reserved.value.id, status: 'failed', error });
463
+ const result = buildResumeAfterApprovalResult({
464
+ runId: approval.value.runId,
465
+ approvalId: approval.value.id,
466
+ attemptId: reserved.value.id,
467
+ permissionEventId: permissionEvent.id,
468
+ pendingExecutionEventId: pendingExecutionEvent.id,
469
+ operationFingerprint: replayGuard.operationFingerprint,
470
+ executorName: input.executor.name,
471
+ operation,
472
+ status: 'failed',
473
+ error,
474
+ });
475
+ const attempt = this.runs.completeOperationAttempt({ attemptId: reserved.value.id, status: 'failed', output: result, error });
463
476
  if (!attempt.ok)
464
477
  return attempt;
465
478
  const executionEvent = this.runs.appendEvent({
@@ -478,6 +491,7 @@ export class RunService {
478
491
  operationFingerprint: replayGuard.operationFingerprint,
479
492
  resumedFromApprovalId: approval.value.id,
480
493
  executorInvoked: true,
494
+ result,
481
495
  error,
482
496
  }),
483
497
  relatedType: 'approval',
@@ -486,7 +500,7 @@ export class RunService {
486
500
  if (!executionEvent.ok)
487
501
  return { ok: false, error: executionEvent.error };
488
502
  const linkedAttempt = this.runs.attachAttemptResultEvent(attempt.value.id, executionEvent.value.id);
489
- const evidence = appendApplyProgressAllowlistEvidenceIfNeeded(this.runs, approval.value.id, permissionEvent, pendingExecutionEvent, linkedAttempt.ok ? linkedAttempt.value : attempt.value, executionEvent.value, replayGuard.operationFingerprint, input.executor.name, operation, undefined, error);
503
+ const evidence = appendApplyProgressAllowlistEvidenceIfNeeded(this.runs, approval.value.id, permissionEvent, pendingExecutionEvent, linkedAttempt.ok ? linkedAttempt.value : attempt.value, executionEvent.value, replayGuard.operationFingerprint, input.executor.name, operation, result);
490
504
  if (!evidence.ok)
491
505
  return { ok: false, error: evidence.error };
492
506
  return {
@@ -498,12 +512,25 @@ export class RunService {
498
512
  attempt: linkedAttempt.ok ? linkedAttempt.value : attempt.value,
499
513
  executionEvent: executionEvent.value,
500
514
  status: 'failed',
515
+ output: result,
501
516
  ...(evidence.value === undefined ? {} : evidence.value),
502
517
  },
503
518
  };
504
519
  }
505
520
  const output = executed.value.output;
506
- const attempt = this.runs.completeOperationAttempt({ attemptId: reserved.value.id, status: 'succeeded', ...(output === undefined ? {} : { output }) });
521
+ const result = buildResumeAfterApprovalResult({
522
+ runId: approval.value.runId,
523
+ approvalId: approval.value.id,
524
+ attemptId: reserved.value.id,
525
+ permissionEventId: permissionEvent.id,
526
+ pendingExecutionEventId: pendingExecutionEvent.id,
527
+ operationFingerprint: replayGuard.operationFingerprint,
528
+ executorName: input.executor.name,
529
+ operation,
530
+ status: 'succeeded',
531
+ ...(output === undefined ? {} : { executorOutput: output }),
532
+ });
533
+ const attempt = this.runs.completeOperationAttempt({ attemptId: reserved.value.id, status: 'succeeded', output: result });
507
534
  if (!attempt.ok)
508
535
  return attempt;
509
536
  const executionEvent = this.runs.appendEvent({
@@ -522,7 +549,7 @@ export class RunService {
522
549
  operationFingerprint: replayGuard.operationFingerprint,
523
550
  resumedFromApprovalId: approval.value.id,
524
551
  executorInvoked: true,
525
- output: output ?? null,
552
+ result,
526
553
  }),
527
554
  relatedType: 'approval',
528
555
  relatedId: approval.value.id,
@@ -530,7 +557,7 @@ export class RunService {
530
557
  if (!executionEvent.ok)
531
558
  return { ok: false, error: executionEvent.error };
532
559
  const linkedAttempt = this.runs.attachAttemptResultEvent(attempt.value.id, executionEvent.value.id);
533
- const evidence = appendApplyProgressAllowlistEvidenceIfNeeded(this.runs, approval.value.id, permissionEvent, pendingExecutionEvent, linkedAttempt.ok ? linkedAttempt.value : attempt.value, executionEvent.value, replayGuard.operationFingerprint, input.executor.name, operation, output, undefined);
560
+ const evidence = appendApplyProgressAllowlistEvidenceIfNeeded(this.runs, approval.value.id, permissionEvent, pendingExecutionEvent, linkedAttempt.ok ? linkedAttempt.value : attempt.value, executionEvent.value, replayGuard.operationFingerprint, input.executor.name, operation, result);
534
561
  if (!evidence.ok)
535
562
  return { ok: false, error: evidence.error };
536
563
  return {
@@ -542,7 +569,7 @@ export class RunService {
542
569
  attempt: linkedAttempt.ok ? linkedAttempt.value : attempt.value,
543
570
  executionEvent: executionEvent.value,
544
571
  status: 'succeeded',
545
- ...(output === undefined ? {} : { output }),
572
+ output: result,
546
573
  ...(evidence.value === undefined ? {} : evidence.value),
547
574
  },
548
575
  };
@@ -1002,24 +1029,21 @@ function workflowConflictDecision(input, runWorkflow) {
1002
1029
  auditEvidence: [`runWorkflow:${runWorkflow}`, `explicitWorkflow:${input.workflow}`],
1003
1030
  };
1004
1031
  }
1005
- function appendApplyProgressAllowlistEvidenceIfNeeded(runs, approvalId, permissionEvent, pendingExecutionEvent, attempt, executionEvent, operationFingerprint, executorName, operation, output, error) {
1032
+ function appendApplyProgressAllowlistEvidenceIfNeeded(runs, approvalId, permissionEvent, pendingExecutionEvent, attempt, executionEvent, operationFingerprint, executorName, operation, result) {
1006
1033
  if (!isApplyProgressAllowlistedCommandOperation(operation))
1007
1034
  return { ok: true, value: undefined };
1008
1035
  const base = {
1009
- kind: 'apply-progress-operation',
1010
- operationKind: 'allowlisted-command',
1011
- runId: attempt.runId,
1012
- approvalId,
1013
- attemptId: attempt.id,
1014
- pendingExecutionEventId: pendingExecutionEvent.id,
1015
- permissionEventId: permissionEvent.id,
1036
+ ...result,
1016
1037
  executionEventId: executionEvent.id,
1017
- operationFingerprint,
1018
- executor: executorName,
1019
- operation: operationMetadata(operation),
1020
- status: attempt.status,
1021
- output: output ?? null,
1022
- error: error ?? null,
1038
+ audit: {
1039
+ metadataOnly: true,
1040
+ operationFingerprint,
1041
+ executor: executorName,
1042
+ approvalId,
1043
+ pendingExecutionEventId: pendingExecutionEvent.id,
1044
+ permissionEventId: permissionEvent.id,
1045
+ attemptId: attempt.id,
1046
+ },
1023
1047
  };
1024
1048
  const evidence = runs.appendEvent({
1025
1049
  runId: attempt.runId,
@@ -162,6 +162,11 @@ function acceptedEvidence(workspaceRoot, cwd, checks) {
162
162
  enforceable: true,
163
163
  createsSandbox: false,
164
164
  createsWorktree: false,
165
+ filesystemIsolation: false,
166
+ networkIsolation: false,
167
+ shellDisabled: true,
168
+ argvArrayOnly: true,
169
+ providerConfigWritesBlocked: true,
165
170
  workspaceRoot,
166
171
  cwd,
167
172
  capabilities: {
@@ -55,16 +55,31 @@ export class CommandAllowlistAdapter {
55
55
  const result = this.runner(this.request);
56
56
  if (!result.ok)
57
57
  throw new Error(`${result.error.code}: ${result.error.message}`);
58
+ const stdoutBytes = Buffer.byteLength(result.value.stdout);
59
+ const stderrBytes = Buffer.byteLength(result.value.stderr);
60
+ const safety = {
61
+ strategy: result.value.evidence.strategy,
62
+ boundedProcess: true,
63
+ createsSandbox: result.value.evidence.createsSandbox,
64
+ createsWorktree: result.value.evidence.createsWorktree,
65
+ filesystemIsolation: result.value.evidence.filesystemIsolation,
66
+ networkIsolation: result.value.evidence.networkIsolation,
67
+ shellDisabled: result.value.evidence.shellDisabled,
68
+ argvArrayOnly: result.value.evidence.argvArrayOnly,
69
+ providerConfigWritesBlocked: result.value.evidence.providerConfigWritesBlocked,
70
+ };
58
71
  const output = {
59
- command: this.commandId,
72
+ commandId: this.commandId,
60
73
  executable: this.entry.executable,
61
- args: this.entry.args,
74
+ argv: [this.entry.executable, ...this.entry.args],
75
+ cwd: this.plan.request.cwd,
62
76
  exitCode: result.value.exitCode,
63
77
  signal: result.value.signal,
64
78
  timedOut: result.value.timedOut,
65
79
  outputTruncated: result.value.outputTruncated,
66
- stdout: result.value.stdout,
67
- stderr: result.value.stderr,
80
+ stdoutBytes,
81
+ stderrBytes,
82
+ safety,
68
83
  };
69
84
  const failed = result.value.timedOut || result.value.exitCode !== 0;
70
85
  return {
@@ -77,6 +92,11 @@ export class CommandAllowlistAdapter {
77
92
  shell: false,
78
93
  argv: [this.entry.executable, ...this.entry.args],
79
94
  cwd: this.plan.request.cwd,
95
+ stdoutBytes,
96
+ stderrBytes,
97
+ outputTruncated: result.value.outputTruncated,
98
+ timedOut: result.value.timedOut,
99
+ safety,
80
100
  },
81
101
  ...(failed
82
102
  ? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vgxness",
3
- "version": "1.19.5",
3
+ "version": "1.19.7",
4
4
  "description": "CLI and MCP control plane for guided AI-agent workflows, SDD, memory, and OpenCode setup.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {