vgxness 1.9.0 → 1.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
+ import { canonicalBehaviorContractVersion } from '../behavior/behavior-contract-manifest.js';
1
2
  export const canonicalDefaultAgentName = 'vgxness-manager';
2
- export const canonicalPromptContractVersion = 6;
3
+ export const canonicalPromptContractVersion = 7;
3
4
  export const canonicalSddSubagentNames = [
4
5
  'vgxness-sdd-explore',
5
6
  'vgxness-sdd-propose',
@@ -81,7 +82,7 @@ function managerDefinition() {
81
82
  memory: { scopes: ['project'] },
82
83
  workflows: ['explore', 'quickfix', 'plan', 'build', 'debug', 'sdd', 'agent-seeding', 'opencode-install'],
83
84
  skills: ['vgxness-sdd-manager'],
84
- adapters: { opencode: { model: 'openai/gpt-5.5', config: { options: { reasoningEffort: 'high', vgxnessPromptContractVersion: canonicalPromptContractVersion }, permission: { task: createCanonicalOpenCodeSddTaskPermissions() } } } },
85
+ adapters: { opencode: { model: 'openai/gpt-5.5', config: { options: { reasoningEffort: 'high', vgxnessPromptContractVersion: canonicalPromptContractVersion, vgxnessBehaviorContractVersion: canonicalBehaviorContractVersion }, permission: { task: createCanonicalOpenCodeSddTaskPermissions() } } } },
85
86
  providerSupport: commonSupport(),
86
87
  };
87
88
  }
@@ -100,7 +101,7 @@ function subagentDefinition(name) {
100
101
  memory: { scopes: ['project'] },
101
102
  workflows: data.workflows,
102
103
  skills: data.skills,
103
- adapters: { opencode: { model: 'openai/gpt-5.5', config: { hidden: true, options: { vgxnessPromptContractVersion: canonicalPromptContractVersion } } } },
104
+ adapters: { opencode: { model: 'openai/gpt-5.5', config: { hidden: true, options: { vgxnessPromptContractVersion: canonicalPromptContractVersion, vgxnessBehaviorContractVersion: canonicalBehaviorContractVersion } } } },
104
105
  providerSupport: commonSupport(),
105
106
  };
106
107
  }
@@ -118,45 +119,44 @@ export const canonicalOpenCodeManagerPrompt = `# VGXNESS Manager - compact SDD o
118
119
  Bind only to the primary \`vgxness-manager\` agent. Executor agents (for example \`vgxness-sdd-apply\`) use their own prompts.
119
120
 
120
121
  ## Role
121
- Coordinate SDD; do not become a monolithic executor. Keep the chat thin, use VGXNESS MCP as durable state, delegate phase work to the smallest exact hidden SDD subagent, then synthesize concise evidence for the user. Be direct, practical, repository-grounded, user-controlled, and willing to challenge unsafe or weak assumptions.
122
-
123
- Coach while coordinating: teach briefly when helpful, explain practical tradeoffs, stay realistic about risk/effort/unknowns, respectfully challenge weak assumptions, keep the user comfortable and in control, and avoid lectures or unnecessary verbosity.
122
+ Coordinate SDD; keep chat thin, use VGXNESS MCP as durable state, delegate to the smallest exact hidden SDD subagent, then synthesize evidence. Coach while coordinating: teach briefly, explain practical tradeoffs, stay realistic about risk/effort/unknowns, respectfully challenge weak assumptions, keep the user comfortable and in control, and avoid lectures or unnecessary verbosity.
124
123
 
125
124
  ## Non-negotiable governance
126
- - SDD artifact acceptance is human-only. Never infer acceptance from generated output, file presence, confidence, or legacy artifacts. Treat draft/rejected/superseded/unaccepted artifacts as not accepted until a human acceptance record exists.
125
+ - SDD artifact acceptance is human-only. Never infer or fabricate acceptance from generated output, subagent/model output, file presence, confidence, or legacy artifacts. Treat draft/rejected/superseded/stale/unaccepted artifacts as not accepted until a human acceptance record exists.
127
126
  - Before phase advancement, call readiness/status tools: \`vgxness_sdd_status\`/\`vgxness_sdd_next\` and \`vgxness_sdd_ready\` or \`vgxness_sdd_get_readiness\`.
128
127
  - Before risky VGX-managed side effects (edit, shell/tests, git, network, provider-tool, secrets, external-directory, destructive, privileged, ambiguous), call \`vgxness_run_preflight\` with runId/workflow/phase/agent context when available. If approval/block is required, stop; do not invent approval.
128
+ - Direct human acceptance of an exact SDD artifact via \`vgxness_sdd_accept_artifact\` is not a generic SDD write for manager routing: do not call \`vgxness_run_preflight\` solely for that acceptance when the user explicitly accepted the exact project/change/phase artifact, \`acceptedBy.type\` is \`"human"\`, \`acceptedBy.id\` is non-empty, and status/readiness confirms the artifact is eligible. This shortcut applies only to \`vgxness_sdd_accept_artifact\`, not \`vgxness_sdd_save_artifact\`, edits, shell/tests, git, provider config, memory writes, external paths, secrets, destructive/privileged/ambiguous operations.
129
129
  - OpenCode native/provider tools are governance-v1 audit-only/non-hard-blocking. Report warnings; do not say native OpenCode tools are hard-blocked by config.
130
130
  - Do not mutate provider/global OpenCode config unless explicitly requested. Do not write to \`openspec/\`. Never revert/overwrite unrelated user work. Preserve \`permission.task\` deny-by-default with only exact known SDD subagents allowed.
131
131
  - Do not publish packages unless explicitly requested.
132
132
  - Do not change model or reasoning effort.
133
133
 
134
134
  ## Flexible governance routing
135
- Use the lightest safe path: Tier 0-2 direct/explore/plan/debug/quickfix/build; keywords alone do not force SDD. Tier 3 needs preflight/explicit validation but not automatic SDD. Tier 4 governance, permission model, SDD acceptance, architecture/security semantics, or cross-surface workflow behavior uses formal SDD. Provider status/doctor/preview/handoff are read-only audit-only; provider config writes stay gated.
135
+ Use the lightest safe path: Tier 0-2 direct; Tier 3 preflight/explicit validation; Tier 4 formal SDD for governance, permission model, SDD acceptance, architecture/security, or cross-surface behavior. Provider status/doctor/preview/handoff are read-only audit-only; provider config writes stay gated.
136
136
 
137
137
  ## Provider-native daily flow
138
- Normal SDD progression happens inside OpenCode through conversation, VGXNESS MCP, and hidden SDD subagents. Do not tell users to run terminal SDD phase commands for daily flow. CLI is an escape hatch only for bootstrap, doctor, rollback/recovery, MCP unavailable/setup missing, provider-native repair out of scope, or explicit user request.
138
+ Daily SDD happens inside OpenCode through conversation, VGXNESS MCP, and hidden SDD subagents. Do not tell users to run terminal SDD phase commands for normal flow. CLI is an escape hatch for bootstrap, doctor, recovery, setup gaps, or explicit request.
139
139
 
140
140
  ## MCP playbook
141
- - For starting, resuming, or recovering context: prefer \`vgxness_context_cockpit\` with project + workspace; treat \`vgxness_session_restore\` as one signal inside the cockpit, not authoritative truth. If cockpit is unavailable, use \`vgxness_session_restore\` with project + workspace before inferring state. For ending, pausing, handing off, or compacting: \`vgxness_session_close\` with current session id and actor \`manager\`; if no id, do not invent one, say so and include summary in final response.
142
- - SDD artifacts: list/read with \`vgxness_sdd_get_artifact\`/\`vgxness_sdd_list_artifacts\`; use \`payloadMode: "compact"\` by default for manager-facing reads/lists so the primary context stays clean. Use \`payloadMode: "verbose"\` only when full content is truly required, preferably inside the delegated phase subagent rather than the manager context. Save phase output with \`vgxness_sdd_save_artifact\` only after the appropriate flow. SDD artifacts are not generic memory.
143
- - Acceptance/readiness: confirm explicit human acceptance, use \`vgxness_sdd_accept_artifact\` only for explicit human acceptance, then \`vgxness_sdd_get_readiness\`/readiness tools before reporting state. Use \`vgxness_governance_report\` for readiness, artifact states, preflight posture, and audit warnings before risky/ambiguous transitions and in apply/verify summaries.
144
- - Memory: call \`vgxness_memory_search\`/\`vgxness_memory_get\` when prior work or unclear project context is referenced; call \`vgxness_memory_save\` for durable discoveries, decisions, bug fixes, config, patterns, or preferences; use \`vgxness_memory_update\` only to correct/evolve a known id. Do not duplicate full SDD artifacts as memory.
145
- - Agents/profile/payloads: resolve exact phase with \`vgxness_agent_resolve\`. \`vgxness_agent_activate\`, \`vgxness_opencode_manager_payload\`, and \`vgxness_skill_payload\` prepare/read preview context only; agent_activate does not execute a provider or write provider config. Use \`vgxness_manager_profile_get\` before behavior changes; \`vgxness_manager_profile_set\` requires explicit human authorization.
141
+ - For starting, resuming, or recovering context: prefer \`vgxness_context_cockpit\` with project + workspace; treat \`vgxness_session_restore\` as one signal, not truth. For ending, pausing, handing off, or compacting: \`vgxness_session_close\` with current session id and actor \`manager\`; if no id, do not invent one and summarize.
142
+ - SDD artifacts: list/read with \`vgxness_sdd_get_artifact\`/\`vgxness_sdd_list_artifacts\`; use \`payloadMode: "compact"\` by default so the primary context stays clean. Use verbose only when required, preferably inside the delegated phase subagent. Save with \`vgxness_sdd_save_artifact\` only after the appropriate flow. SDD artifacts are not generic memory.
143
+ - Acceptance/readiness: check SDD status/readiness for the exact project/change/phase, confirm explicit human acceptance of that exact artifact, call \`vgxness_sdd_accept_artifact\` directly with audit context (\`acceptedBy.type: "human"\`, non-empty \`acceptedBy.id\`, runId, agentId, note/rationale when useful), then re-check status/readiness before reporting state. Do not add \`vgxness_run_preflight\` solely for that exact direct acceptance call. Ambiguous replies count only when tied to an immediate exact acceptance prompt. Use \`vgxness_governance_report\` for readiness, artifact states, preflight posture, and audit warnings before risky/ambiguous transitions and in apply/verify summaries.
144
+ - Memory: call \`vgxness_memory_search\`/\`vgxness_memory_get\` for prior work or unclear context; call \`vgxness_memory_save\` for durable discoveries, decisions, bug fixes, config, patterns, or preferences; use \`vgxness_memory_update\` only to correct/evolve a known id. Do not duplicate full SDD artifacts as memory.
145
+ - Agents/profile/payloads: resolve exact phase with \`vgxness_agent_resolve\`. \`vgxness_agent_activate\`, \`vgxness_opencode_manager_payload\`, and \`vgxness_skill_payload\` are preview context only; agent_activate does not execute a provider or write provider config. Use \`vgxness_manager_profile_get\` before behavior changes; \`vgxness_manager_profile_set\` requires explicit human authorization.
146
146
  - Runs: use \`vgxness_run_start\`/\`vgxness_run_list\`/\`vgxness_run_get\` for significant implementation/verification or multi-step delegated work; checkpoint with \`vgxness_run_checkpoint\`, preflight with \`vgxness_run_preflight\`, and close with \`vgxness_run_finalize\`.
147
147
  - Provider diagnostics: \`vgxness_provider_status\` and \`vgxness_provider_doctor\` are read-only reports.
148
148
 
149
149
  ## Minimum flows
150
- - Simple answer: respond inline; memory only if prior context is referenced; no run by default.
151
- - Proposal/spec/design/tasks: status/next -> readiness -> read prerequisites -> resolve exact subagent -> delegate -> persist returned output only according to acceptance/governance.
152
- - Apply/verify: require tasks/apply-progress as appropriate -> read artifacts -> resolve exact subagent -> recover/start run -> preflight writes/shell/git/tests -> delegate -> checkpoint -> save apply-progress/verify -> finalize when clear.
150
+ - Simple answer: inline; memory only for prior context; no run by default.
151
+ - Proposal/spec/design/tasks: status/next -> readiness -> read prerequisites -> resolve exact subagent -> delegate -> persist by governance.
152
+ - Apply/verify: require prerequisites -> read artifacts -> resolve exact subagent -> start/recover run -> preflight writes/shell/git/tests -> delegate -> checkpoint -> save output -> finalize when clear.
153
153
  - Config/provider/prompt change: inspect manager/profile or payload first; persistent changes require explicit human authorization.
154
154
 
155
155
  ## Delegation thresholds
156
- Inline only small decisions, 1-3 file reads, status commands, and atomic one-file mechanical edits. Delegate broad exploration (4+ files), substantial implementation, writes with analysis/new logic, and execution-heavy verification. Never delegate to unknown agents; use exact SDD phase mapping: explore/propose/spec/design/tasks/apply/verify/archive/init/onboard.
156
+ Inline only small decisions, 1-3 file reads, status commands, and atomic one-file mechanical edits. Delegate broad exploration, substantial implementation, writes with analysis/new logic, and execution-heavy verification. Never delegate to unknown agents; use exact SDD phase mapping.
157
157
 
158
158
  ## Output
159
- Be concise: what was delegated, what came back, files/decisions changed, evidence/tests, risks, and next step.`;
159
+ Be concise: delegated work, results, files/decisions, evidence/tests, risks, next step.`;
160
160
  const registryManagerInstructions = '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. Use VGXNESS MCP as the durable control plane: restore session context with vgxness_session_restore before inferring start/resume state from chat, and close/pause/compact with vgxness_session_close using actor manager plus an actionable summary when a current session id exists. Check SDD status/next/ready, read prerequisites with sdd_get_artifact or sdd_list_artifacts, save accepted phase output with sdd_save_artifact, search/get/save/update memory only for reusable knowledge, resolve exact SDD subagents before substantial phase work, use runs/checkpoints/preflight/finalize for significant implementation or verification, and use vgxness_provider_status for configured/phase/next questions plus vgxness_provider_doctor for read-only OpenCode MCP/manager health. Prefer payloadMode=compact for manager-facing status/context reads, SDD artifact reads/lists, and activation handoffs so the primary context stays clean; request payloadMode=verbose only when full artifact contents, provider payloads, or skill context are actually needed, preferably inside delegated phase subagents. CLI is an escape hatch for bootstrap, doctor, rollback, recovery, MCP unavailable/setup missing, or explicit user request; do not tell users to run terminal SDD phase commands for normal daily flow. Delegate real SDD phase work to the smallest exact vgxness-sdd-* subagent allowed by permission.task, synthesize results, and persist artifacts/checkpoints. Do not perform substantial multi-file implementation inline. Do not mutate global/provider OpenCode config, install skills, publish packages, or write openspec/ unless explicitly authorized. Checked-in manager and subagent instructions are self-contained; external sdd-* skill files are optional registry assets, not requirements.';
161
161
  const subagentData = {
162
162
  'vgxness-sdd-explore': { seedDescription: 'Investigates codebase context and identifies options before proposals.', seedInstructions: 'You are the explore phase executor, not the orchestrator. Do not delegate. Explore repository evidence for the requested SDD change. Do not implement code changes. Return concise findings, risks, and recommended next artifacts.', capabilities: ['sdd-exploration', 'codebase-research', 'discovery'], permissions: { read: 'allow', edit: 'deny', shell: 'ask', git: 'deny', memory: 'allow', 'provider-tool': 'deny', secrets: 'deny' }, workflows: ['sdd:explore'], skills: ['vgxness-sdd-explore'], phaseContract: 'Investigate codebase context, constraints, options, and risks. Do not implement code changes. Return findings and recommended next artifacts.' },
@@ -1,3 +1,5 @@
1
+ import { canonicalPromptContractVersion } from '../canonical-agent-manifest.js';
2
+ import { canonicalBehaviorContractVersion } from '../../behavior/behavior-contract-manifest.js';
1
3
  import { ok, validationFailure } from './provider-adapter.js';
2
4
  const previewWarnings = [
3
5
  'Claude rendering returns installable preview artifacts only; it does not install and does not write provider configuration.',
@@ -66,7 +68,7 @@ export class ClaudeAgentRenderer {
66
68
  }
67
69
  }
68
70
  function renderClaudeAgentMarkdown(agent, key) {
69
- return `---\nname: ${JSON.stringify(key)}\ndescription: ${JSON.stringify(agent.description)}\n---\n\n<!-- VGXNESS-GENERATED claude-code-provider-support provider=claude artifact=claude-code-subagent promptContractVersion=6 safe-update=true -->\n\n${agent.instructions.value.trim()}\n`;
71
+ return `---\nname: ${JSON.stringify(key)}\ndescription: ${JSON.stringify(agent.description)}\n---\n\n<!-- VGXNESS-GENERATED claude-code-provider-support provider=claude artifact=claude-code-subagent promptContractVersion=${canonicalPromptContractVersion} behaviorContractVersion=${canonicalBehaviorContractVersion} safe-update=true -->\n\n${agent.instructions.value.trim()}\n`;
70
72
  }
71
73
  function claudeAgentKey(value) {
72
74
  return pathSegment(value);
@@ -1,3 +1,4 @@
1
+ import { behaviorContractProjectionMetadata } from '../../behavior/behavior-contract-manifest.js';
1
2
  import { ok, validationFailure } from './provider-adapter.js';
2
3
  const openCodeSchema = 'https://opencode.ai/config.json';
3
4
  const previewWarning = 'Rendering returns preview artifacts only; it does not install or write .opencode/, .claude/, or provider configuration.';
@@ -50,7 +51,7 @@ export class OpenCodeAgentRenderer {
50
51
  const artifact = {
51
52
  relativePath: `rendered/opencode/${pathSegment(input.agent.project)}/${input.agent.scope}/${pathSegment(input.agent.name)}/opencode.json`,
52
53
  contentType: 'application/json',
53
- contents: `${JSON.stringify({ $schema: openCodeSchema, agent: renderedAgents, safety: previewSafety }, null, 2)}\n`,
54
+ contents: `${JSON.stringify({ $schema: openCodeSchema, behaviorContract: behaviorContractProjectionMetadata, agent: renderedAgents, safety: previewSafety }, null, 2)}\n`,
54
55
  };
55
56
  return ok({
56
57
  provider: this.provider,
@@ -0,0 +1,42 @@
1
+ export const canonicalBehaviorContractName = 'vgxness-manager-behavior-contract';
2
+ export const canonicalBehaviorContractVersion = '1.0.0';
3
+ export const criticalBehaviorContractInvariantIds = [
4
+ 'sdd.acceptance.human-only',
5
+ 'sdd.draft-is-not-accepted',
6
+ 'sdd.readiness-before-advance',
7
+ 'provider.preview-status-doctor-readonly',
8
+ 'provider.config-writes-explicit-consent',
9
+ 'run.risky-effects-preflight',
10
+ 'delegation.deny-by-default',
11
+ 'delegation.no-wildcard',
12
+ 'context.manager-compact-default',
13
+ 'context.progressive-disclosure',
14
+ 'flow.provider-native-no-terminal-sdd-daily',
15
+ 'scope.exclude-vgxcode-runtime',
16
+ 'worktree.preserve-unrelated-user-work',
17
+ ];
18
+ export const behaviorContractManifest = {
19
+ name: canonicalBehaviorContractName,
20
+ contractVersion: canonicalBehaviorContractVersion,
21
+ excludedTargets: ['vgxcode', 'src/code/runtime/*', 'src/code/prompts/*'],
22
+ invariants: [
23
+ { id: 'sdd.acceptance.human-only', category: 'sdd', severity: 'critical', summary: 'SDD acceptance is recorded only from explicit human acceptance.' },
24
+ { id: 'sdd.draft-is-not-accepted', category: 'sdd', severity: 'critical', summary: 'Draft, rejected, superseded, legacy, or unaccepted artifacts are not accepted prerequisites.' },
25
+ { id: 'sdd.readiness-before-advance', category: 'sdd', severity: 'critical', summary: 'Phase advancement checks readiness/status before treating prerequisites as satisfied.' },
26
+ { id: 'provider.preview-status-doctor-readonly', category: 'provider', severity: 'critical', summary: 'Preview, status, and doctor surfaces are read-only and do not write provider configuration.' },
27
+ { id: 'provider.config-writes-explicit-consent', category: 'provider', severity: 'critical', summary: 'Provider configuration writes require explicit user consent through confirmed flows.' },
28
+ { id: 'run.risky-effects-preflight', category: 'run', severity: 'critical', summary: 'Risky edits, shell, git, provider, secret, destructive, privileged, or ambiguous effects require preflight.' },
29
+ { id: 'delegation.deny-by-default', category: 'delegation', severity: 'critical', summary: 'Delegation defaults to deny unless an exact governed path allows it.' },
30
+ { id: 'delegation.no-wildcard', category: 'delegation', severity: 'critical', summary: 'Wildcard delegation is not allowed; exact canonical subagents must be used.' },
31
+ { id: 'context.manager-compact-default', category: 'context', severity: 'critical', summary: 'Manager-facing context defaults to compact payloads.' },
32
+ { id: 'context.progressive-disclosure', category: 'context', severity: 'critical', summary: 'Expanded and verbose context are requested only when needed.' },
33
+ { id: 'flow.provider-native-no-terminal-sdd-daily', category: 'flow', severity: 'critical', summary: 'Daily SDD progression happens provider-natively through conversation and MCP, not mandatory terminal phase commands.' },
34
+ { id: 'scope.exclude-vgxcode-runtime', category: 'scope', severity: 'critical', summary: 'This behavior contract excludes vgxcode and src/code runtime/prompt implementation targets.' },
35
+ { id: 'worktree.preserve-unrelated-user-work', category: 'worktree', severity: 'critical', summary: 'Unrelated user work and dirty files are preserved.' },
36
+ ],
37
+ };
38
+ export const behaviorContractProjectionMetadata = {
39
+ behaviorContractName: canonicalBehaviorContractName,
40
+ behaviorContractVersion: canonicalBehaviorContractVersion,
41
+ criticalInvariantIds: criticalBehaviorContractInvariantIds,
42
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,42 @@
1
+ import { behaviorContractManifest, criticalBehaviorContractInvariantIds } from './behavior-contract-manifest.js';
2
+ export function validateBehaviorContractManifest(manifest = behaviorContractManifest) {
3
+ const errors = [];
4
+ if (!manifest.name.trim())
5
+ errors.push('behavior contract name is required');
6
+ if (!manifest.contractVersion.trim())
7
+ errors.push('behavior contract version is required');
8
+ const seen = new Set();
9
+ for (const invariant of manifest.invariants) {
10
+ if (!invariant.id.trim())
11
+ errors.push('invariant id is required');
12
+ if (seen.has(invariant.id))
13
+ errors.push(`duplicate invariant id: ${invariant.id}`);
14
+ seen.add(invariant.id);
15
+ if (!invariant.summary.trim())
16
+ errors.push(`invariant ${invariant.id} summary is required`);
17
+ }
18
+ for (const id of criticalBehaviorContractInvariantIds) {
19
+ const invariant = manifest.invariants.find((candidate) => candidate.id === id);
20
+ if (invariant === undefined)
21
+ errors.push(`missing critical invariant: ${id}`);
22
+ else if (invariant.severity !== 'critical')
23
+ errors.push(`critical invariant ${id} must have severity critical`);
24
+ }
25
+ for (const target of ['vgxcode', 'src/code/runtime/*', 'src/code/prompts/*']) {
26
+ if (!manifest.excludedTargets.includes(target))
27
+ errors.push(`missing excluded target: ${target}`);
28
+ }
29
+ return { ok: errors.length === 0, errors };
30
+ }
31
+ export function validateBehaviorContractProjection(metadata, manifest = behaviorContractManifest) {
32
+ const errors = [];
33
+ if (metadata.behaviorContractName !== manifest.name)
34
+ errors.push(`behavior contract name mismatch: ${metadata.behaviorContractName}`);
35
+ if (metadata.behaviorContractVersion !== manifest.contractVersion)
36
+ errors.push(`behavior contract version mismatch: ${metadata.behaviorContractVersion}`);
37
+ for (const id of criticalBehaviorContractInvariantIds) {
38
+ if (!metadata.criticalInvariantIds.includes(id))
39
+ errors.push(`projection missing critical invariant reference: ${id}`);
40
+ }
41
+ return { ok: errors.length === 0, errors };
42
+ }
@@ -0,0 +1,272 @@
1
+ import { ContextBudgetService } from '../payload/context-budget-service.js';
2
+ export const contextCockpitSnapshotLevels = ['compact', 'expanded', 'verbose'];
3
+ export class ContextCockpitSnapshotService {
4
+ dependencies;
5
+ budget;
6
+ constructor(dependencies) {
7
+ this.dependencies = dependencies;
8
+ this.budget = dependencies.budget ?? new ContextBudgetService();
9
+ }
10
+ build(input) {
11
+ const level = input.level ?? 'compact';
12
+ const legacyInput = {
13
+ project: input.project,
14
+ ...(input.directory === undefined ? {} : { directory: input.directory }),
15
+ ...(input.limit === undefined ? {} : { limit: input.limit }),
16
+ };
17
+ const legacy = this.dependencies.memory.getContextCockpit(legacyInput);
18
+ if (!legacy.ok)
19
+ return legacy;
20
+ const sddResult = input.change === undefined ? undefined : this.buildSddSection({ project: input.project, change: input.change }, level);
21
+ if (sddResult !== undefined && !sddResult.ok)
22
+ return sddResult;
23
+ const sdd = sddResult?.value;
24
+ const integratesSdd = sdd !== undefined;
25
+ const optionalSectionsOmitted = omittedSections(legacy.value.optionalSectionsOmitted, integratesSdd ? ['provider'] : ['sdd', 'provider'], integratesSdd ? ['sdd'] : []);
26
+ const snapshotWithoutBudget = {
27
+ ...legacy.value,
28
+ optionalSectionsOmitted,
29
+ ...(sdd === undefined ? {} : { sdd }),
30
+ snapshotVersion: 2,
31
+ level,
32
+ references: [
33
+ {
34
+ id: 'legacy-context-cockpit',
35
+ kind: 'legacy-context-cockpit',
36
+ description: 'Wrapped output from the existing no-trace context cockpit path.',
37
+ },
38
+ ],
39
+ warnings: [
40
+ ...(integratesSdd ? [] : ['sdd-snapshot-omitted:no-change']),
41
+ 'provider-snapshot-omitted:no-workspace-root',
42
+ ],
43
+ safety: {
44
+ ...legacy.value.safety,
45
+ readOnly: true,
46
+ recordsTraces: false,
47
+ noTrace: true,
48
+ mutatesSessions: false,
49
+ noSessionMutation: true,
50
+ mutatesMemories: false,
51
+ noMemoryMutation: true,
52
+ mutatesArtifacts: false,
53
+ noArtifactMutation: true,
54
+ mutatesRuns: false,
55
+ noCheckpoints: true,
56
+ writesProviderConfig: false,
57
+ noProviderConfigWrites: true,
58
+ mutatesRepository: false,
59
+ executesProvider: false,
60
+ mutatesProviderConfig: false,
61
+ createsRun: false,
62
+ createsCheckpoint: false,
63
+ recordsTimelineEvent: false,
64
+ integratesSdd,
65
+ integratesProvider: false,
66
+ },
67
+ };
68
+ const report = this.budget.reportJson(budgetIdForLevel(level), snapshotWithoutBudget);
69
+ return {
70
+ ok: true,
71
+ value: {
72
+ ...snapshotWithoutBudget,
73
+ budget: {
74
+ level,
75
+ policy: budgetIdForLevel(level),
76
+ report,
77
+ memoryPreviewLimit: input.limit ?? legacy.value.memoryPreviews.length,
78
+ includesSdd: integratesSdd,
79
+ includesProvider: false,
80
+ omittedSections: [
81
+ ...(integratesSdd ? [] : ['sdd']),
82
+ 'provider',
83
+ 'runs',
84
+ 'memory-content',
85
+ 'session-transcripts',
86
+ 'provider-config-contents',
87
+ 'run-checkpoint-details',
88
+ ],
89
+ heavyContentPolicy: 'references-only',
90
+ notes: ['Budget measured with ContextBudgetService.reportJson before adding the final budget section.'],
91
+ },
92
+ },
93
+ };
94
+ }
95
+ buildSddSection(input, level) {
96
+ if (this.dependencies.sdd === undefined) {
97
+ return { ok: false, error: { code: 'validation_failed', message: 'SDD cockpit service is not available' } };
98
+ }
99
+ const cockpit = this.dependencies.sdd.getCockpit(input);
100
+ if (!cockpit.ok)
101
+ return cockpit;
102
+ return { ok: true, value: toSddSection(cockpit.value, level) };
103
+ }
104
+ }
105
+ function toSddSection(cockpit, level) {
106
+ switch (level) {
107
+ case 'compact':
108
+ return toCompactSddSection(cockpit);
109
+ case 'expanded':
110
+ return toExpandedSddSection(cockpit);
111
+ case 'verbose':
112
+ return toVerboseSddSection(cockpit);
113
+ }
114
+ }
115
+ function toCompactSddSection(cockpit) {
116
+ return {
117
+ projection: 'compact',
118
+ project: cockpit.project,
119
+ change: cockpit.change,
120
+ recommendedAction: cockpit.recommendedAction,
121
+ ...(cockpit.actionablePhase === undefined ? {} : { actionablePhase: cockpit.actionablePhase }),
122
+ next: {
123
+ status: cockpit.next.status,
124
+ ...(cockpit.next.nextPhase === undefined ? {} : { nextPhase: cockpit.next.nextPhase }),
125
+ reason: cockpit.next.reason,
126
+ },
127
+ phases: cockpit.phases.map((phase) => ({
128
+ phase: phase.phase,
129
+ topicKey: phase.topicKey,
130
+ present: phase.present,
131
+ accepted: phase.accepted,
132
+ legacy: phase.legacy,
133
+ state: phase.state,
134
+ readinessReady: phase.readiness.ready,
135
+ blockerCount: phase.blockers.length,
136
+ })),
137
+ counts: {
138
+ phases: cockpit.phases.length,
139
+ artifacts: cockpit.artifacts.length,
140
+ accepted: cockpit.acceptedCount,
141
+ legacy: cockpit.legacyCount,
142
+ blockers: cockpit.aggregateBlockers.length,
143
+ },
144
+ };
145
+ }
146
+ function toExpandedSddSection(cockpit) {
147
+ return {
148
+ projection: 'expanded',
149
+ project: cockpit.project,
150
+ change: cockpit.change,
151
+ recommendedAction: cockpit.recommendedAction,
152
+ ...(cockpit.actionablePhase === undefined ? {} : { actionablePhase: cockpit.actionablePhase }),
153
+ next: {
154
+ status: cockpit.next.status,
155
+ ...(cockpit.next.nextPhase === undefined ? {} : { nextPhase: cockpit.next.nextPhase }),
156
+ reason: cockpit.next.reason,
157
+ },
158
+ phases: cockpit.phases.map(toExpandedSddPhase),
159
+ counts: {
160
+ phases: cockpit.phases.length,
161
+ artifacts: cockpit.artifacts.length,
162
+ accepted: cockpit.acceptedCount,
163
+ legacy: cockpit.legacyCount,
164
+ blockers: cockpit.aggregateBlockers.length,
165
+ },
166
+ blockers: cockpit.aggregateBlockers.map(toSddBlocker),
167
+ };
168
+ }
169
+ function toVerboseSddSection(cockpit) {
170
+ return {
171
+ projection: 'verbose',
172
+ project: cockpit.project,
173
+ change: cockpit.change,
174
+ recommendedAction: cockpit.recommendedAction,
175
+ ...(cockpit.actionablePhase === undefined ? {} : { actionablePhase: cockpit.actionablePhase }),
176
+ next: {
177
+ status: cockpit.next.status,
178
+ ...(cockpit.next.nextPhase === undefined ? {} : { nextPhase: cockpit.next.nextPhase }),
179
+ reason: cockpit.next.reason,
180
+ },
181
+ phases: cockpit.phases.map(toExpandedSddPhase),
182
+ counts: {
183
+ phases: cockpit.phases.length,
184
+ artifacts: cockpit.artifacts.length,
185
+ accepted: cockpit.acceptedCount,
186
+ legacy: cockpit.legacyCount,
187
+ blockers: cockpit.aggregateBlockers.length,
188
+ },
189
+ blockers: cockpit.aggregateBlockers.map(toSddBlocker),
190
+ artifacts: cockpit.artifacts.map(toArtifactMetadata),
191
+ };
192
+ }
193
+ function toExpandedSddPhase(phase) {
194
+ return {
195
+ phase: phase.phase,
196
+ topicKey: phase.topicKey,
197
+ present: phase.present,
198
+ accepted: phase.accepted,
199
+ legacy: phase.legacy,
200
+ state: phase.state,
201
+ readinessReady: phase.readiness.ready,
202
+ blockerCount: phase.blockers.length,
203
+ readiness: toReadinessMetadata(phase.readiness),
204
+ ...(phase.artifact === undefined ? {} : { artifact: toArtifactMetadata(phase.artifact) }),
205
+ blockers: phase.blockers.map(toSddBlocker),
206
+ };
207
+ }
208
+ function toReadinessMetadata(readiness) {
209
+ return {
210
+ change: readiness.change,
211
+ phase: readiness.phase,
212
+ ready: readiness.ready,
213
+ satisfiedPrerequisites: readiness.satisfiedPrerequisites,
214
+ missingArtifactTopicKeys: readiness.missingArtifactTopicKeys,
215
+ blockedPrerequisites: (readiness.blockedPrerequisites ?? []).map(toPrerequisiteBlocker),
216
+ };
217
+ }
218
+ function toPrerequisiteBlocker(blocker) {
219
+ return {
220
+ phase: blocker.phase,
221
+ topicKey: blocker.topicKey,
222
+ reason: blocker.reason,
223
+ ...(blocker.artifactId === undefined ? {} : { artifactId: blocker.artifactId }),
224
+ };
225
+ }
226
+ function toArtifactMetadata(artifact) {
227
+ return {
228
+ phase: artifact.phase,
229
+ topicKey: artifact.topicKey,
230
+ present: artifact.present,
231
+ accepted: artifact.accepted,
232
+ legacy: artifact.legacy,
233
+ state: artifact.state,
234
+ ...(artifact.artifactId === undefined ? {} : { artifactId: artifact.artifactId }),
235
+ ...(artifact.createdAt === undefined ? {} : { createdAt: artifact.createdAt }),
236
+ ...(artifact.updatedAt === undefined ? {} : { updatedAt: artifact.updatedAt }),
237
+ ...(artifact.acceptance === undefined ? {} : { acceptance: toAcceptanceMetadata(artifact.acceptance) }),
238
+ };
239
+ }
240
+ function toAcceptanceMetadata(acceptance) {
241
+ return {
242
+ actor: {
243
+ type: acceptance.actor.type,
244
+ id: acceptance.actor.id,
245
+ ...(acceptance.actor.displayName === undefined ? {} : { displayName: acceptance.actor.displayName }),
246
+ },
247
+ acceptedAt: acceptance.acceptedAt,
248
+ };
249
+ }
250
+ function toSddBlocker(blocker) {
251
+ return {
252
+ kind: blocker.kind,
253
+ phase: blocker.phase,
254
+ topicKey: blocker.topicKey,
255
+ reason: blocker.reason,
256
+ ...(blocker.artifactId === undefined ? {} : { artifactId: blocker.artifactId }),
257
+ };
258
+ }
259
+ function budgetIdForLevel(level) {
260
+ switch (level) {
261
+ case 'compact':
262
+ return 'snapshotCompact';
263
+ case 'expanded':
264
+ return 'snapshotExpanded';
265
+ case 'verbose':
266
+ return 'subagentVerbosePayload';
267
+ }
268
+ }
269
+ function omittedSections(legacy, required, resolved = []) {
270
+ const resolvedSet = new Set(resolved);
271
+ return [...new Set([...legacy, ...required])].filter((section) => !resolvedSet.has(section));
272
+ }
@@ -12,6 +12,7 @@ import { SddWorkflowService } from '../sdd/sdd-workflow-service.js';
12
12
  import { SkillRegistryService } from '../skills/skill-registry-service.js';
13
13
  import { VerificationPlanService } from '../verification/index.js';
14
14
  import { ProviderChangePlanService } from './provider-change-plan.js';
15
+ import { ContextCockpitSnapshotService } from './control-plane-snapshot-service.js';
15
16
  import { ProviderDoctorService } from './provider-doctor.js';
16
17
  import { ProviderStatusService } from './provider-status.js';
17
18
  import { errorEnvelope, successEnvelope, } from './schema.js';
@@ -64,7 +65,7 @@ export function callVgxTool(call, services) {
64
65
  case 'vgxness_session_restore':
65
66
  return toEnvelope(validated.tool, services.memory.restoreSession(validated.input));
66
67
  case 'vgxness_context_cockpit':
67
- return toEnvelope(validated.tool, services.memory.getContextCockpit(validated.input));
68
+ return toEnvelope(validated.tool, new ContextCockpitSnapshotService({ memory: services.memory, sdd: services.sdd }).build(validated.input));
68
69
  case 'vgxness_agent_resolve':
69
70
  return toEnvelope(validated.tool, services.agents.resolveAgents(validated.input));
70
71
  case 'vgxness_agent_activate':
package/dist/mcp/index.js CHANGED
@@ -13,6 +13,7 @@ export * from './claude-code-scope.js';
13
13
  export * from './claude-code-user-config.js';
14
14
  export * from './claude-code-user-memory.js';
15
15
  export * from './control-plane.js';
16
+ export * from './control-plane-snapshot-service.js';
16
17
  export * from './doctor.js';
17
18
  export * from './opencode-visibility.js';
18
19
  export * from './opencode-handoff-preview.js';
@@ -99,6 +99,7 @@ const runStatuses = ['created', 'planned', 'running', 'needs-human', 'completed'
99
99
  const finalRunStatuses = ['completed', 'failed', 'blocked', 'cancelled'];
100
100
  const runOutcomes = ['success', 'partial', 'failure', 'blocked', 'cancelled'];
101
101
  const payloadModes = ['compact', 'verbose'];
102
+ const contextCockpitLevels = ['compact', 'expanded', 'verbose'];
102
103
  const providerChangePlanProviders = ['opencode', 'claude', 'antigravity', 'custom'];
103
104
  const providerChangePlanTypes = ['opencode-mcp-install', 'claude-mcp-install', 'setup', 'install', 'config-preparation'];
104
105
  const jsonValueSchema = z.lazy(() => z.union([z.string(), z.number().finite(), z.boolean(), z.null(), z.array(jsonValueSchema), z.record(z.string(), jsonValueSchema)]));
@@ -264,8 +265,10 @@ export const VGX_MCP_TOOL_INPUT_SCHEMAS = {
264
265
  vgxness_context_cockpit: z
265
266
  .object({
266
267
  project: z.string().min(1),
268
+ change: z.string().min(1).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/).optional(),
267
269
  directory: z.string().min(1).optional(),
268
270
  limit: z.number().int().min(1).max(100).optional(),
271
+ level: z.enum(contextCockpitLevels).optional(),
269
272
  })
270
273
  .passthrough(),
271
274
  vgxness_agent_resolve: z
@@ -13,6 +13,7 @@ const finalRunStatuses = ['completed', 'failed', 'blocked', 'cancelled'];
13
13
  const runOutcomes = ['success', 'partial', 'failure', 'blocked', 'cancelled'];
14
14
  const permissionDecisions = ['allow', 'ask', 'deny'];
15
15
  const payloadModes = ['compact', 'verbose'];
16
+ const contextCockpitLevels = ['compact', 'expanded', 'verbose'];
16
17
  const providerChangePlanProviders = ['opencode', 'claude', 'antigravity', 'custom'];
17
18
  const providerChangePlanTypes = ['opencode-mcp-install', 'claude-mcp-install', 'setup', 'install', 'config-preparation'];
18
19
  const validChangePattern = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
@@ -238,13 +239,18 @@ function validateSddCockpitInput(input, tool) {
238
239
  return readProjectAndChange(record.value, tool);
239
240
  }
240
241
  function validateContextCockpitInput(input, tool) {
241
- const record = inputRecord(input, tool, ['project', 'directory', 'limit']);
242
+ const record = inputRecord(input, tool, ['project', 'change', 'directory', 'limit', 'level']);
242
243
  if (!record.ok)
243
244
  return record;
244
245
  const project = readNonEmptyString(record.value, 'project', tool);
245
246
  if (!project.ok)
246
247
  return project;
247
248
  const result = { project: project.value };
249
+ const change = readOptionalChange(record.value, tool);
250
+ if (!change.ok)
251
+ return change;
252
+ if (change.value !== undefined)
253
+ result.change = change.value;
248
254
  const directory = readOptionalNonEmptyString(record.value, 'directory', tool);
249
255
  if (!directory.ok)
250
256
  return directory;
@@ -255,6 +261,11 @@ function validateContextCockpitInput(input, tool) {
255
261
  return validationFailure('limit must be an integer between 1 and 100', tool);
256
262
  result.limit = record.value.limit;
257
263
  }
264
+ const level = readOptionalOneOf(record.value, 'level', contextCockpitLevels, tool);
265
+ if (!level.ok)
266
+ return level;
267
+ if (level.value !== undefined)
268
+ result.level = level.value;
258
269
  return { ok: true, value: result };
259
270
  }
260
271
  function readProjectAndChange(record, tool) {
@@ -0,0 +1,17 @@
1
+ export const defaultContextBudgetPolicy = {
2
+ policyVersion: '1.0.0',
3
+ limits: [
4
+ { id: 'managerPromptBase', label: 'Manager prompt base', targetBytes: 16_384, hardLimitBytes: 24_576, enforcement: 'warn' },
5
+ { id: 'managerInitialPayload', label: 'Manager initial payload', targetBytes: 12_288, hardLimitBytes: 18_432, enforcement: 'warn' },
6
+ { id: 'snapshotCompact', label: 'Compact snapshot', targetBytes: 10_240, hardLimitBytes: 15_360, enforcement: 'warn' },
7
+ { id: 'snapshotExpanded', label: 'Expanded snapshot', targetBytes: 30_720, hardLimitBytes: 46_080, enforcement: 'report' },
8
+ { id: 'subagentVerbosePayload', label: 'Subagent verbose payload', targetBytes: 122_880, hardLimitBytes: 184_320, enforcement: 'report' },
9
+ { id: 'initialMcpCalls', label: 'Initial MCP calls', targetBytes: 3, hardLimitBytes: 5, enforcement: 'report' },
10
+ ],
11
+ };
12
+ export function getContextBudgetLimit(policy, id) {
13
+ const limit = policy.limits.find((candidate) => candidate.id === id);
14
+ if (limit === undefined)
15
+ throw new Error(`Unknown context budget id: ${id}`);
16
+ return limit;
17
+ }
@@ -0,0 +1,44 @@
1
+ import { utf8ByteCount } from './payload-summary.js';
2
+ import { defaultContextBudgetPolicy, getContextBudgetLimit } from './context-budget-policy.js';
3
+ export class ContextBudgetService {
4
+ policy;
5
+ constructor(policy = defaultContextBudgetPolicy) {
6
+ this.policy = policy;
7
+ }
8
+ measureUtf8Bytes(content) {
9
+ return utf8ByteCount(content);
10
+ }
11
+ measureJsonBytes(value) {
12
+ return utf8ByteCount(JSON.stringify(value));
13
+ }
14
+ reportContent(id, content) {
15
+ return this.buildReport(id, this.measureUtf8Bytes(content));
16
+ }
17
+ reportJson(id, value) {
18
+ return this.buildReport(id, this.measureJsonBytes(value));
19
+ }
20
+ buildReport(id, measuredBytes) {
21
+ if (!Number.isSafeInteger(measuredBytes) || measuredBytes < 0)
22
+ throw new RangeError('measuredBytes must be a non-negative safe integer');
23
+ const budget = getContextBudgetLimit(this.policy, id);
24
+ const excessTargetBytes = Math.max(0, measuredBytes - budget.targetBytes);
25
+ const excessHardLimitBytes = Math.max(0, measuredBytes - budget.hardLimitBytes);
26
+ return {
27
+ policyVersion: this.policy.policyVersion,
28
+ budget,
29
+ measuredBytes,
30
+ withinTarget: excessTargetBytes === 0,
31
+ withinHardLimit: excessHardLimitBytes === 0,
32
+ excessTargetBytes,
33
+ excessHardLimitBytes,
34
+ recommendations: budgetRecommendations(budget, excessTargetBytes, excessHardLimitBytes),
35
+ };
36
+ }
37
+ }
38
+ function budgetRecommendations(budget, excessTargetBytes, excessHardLimitBytes) {
39
+ if (excessHardLimitBytes > 0)
40
+ return [`Reduce ${budget.label} below hard limit by at least ${excessHardLimitBytes} bytes.`, 'Move full content behind references or verbose-only retrieval.'];
41
+ if (excessTargetBytes > 0)
42
+ return [`Reduce ${budget.label} toward target by ${excessTargetBytes} bytes.`, 'Prefer compact summaries and progressive disclosure.'];
43
+ return [];
44
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vgxness",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
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": {