vgxness 1.5.0 → 1.5.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.
@@ -63,6 +63,8 @@ export function callVgxTool(call, services) {
63
63
  return toEnvelope(validated.tool, services.memory.closeSession(validated.input, memoryContext(validated.input.sessionId)));
64
64
  case 'vgxness_session_restore':
65
65
  return toEnvelope(validated.tool, services.memory.restoreSession(validated.input));
66
+ case 'vgxness_context_cockpit':
67
+ return toEnvelope(validated.tool, services.memory.getContextCockpit(validated.input));
66
68
  case 'vgxness_agent_resolve':
67
69
  return toEnvelope(validated.tool, services.agents.resolveAgents(validated.input));
68
70
  case 'vgxness_agent_activate':
@@ -1,5 +1,5 @@
1
1
  export const vgxnessOpenCodeDefaultAgent = 'vgxness-manager';
2
- export const vgxnessOpenCodePromptContractVersion = 4;
2
+ export const vgxnessOpenCodePromptContractVersion = 6;
3
3
  export const vgxnessOpenCodeInstructionsPath = 'AGENTS.md';
4
4
  export const vgxnessOpenCodeSddSubagents = [
5
5
  'vgxness-sdd-explore',
@@ -65,7 +65,7 @@ export function createOpenCodeDefaultAgentConfig() {
65
65
  }
66
66
  function createSddSubagentPrompt(name) {
67
67
  const phase = name.replace('vgxness-sdd-', '');
68
- const common = `You are the VGXNESS SDD ${phase} executor, not the orchestrator. Do this phase's work yourself. Do NOT delegate, do NOT call task/delegate, and do NOT launch sub-agents. Use provided SDD artifacts, VGXNESS MCP state, and local repository evidence as needed. Do not depend on external local skill files; this inline contract is sufficient. Preserve unrelated user work, keep output concise, and report evidence.`;
68
+ const common = `You are the VGXNESS SDD ${phase} executor, not the orchestrator. Do this phase's work yourself. Do NOT delegate, do NOT call task/delegate, and do NOT launch sub-agents. Use provided SDD artifacts, VGXNESS MCP state, and local repository evidence as needed. Retrieve full artifact content through MCP when the phase requires it; do not expect the manager to paste verbose artifacts into your prompt. Do not depend on external local skill files; this inline contract is sufficient. Preserve unrelated user work, keep output concise, and report evidence.`;
69
69
  const contracts = {
70
70
  'vgxness-sdd-explore': 'Investigate codebase context, constraints, options, and risks. Do not implement code changes. Return findings and recommended next artifacts.',
71
71
  'vgxness-sdd-propose': 'Create or refine a focused SDD proposal from exploration evidence. Do not implement code changes. Include scope, tradeoffs, non-goals, and acceptance direction.',
@@ -102,8 +102,8 @@ Coach while coordinating: teach briefly when helpful, explain practical tradeoff
102
102
  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.
103
103
 
104
104
  ## MCP playbook
105
- - For starting, resuming, or recovering context: \`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.
106
- - SDD artifacts: list/read with \`vgxness_sdd_get_artifact\`/\`vgxness_sdd_list_artifacts\`; save phase output with \`vgxness_sdd_save_artifact\` only after the appropriate flow. SDD artifacts are not generic memory.
105
+ - 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.
106
+ - 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.
107
107
  - 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.
108
108
  - 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.
109
109
  - 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.
@@ -1,3 +1,4 @@
1
+ import { vgxnessOpenCodePromptContractVersion } from './opencode-default-agent-config.js';
1
2
  export const PROVIDER_HEALTH_SAFETY = {
2
3
  readOnly: true,
3
4
  writesProviderConfig: false,
@@ -29,6 +30,7 @@ export const REQUIRED_PROVIDER_NATIVE_MCP_TOOLS = [
29
30
  'vgxness_memory_search',
30
31
  'vgxness_memory_get',
31
32
  'vgxness_memory_save',
33
+ 'vgxness_context_cockpit',
32
34
  'vgxness_session_restore',
33
35
  'vgxness_session_close',
34
36
  ];
@@ -40,7 +42,7 @@ export function normalizeProviderHealthInput(input) {
40
42
  workspaceRoot: input.workspaceRoot?.trim() || process.cwd(),
41
43
  env: input.env ?? process.env,
42
44
  change: input.change?.trim() ?? '',
43
- expectedPromptContractVersion: input.expectedPromptContractVersion ?? 4,
45
+ expectedPromptContractVersion: input.expectedPromptContractVersion ?? vgxnessOpenCodePromptContractVersion,
44
46
  payloadMode: input.payloadMode ?? 'compact',
45
47
  };
46
48
  }
@@ -21,6 +21,7 @@ export const SUPPORTED_VGX_MCP_TOOL_NAMES = [
21
21
  'vgxness_session_append_activity',
22
22
  'vgxness_session_close',
23
23
  'vgxness_session_restore',
24
+ 'vgxness_context_cockpit',
24
25
  'vgxness_agent_resolve',
25
26
  'vgxness_agent_activate',
26
27
  'vgxness_manager_profile_get',
@@ -60,6 +61,7 @@ export const EXPOSED_VGX_MCP_TOOL_NAMES = [
60
61
  'session_append_activity',
61
62
  'session_close',
62
63
  'session_restore',
64
+ 'context_cockpit',
63
65
  'agent_resolve',
64
66
  'agent_activate',
65
67
  'manager_profile_get',
@@ -257,6 +259,13 @@ export const VGX_MCP_TOOL_INPUT_SCHEMAS = {
257
259
  directory: z.string().min(1).optional(),
258
260
  })
259
261
  .passthrough(),
262
+ vgxness_context_cockpit: z
263
+ .object({
264
+ project: z.string().min(1),
265
+ directory: z.string().min(1).optional(),
266
+ limit: z.number().int().min(1).max(100).optional(),
267
+ })
268
+ .passthrough(),
260
269
  vgxness_agent_resolve: z
261
270
  .object({
262
271
  project: z.string().min(1).optional(),
@@ -59,6 +59,8 @@ function descriptionForTool(publicToolName) {
59
59
  return 'Read-only run resume advisory inspect; plan-only and does not execute resume logic, invoke providers, write provider config, mutate retry/abandon/attempt state, or reconstruct sandboxes, worktrees, sessions, or transcripts.';
60
60
  if (publicToolName === 'run_resume_gate')
61
61
  return 'Read-only run resume gate advisory; plan-only and does not execute resume logic, invoke providers, write provider config, admit retries, abandon or mutate attempts, or reconstruct sandboxes, worktrees, sessions, or transcripts.';
62
+ if (publicToolName === 'context_cockpit')
63
+ return 'Read-only context cockpit for start/resume/recovery; returns latest restorable session plus bounded memory previews without traces, provider config writes, repository writes, runs, artifacts, or session mutations.';
62
64
  if (publicToolName === 'sdd_cockpit')
63
65
  return 'Read-only SDD cockpit summary with next decision, explicit acceptance state, metadata-only artifact summaries, and aggregate blockers.';
64
66
  const toolName = toInternalVgxMcpToolName(publicToolName);
@@ -66,6 +66,8 @@ export function validateVgxMcpToolCall(call) {
66
66
  return validationSuccess(tool.value, validateSessionCloseInput(input, tool.value));
67
67
  case 'vgxness_session_restore':
68
68
  return validationSuccess(tool.value, validateSessionRestoreInput(input, tool.value));
69
+ case 'vgxness_context_cockpit':
70
+ return validationSuccess(tool.value, validateContextCockpitInput(input, tool.value));
69
71
  case 'vgxness_agent_resolve':
70
72
  return validationSuccess(tool.value, validateAgentResolveInput(input, tool.value));
71
73
  case 'vgxness_agent_activate':
@@ -234,6 +236,26 @@ function validateSddCockpitInput(input, tool) {
234
236
  return record;
235
237
  return readProjectAndChange(record.value, tool);
236
238
  }
239
+ function validateContextCockpitInput(input, tool) {
240
+ const record = inputRecord(input, tool, ['project', 'directory', 'limit']);
241
+ if (!record.ok)
242
+ return record;
243
+ const project = readNonEmptyString(record.value, 'project', tool);
244
+ if (!project.ok)
245
+ return project;
246
+ const result = { project: project.value };
247
+ const directory = readOptionalNonEmptyString(record.value, 'directory', tool);
248
+ if (!directory.ok)
249
+ return directory;
250
+ if (directory.value !== undefined)
251
+ result.directory = directory.value;
252
+ if (record.value.limit !== undefined) {
253
+ if (typeof record.value.limit !== 'number' || !Number.isSafeInteger(record.value.limit) || record.value.limit < 1 || record.value.limit > 100)
254
+ return validationFailure('limit must be an integer between 1 and 100', tool);
255
+ result.limit = record.value.limit;
256
+ }
257
+ return { ok: true, value: result };
258
+ }
237
259
  function readProjectAndChange(record, tool) {
238
260
  const project = readNonEmptyString(record, 'project', tool);
239
261
  if (!project.ok)
@@ -50,6 +50,54 @@ export class MemoryService {
50
50
  const result = this.observations.searchPreviews(filters);
51
51
  return this.record(result, context, { operation: 'observation.search', targetType: 'observation', topicKey: filters.topicKey });
52
52
  }
53
+ /** Read memory previews without writing provenance traces. */
54
+ searchObservationPreviewsNoTrace(filters) {
55
+ return this.observations.searchPreviews(filters);
56
+ }
57
+ /** Read compact current context without writing traces or mutating durable state. */
58
+ getContextCockpit(input) {
59
+ const limit = normalizeContextLimit(input.limit);
60
+ const memories = this.searchObservationPreviewsNoTrace({ project: input.project, limit });
61
+ if (!memories.ok)
62
+ return { ok: false, error: memories.error };
63
+ const session = this.restoreSession(input.directory === undefined ? { project: input.project } : { project: input.project, directory: input.directory });
64
+ if (!session.ok && session.error.code !== 'not_found')
65
+ return { ok: false, error: session.error };
66
+ const latestRestorableSession = session.ok ? session.value : undefined;
67
+ const newestMemoryUpdatedAt = memories.value[0]?.updatedAt;
68
+ const latestSessionEndedAt = latestRestorableSession?.endedAt;
69
+ const stale = latestRestorableSession === undefined || (newestMemoryUpdatedAt !== undefined && latestSessionEndedAt !== undefined && newestMemoryUpdatedAt > latestSessionEndedAt);
70
+ const staleness = {
71
+ stale,
72
+ reason: latestRestorableSession === undefined ? 'no-restorable-session' : stale ? 'memory-newer-than-session' : 'current',
73
+ ...(newestMemoryUpdatedAt === undefined ? {} : { newestMemoryUpdatedAt }),
74
+ ...(latestSessionEndedAt === undefined ? {} : { latestSessionEndedAt }),
75
+ };
76
+ return {
77
+ ok: true,
78
+ value: {
79
+ version: 1,
80
+ kind: 'context-cockpit',
81
+ project: input.project,
82
+ ...(input.directory === undefined ? {} : { directory: input.directory }),
83
+ ...(latestRestorableSession === undefined ? {} : { latestRestorableSession }),
84
+ memoryPreviews: memories.value,
85
+ staleness,
86
+ optionalSectionsOmitted: ['sdd', 'runs'],
87
+ notes: ['SDD and run summaries are omitted because safe no-trace metadata-only aggregation is not part of this cockpit path yet.'],
88
+ safety: {
89
+ readOnly: true,
90
+ recordsTraces: false,
91
+ mutatesSessions: false,
92
+ mutatesMemories: false,
93
+ mutatesArtifacts: false,
94
+ mutatesRuns: false,
95
+ writesProviderConfig: false,
96
+ mutatesRepository: false,
97
+ },
98
+ },
99
+ };
100
+ }
53
101
  listObservationRevisions(id, context) {
54
102
  const result = this.observations.listRevisions(id);
55
103
  return this.record(result, context, { operation: 'observation.revisions.list', targetType: 'observation', targetId: id });
@@ -140,3 +188,10 @@ class MemoryServiceTransactionRollback extends Error {
140
188
  super('Memory service transaction rolled back');
141
189
  }
142
190
  }
191
+ function normalizeContextLimit(limit) {
192
+ if (limit === undefined)
193
+ return 5;
194
+ if (!Number.isFinite(limit))
195
+ return 5;
196
+ return Math.max(1, Math.min(100, Math.trunc(limit)));
197
+ }
@@ -39,7 +39,7 @@ export class SessionRepository {
39
39
  AND summary IS NOT NULL
40
40
  AND TRIM(summary) <> ''
41
41
  AND (@directory IS NULL OR directory = @directory)
42
- ORDER BY ended_at DESC
42
+ ORDER BY ended_at DESC, started_at DESC, id DESC
43
43
  LIMIT 1
44
44
  `)
45
45
  .get({ project: input.project, directory: input.directory ?? null });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vgxness",
3
- "version": "1.5.0",
3
+ "version": "1.5.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": {