memorix 1.5.1 → 1.6.0

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.
Files changed (122) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +3 -3
  3. package/README.zh-CN.md +3 -3
  4. package/TEAM.md +86 -86
  5. package/dist/cli/index.js +243 -42
  6. package/dist/cli/memcode.js +0 -0
  7. package/dist/index.js +167 -20
  8. package/dist/maintenance-runner.js +5 -4
  9. package/dist/media-audio-runner.js +5 -4
  10. package/dist/media-video-runner.js +5 -4
  11. package/dist/memcode-runtime/CHANGELOG.md +23 -0
  12. package/dist/sdk.js +166 -19
  13. package/dist/vector-backfill-runner.js +5 -4
  14. package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +1 -1
  15. package/docs/API_REFERENCE.md +1 -1
  16. package/docs/DESIGN_DECISIONS.md +357 -357
  17. package/docs/DEVELOPMENT.md +5 -3
  18. package/package.json +1 -1
  19. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  20. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  21. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  22. package/plugins/copilot/memorix/plugin.json +1 -1
  23. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  24. package/plugins/omp/memorix/package.json +1 -1
  25. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  26. package/plugins/pi/memorix/package.json +1 -1
  27. package/server.json +2 -2
  28. package/src/audit/index.ts +156 -156
  29. package/src/cli/commands/codegraph.ts +48 -5
  30. package/src/cli/commands/context.ts +20 -4
  31. package/src/cli/commands/formation.ts +48 -48
  32. package/src/cli/commands/git-hook-install.ts +111 -111
  33. package/src/cli/commands/handoff.ts +54 -54
  34. package/src/cli/commands/hooks-status.ts +63 -63
  35. package/src/cli/commands/ingest.ts +44 -44
  36. package/src/cli/commands/integrate-shared.ts +15 -15
  37. package/src/cli/commands/lock.ts +82 -82
  38. package/src/cli/commands/message.ts +104 -104
  39. package/src/cli/commands/poll.ts +58 -58
  40. package/src/cli/commands/reasoning.ts +118 -118
  41. package/src/cli/commands/resume.ts +4 -0
  42. package/src/cli/commands/skills.ts +114 -114
  43. package/src/cli/commands/task.ts +167 -167
  44. package/src/cli/commands/transfer.ts +47 -47
  45. package/src/cli/index.ts +406 -406
  46. package/src/cli/tui/ChatView.tsx +234 -234
  47. package/src/cli/tui/CommandBar.tsx +312 -312
  48. package/src/cli/tui/ContextRail.tsx +118 -118
  49. package/src/cli/tui/HeaderBar.tsx +72 -72
  50. package/src/cli/tui/LogoBanner.tsx +51 -51
  51. package/src/cli/tui/index.ts +41 -41
  52. package/src/cli/version.ts +7 -7
  53. package/src/cli/workbench.ts +1 -1
  54. package/src/codegraph/auto-context.ts +4 -1
  55. package/src/codegraph/context-pack.ts +3 -1
  56. package/src/codegraph/external-provider.ts +93 -0
  57. package/src/dashboard/project-classification.ts +64 -64
  58. package/src/git/hooks-path.ts +85 -85
  59. package/src/hooks/installers/index.ts +1 -1
  60. package/src/hooks/official-skills.ts +3 -3
  61. package/src/hooks/pattern-detector.ts +173 -173
  62. package/src/hooks/rules/memorix-agent-rules.md +1 -1
  63. package/src/hooks/significance-filter.ts +250 -250
  64. package/src/knowledge/context-receipt.ts +41 -0
  65. package/src/knowledge/workflows.ts +6 -3
  66. package/src/knowledge/workset.ts +56 -2
  67. package/src/llm/memory-manager.ts +328 -328
  68. package/src/llm/quality.ts +248 -248
  69. package/src/memory/attribution-guard.ts +249 -249
  70. package/src/memory/disclosure-policy.ts +135 -135
  71. package/src/memory/entity-extractor.ts +197 -197
  72. package/src/memory/formation/evaluate.ts +217 -217
  73. package/src/memory/freshness.ts +122 -122
  74. package/src/memory/graph.ts +197 -197
  75. package/src/memory/refs.ts +94 -94
  76. package/src/memory/secret-filter.ts +79 -79
  77. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  78. package/src/orchestrate/adapters/claude.ts +111 -111
  79. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  80. package/src/orchestrate/adapters/codex.ts +41 -41
  81. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  82. package/src/orchestrate/adapters/gemini.ts +42 -42
  83. package/src/orchestrate/adapters/index.ts +73 -73
  84. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  85. package/src/orchestrate/adapters/opencode.ts +47 -47
  86. package/src/orchestrate/adapters/types.ts +77 -77
  87. package/src/orchestrate/capability-router.ts +284 -284
  88. package/src/orchestrate/cost-tracker.ts +219 -219
  89. package/src/orchestrate/error-recovery.ts +191 -191
  90. package/src/orchestrate/evidence.ts +140 -140
  91. package/src/orchestrate/ledger.ts +110 -110
  92. package/src/orchestrate/memorix-bridge.ts +343 -343
  93. package/src/orchestrate/output-budget.ts +80 -80
  94. package/src/orchestrate/permission.ts +152 -152
  95. package/src/orchestrate/pipeline-trace.ts +131 -131
  96. package/src/orchestrate/prompt-builder.ts +155 -155
  97. package/src/orchestrate/ring-buffer.ts +37 -37
  98. package/src/orchestrate/task-graph.ts +389 -389
  99. package/src/project/aliases.ts +374 -374
  100. package/src/rules/adapters/trae.ts +56 -56
  101. package/src/rules/syncer.ts +235 -235
  102. package/src/search/query-expansion.ts +52 -52
  103. package/src/server/formation-timeout.ts +27 -27
  104. package/src/server.ts +15 -3
  105. package/src/skills/mini-skills.ts +386 -386
  106. package/src/store/chat-store.ts +119 -119
  107. package/src/store/graph-store.ts +249 -249
  108. package/src/store/mini-skill-store.ts +349 -349
  109. package/src/store/persistence-json.ts +212 -212
  110. package/src/store/persistence.ts +291 -291
  111. package/src/store/project-affinity.ts +195 -195
  112. package/src/team/event-bus.ts +76 -76
  113. package/src/team/handoff.ts +161 -161
  114. package/src/team/poll.ts +132 -132
  115. package/src/workspace/mcp-adapters/codex.ts +191 -191
  116. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  117. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  118. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  119. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  120. package/src/workspace/mcp-adapters/trae.ts +134 -134
  121. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  122. package/src/workspace/sanitizer.ts +60 -60
package/dist/cli/index.js CHANGED
@@ -3221,7 +3221,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
3221
3221
 
3222
3222
  // src/cli/version.ts
3223
3223
  function getCliVersion() {
3224
- return true ? "1.5.1" : pkg.version;
3224
+ return true ? "1.6.0" : pkg.version;
3225
3225
  }
3226
3226
  var init_version = __esm({
3227
3227
  "src/cli/version.ts"() {
@@ -182078,6 +182078,7 @@ var init_task_lens = __esm({
182078
182078
  var workflows_exports = {};
182079
182079
  __export(workflows_exports, {
182080
182080
  WORKFLOW_ADAPTER_TARGETS: () => WORKFLOW_ADAPTER_TARGETS,
182081
+ WORKFLOW_AGENT_TARGETS: () => WORKFLOW_AGENT_TARGETS,
182081
182082
  applyWorkflowAdapter: () => applyWorkflowAdapter,
182082
182083
  importWindsurfWorkflows: () => importWindsurfWorkflows,
182083
182084
  parseWorkflowMarkdown: () => parseWorkflowMarkdown,
@@ -182143,7 +182144,7 @@ function optionalStatus(data) {
182143
182144
  return value;
182144
182145
  }
182145
182146
  function normalizeAgents(values) {
182146
- const unknown2 = values.filter((value) => !KNOWN_AGENTS.includes(value));
182147
+ const unknown2 = values.filter((value) => !WORKFLOW_AGENT_TARGETS.includes(value));
182147
182148
  if (unknown2.length > 0) {
182148
182149
  throw new Error("workflow frontmatter has unsupported agent: " + unknown2[0]);
182149
182150
  }
@@ -182419,7 +182420,7 @@ function taskScore(workflow, task) {
182419
182420
  return { score, reasons: [...new Set(reasons)] };
182420
182421
  }
182421
182422
  function selectWorkflows(input) {
182422
- const selected = input.workflows.filter((workflow) => workflow.status === "active").map((workflow) => {
182423
+ const selected = input.workflows.filter((workflow) => workflow.status === "active" && (!input.agent || workflow.compatibleAgents.includes(input.agent))).map((workflow) => {
182423
182424
  const match2 = taskScore(workflow, input.task);
182424
182425
  const cautions = input.store && input.projectId ? input.store.recentFailureCautions(input.projectId, workflow.id) : [];
182425
182426
  return {
@@ -182699,7 +182700,7 @@ async function selectWorkspaceWorkflows(input) {
182699
182700
  errors: synced.errors
182700
182701
  };
182701
182702
  }
182702
- var KNOWN_AGENTS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS, GENERIC_WORKFLOW_LENSES, GENERIC_WORKFLOW_TERMS;
182703
+ var WORKFLOW_AGENT_TARGETS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS, GENERIC_WORKFLOW_LENSES, GENERIC_WORKFLOW_TERMS;
182703
182704
  var init_workflows2 = __esm({
182704
182705
  "src/knowledge/workflows.ts"() {
182705
182706
  "use strict";
@@ -182711,7 +182712,7 @@ var init_workflows2 = __esm({
182711
182712
  init_workflow_store();
182712
182713
  init_outcome_store();
182713
182714
  init_task_lens();
182714
- KNOWN_AGENTS = [
182715
+ WORKFLOW_AGENT_TARGETS = [
182715
182716
  "windsurf",
182716
182717
  "cursor",
182717
182718
  "claude-code",
@@ -191131,8 +191132,8 @@ var init_official_skills = __esm({
191131
191132
  "",
191132
191133
  "| Situation | Prefer | CLI fallback |",
191133
191134
  "|---|---|---|",
191134
- '| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --json` |',
191135
- '| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --json` |',
191135
+ '| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --brief-json` |',
191136
+ '| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --brief-json` |',
191136
191137
  '| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
191137
191138
  '| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
191138
191139
  '| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
@@ -191145,7 +191146,7 @@ var init_official_skills = __esm({
191145
191146
  "",
191146
191147
  "- Default first step for non-trivial coding work: call `memorix_project_context` before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Pass the user's actual task so Memorix can choose a bugfix, feature, release, onboarding, refactor, docs, test, or general brief. Start by reading its suggested files.",
191147
191148
  "- In Claude Code headless/print-mode, an initial MCP `pending` status is not a failure by itself. Prefer MCP first: use the client's tool discovery/dynamic loading to find `memorix_project_context` when it is not in the first visible tool list.",
191148
- '- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --json` instead. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
191149
+ '- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --brief-json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --brief-json` instead. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
191149
191150
  "- After a successful `memorix_project_context`, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use Context Pack, search, or detail only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
191150
191151
  "- If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
191151
191152
  "- Use `memorix_search` for a specific decision, bug, file, or prior change that the project context did not answer. Fetch detail only for a result you still need after the brief.",
@@ -192404,7 +192405,7 @@ alwaysApply: true
192404
192405
  "",
192405
192406
  `Default first step for non-trivial coding work: call \`memorix_project_context\` with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). When the task is continuing prior work, the same brief also includes a bounded prior-work projection. Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
192406
192407
  "",
192407
- 'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --json`. For a new task, use `memorix context "<task>" --json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
192408
+ 'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --brief-json`. For a new task, use `memorix context "<task>" --brief-json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
192408
192409
  "",
192409
192410
  "After a successful `memorix_project_context` result, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use `memorix_context_pack`, `memorix_search`, or `memorix_detail` only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
192410
192411
  "If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
@@ -194446,6 +194447,15 @@ function workflowOutput(selection) {
194446
194447
  cautions: selection.cautions.map((caution) => short(caution, 22))
194447
194448
  };
194448
194449
  }
194450
+ function workflowLoadout(agent, selections) {
194451
+ if (!agent) return void 0;
194452
+ return {
194453
+ agent,
194454
+ workflowIds: selections.map((selection) => selection.workflow.id),
194455
+ requiredContext: unique(selections.flatMap((selection) => selection.workflow.requiredContext)).map((item) => short(item, 18)).slice(0, 4),
194456
+ allowedTools: unique(selections.flatMap((selection) => selection.workflow.allowedTools)).map((item) => short(item, 12)).slice(0, 6)
194457
+ };
194458
+ }
194449
194459
  function appendLine(lines, candidate2, maxTokens, omitted, omittedKind, selected, receiptSelection) {
194450
194460
  const next = lines.length ? lines.join("\n") + "\n" + candidate2 : candidate2;
194451
194461
  if (countTextTokens(next) <= maxTokens) {
@@ -194906,6 +194916,22 @@ function renderTaskWorksetPrompt(input) {
194906
194916
  );
194907
194917
  }
194908
194918
  }
194919
+ if (input.agentLoadout) {
194920
+ appendLine(lines, "", maxTokens, omitted, "agent-loadout-heading");
194921
+ appendLine(lines, "Agent loadout (" + input.agentLoadout.agent + ")", maxTokens, omitted, "agent-loadout-heading");
194922
+ for (const required2 of input.agentLoadout.requiredContext.slice(0, 2)) {
194923
+ appendLine(lines, "- Need: " + required2, maxTokens, omitted, "agent-loadout-context");
194924
+ }
194925
+ if (input.agentLoadout.allowedTools.length > 0) {
194926
+ appendLine(
194927
+ lines,
194928
+ "- Workflow tools: " + input.agentLoadout.allowedTools.join(", "),
194929
+ maxTokens,
194930
+ omitted,
194931
+ "agent-loadout-tools"
194932
+ );
194933
+ }
194934
+ }
194909
194935
  if (input.verification.length > 0) {
194910
194936
  appendLine(lines, "", maxTokens, omitted, "verification-heading");
194911
194937
  appendLine(lines, "Verify", maxTokens, omitted, "verification-heading");
@@ -194997,6 +195023,7 @@ async function buildTaskWorkset(input) {
194997
195023
  let workspace;
194998
195024
  let pages = [];
194999
195025
  let workflows = [];
195026
+ let workflowSelections = [];
195000
195027
  try {
195001
195028
  workspace = await preferredWorkspace(input.projectId, input.dataDir);
195002
195029
  if (workspace) {
@@ -195013,14 +195040,15 @@ async function buildTaskWorkset(input) {
195013
195040
  if (task) {
195014
195041
  const workflowStore = new WorkflowStore();
195015
195042
  await workflowStore.init(input.dataDir);
195016
- const selected = selectWorkflows({
195043
+ workflowSelections = selectWorkflows({
195017
195044
  workflows: workflowStore.listWorkflows(workspace.id, "active"),
195018
195045
  task,
195019
195046
  projectId: input.projectId,
195020
195047
  store: workflowStore,
195048
+ ...input.agent ? { agent: input.agent } : {},
195021
195049
  limit: 2
195022
195050
  });
195023
- workflows = selected.map(workflowOutput);
195051
+ workflows = workflowSelections.map(workflowOutput);
195024
195052
  for (const workflow of workflows) {
195025
195053
  for (const caution of workflow.cautions) {
195026
195054
  cautions.push({ kind: "workflow-failed-verification", message: caution });
@@ -195042,6 +195070,10 @@ async function buildTaskWorkset(input) {
195042
195070
  workflows
195043
195071
  });
195044
195072
  const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
195073
+ const agentLoadout = workflowLoadout(
195074
+ input.agent,
195075
+ workflowSelections.filter((selection2) => governed.workflows.some((workflow) => workflow.id === selection2.workflow.id))
195076
+ );
195045
195077
  const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
195046
195078
  claim,
195047
195079
  evidenceByClaim.get(claim.id) ?? []
@@ -195086,6 +195118,7 @@ async function buildTaskWorkset(input) {
195086
195118
  pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
195087
195119
  durableMemory: governed.durableMemory,
195088
195120
  workflows: governed.workflows,
195121
+ ...agentLoadout ? { agentLoadout } : {},
195089
195122
  cautions: normalizedCautions,
195090
195123
  verification,
195091
195124
  evidenceIds,
@@ -195304,10 +195337,12 @@ var init_current_facts = __esm({
195304
195337
  var external_provider_exports = {};
195305
195338
  __export(external_provider_exports, {
195306
195339
  DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
195340
+ EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS: () => EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
195307
195341
  MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES: () => MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES,
195308
195342
  MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
195309
195343
  getExternalCodeGraphContext: () => getExternalCodeGraphContext,
195310
- inspectExternalCodeGraph: () => inspectExternalCodeGraph
195344
+ inspectExternalCodeGraph: () => inspectExternalCodeGraph,
195345
+ runExternalCodeGraphLifecycle: () => runExternalCodeGraphLifecycle
195311
195346
  });
195312
195347
  import { spawn as spawn5 } from "child_process";
195313
195348
  import { existsSync as existsSync16, readFileSync as readFileSync9 } from "fs";
@@ -195506,6 +195541,66 @@ async function inspectExternalCodeGraph(input) {
195506
195541
  const health = healthFromStatus(status);
195507
195542
  return { health, quality: providerQuality({ mode, health }) };
195508
195543
  }
195544
+ async function runExternalCodeGraphLifecycle(input) {
195545
+ const mode = input.mode ?? "auto";
195546
+ if (mode === "off") {
195547
+ const health = { state: "disabled", reason: "External CodeGraph is disabled by configuration." };
195548
+ return {
195549
+ action: input.action,
195550
+ performed: false,
195551
+ message: "External CodeGraph is disabled by configuration.",
195552
+ health,
195553
+ quality: providerQuality({ mode, health })
195554
+ };
195555
+ }
195556
+ const indexPath = join23(input.projectRoot, ".codegraph");
195557
+ if (input.action === "sync" && !existsSync16(indexPath)) {
195558
+ const health = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
195559
+ return {
195560
+ action: input.action,
195561
+ performed: false,
195562
+ message: 'Initialize CodeGraph first with "memorix codegraph init".',
195563
+ health,
195564
+ quality: providerQuality({ mode, health })
195565
+ };
195566
+ }
195567
+ if (input.action === "init" && existsSync16(indexPath)) {
195568
+ const inspected2 = await inspectExternalCodeGraph(input);
195569
+ return {
195570
+ action: input.action,
195571
+ performed: false,
195572
+ message: "A local CodeGraph directory already exists; no initialization was performed.",
195573
+ ...inspected2
195574
+ };
195575
+ }
195576
+ const result = await runSafely(input.runner ?? defaultRunner, {
195577
+ command: input.command,
195578
+ args: input.action === "init" ? ["init", input.projectRoot] : ["sync", input.projectRoot, "--quiet"],
195579
+ cwd: input.projectRoot,
195580
+ // A context read must stay fast; an explicit user-requested index sync is
195581
+ // a different operation and gets its own bounded maintenance window.
195582
+ timeoutMs: EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
195583
+ maxOutputBytes: MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES
195584
+ });
195585
+ if (!result.ok) {
195586
+ const health = unavailableHealth(result);
195587
+ return {
195588
+ action: input.action,
195589
+ performed: false,
195590
+ message: "CodeGraph " + input.action + " did not complete: " + (health.reason ?? "unknown local error"),
195591
+ health,
195592
+ quality: providerQuality({ mode, health })
195593
+ };
195594
+ }
195595
+ const inspected = await inspectExternalCodeGraph(input);
195596
+ const remainsStale = inspected.health.state === "stale";
195597
+ return {
195598
+ action: input.action,
195599
+ performed: true,
195600
+ message: input.action === "init" ? 'Local CodeGraph initialization completed. Run "memorix codegraph sync" when source changes.' : remainsStale ? "Local CodeGraph synchronization completed, but the graph remains stale against the current worktree; this task will use Lite evidence." : "Local CodeGraph synchronization completed and is ready for task-scoped semantic context.",
195601
+ ...inspected
195602
+ };
195603
+ }
195509
195604
  function safeRelativePath(projectRoot, value, exclude) {
195510
195605
  const path47 = safeText(value, 1024);
195511
195606
  if (!path47 || isAbsolute2(path47)) return void 0;
@@ -195631,7 +195726,7 @@ async function getExternalCodeGraphContext(input) {
195631
195726
  quality: providerQuality({ mode, health: inspected.health, ...contributes ? { selected: "external" } : {} })
195632
195727
  };
195633
195728
  }
195634
- var DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES, MAX_EXTERNAL_NODE_COUNT, MAX_EXTERNAL_EDGE_COUNT, MAX_EXTERNAL_FILE_COUNT, MAX_EXTERNAL_TEXT_LENGTH, LITE_SUPPORTED_LANGUAGES, defaultRunner;
195729
+ var DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS, EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES, MAX_EXTERNAL_NODE_COUNT, MAX_EXTERNAL_EDGE_COUNT, MAX_EXTERNAL_FILE_COUNT, MAX_EXTERNAL_TEXT_LENGTH, LITE_SUPPORTED_LANGUAGES, defaultRunner;
195635
195730
  var init_external_provider = __esm({
195636
195731
  "src/codegraph/external-provider.ts"() {
195637
195732
  "use strict";
@@ -195641,6 +195736,7 @@ var init_external_provider = __esm({
195641
195736
  init_ids();
195642
195737
  DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 1200;
195643
195738
  MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 5e3;
195739
+ EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS = 3e4;
195644
195740
  MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES = 256 * 1024;
195645
195741
  MAX_EXTERNAL_NODE_COUNT = 16;
195646
195742
  MAX_EXTERNAL_EDGE_COUNT = 24;
@@ -197363,6 +197459,7 @@ async function buildAutoProjectContext(input) {
197363
197459
  projectId: input.project.id,
197364
197460
  dataDir: input.dataDir,
197365
197461
  ...task ? { task } : {},
197462
+ ...input.agent ? { agent: input.agent } : {},
197366
197463
  lens: lens.id,
197367
197464
  startHere,
197368
197465
  ...alwaysOn.profile.length > 0 || alwaysOn.state || alwaysOn.durable.length > 0 ? { alwaysOn } : {},
@@ -197699,6 +197796,34 @@ var init_auto_context = __esm({
197699
197796
  }
197700
197797
  });
197701
197798
 
197799
+ // src/knowledge/context-receipt.ts
197800
+ var context_receipt_exports = {};
197801
+ __export(context_receipt_exports, {
197802
+ buildBoundedContextReceipt: () => buildBoundedContextReceipt
197803
+ });
197804
+ function buildBoundedContextReceipt(input) {
197805
+ const provider2 = input.providerQuality ?? input.workset.provenance.codeProvider;
197806
+ return {
197807
+ schemaVersion: "1",
197808
+ task: input.workset.task,
197809
+ brief: input.workset.prompt,
197810
+ receipt: input.workset.receipt,
197811
+ code: {
197812
+ selected: provider2?.selected ?? "lite",
197813
+ quality: provider2?.selectedQuality ?? "heuristic",
197814
+ externalState: provider2?.external.state ?? "not-detected",
197815
+ ...input.workset.provenance.snapshotId ? { snapshotId: input.workset.provenance.snapshotId } : {}
197816
+ },
197817
+ ...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {}
197818
+ };
197819
+ }
197820
+ var init_context_receipt = __esm({
197821
+ "src/knowledge/context-receipt.ts"() {
197822
+ "use strict";
197823
+ init_esm_shims();
197824
+ }
197825
+ });
197826
+
197702
197827
  // src/cli/commands/context.ts
197703
197828
  var context_exports = {};
197704
197829
  __export(context_exports, {
@@ -197709,6 +197834,12 @@ function coerceRefreshMode(input) {
197709
197834
  if (value === "always" || value === "never" || value === "auto") return value;
197710
197835
  throw new Error("refresh must be one of: auto, always, never");
197711
197836
  }
197837
+ function coerceAgentTarget(input) {
197838
+ const value = input?.trim().toLowerCase();
197839
+ if (!value) return void 0;
197840
+ if (WORKFLOW_AGENT_TARGETS.includes(value)) return value;
197841
+ throw new Error("agent must be one of: " + WORKFLOW_AGENT_TARGETS.join(", "));
197842
+ }
197712
197843
  var context_default;
197713
197844
  var init_context2 = __esm({
197714
197845
  "src/cli/commands/context.ts"() {
@@ -197718,6 +197849,8 @@ var init_context2 = __esm({
197718
197849
  init_auto_context();
197719
197850
  init_observations();
197720
197851
  init_visibility();
197852
+ init_context_receipt();
197853
+ init_workflows2();
197721
197854
  init_operator_shared();
197722
197855
  context_default = defineCommand({
197723
197856
  meta: {
@@ -197733,10 +197866,12 @@ var init_context2 = __esm({
197733
197866
  },
197734
197867
  resume: { type: "boolean", description: "Always include the bounded prior-work projection" },
197735
197868
  refresh: { type: "string", description: "Project scan policy: auto, always, or never" },
197736
- json: { type: "boolean", description: "Emit machine-readable JSON output" }
197869
+ agent: { type: "string", description: "Optional target agent for compatible workflow selection" },
197870
+ json: { type: "boolean", description: "Emit machine-readable JSON output" },
197871
+ briefJson: { type: "boolean", description: "Emit only the bounded agent brief and receipt JSON" }
197737
197872
  },
197738
197873
  run: async ({ args }) => {
197739
- const asJson = !!args.json;
197874
+ const asJson = !!args.json || !!args.briefJson;
197740
197875
  const task = args.task?.trim() || args.input?.trim() || void 0;
197741
197876
  try {
197742
197877
  const { project, dataDir, reader } = await getCliProjectContext();
@@ -197745,23 +197880,25 @@ var init_context2 = __esm({
197745
197880
  dataDir,
197746
197881
  observations: filterReadableObservations(getAllObservations(), reader),
197747
197882
  task,
197883
+ agent: coerceAgentTarget(args.agent),
197748
197884
  refresh: coerceRefreshMode(args.refresh),
197749
197885
  reader,
197750
197886
  ...args.resume ? { continuation: "always" } : {}
197751
197887
  });
197888
+ const detailed = {
197889
+ project,
197890
+ lens: context.lens,
197891
+ brief: buildAutoProjectBrief(context),
197892
+ currentFacts: context.currentFacts,
197893
+ overview: context.overview,
197894
+ refresh: context.refresh,
197895
+ providerQuality: context.providerQuality,
197896
+ workset: context.workset,
197897
+ ...context.task ? { task: context.task } : {},
197898
+ ...context.continuation ? { continuation: context.continuation } : {}
197899
+ };
197752
197900
  emitResult(
197753
- {
197754
- project,
197755
- lens: context.lens,
197756
- brief: buildAutoProjectBrief(context),
197757
- currentFacts: context.currentFacts,
197758
- overview: context.overview,
197759
- refresh: context.refresh,
197760
- providerQuality: context.providerQuality,
197761
- workset: context.workset,
197762
- ...context.task ? { task: context.task } : {},
197763
- ...context.continuation ? { continuation: context.continuation } : {}
197764
- },
197901
+ args.briefJson ? buildBoundedContextReceipt({ workset: context.workset, providerQuality: context.providerQuality }) : detailed,
197765
197902
  formatAutoProjectContextPrompt(context),
197766
197903
  asJson
197767
197904
  );
@@ -197793,7 +197930,9 @@ var init_resume = __esm({
197793
197930
  args: {
197794
197931
  task: { type: "positional", description: "Current continuation task", required: false },
197795
197932
  refresh: { type: "string", description: "Project scan policy: auto, always, or never" },
197796
- json: { type: "boolean", description: "Emit machine-readable JSON output" }
197933
+ agent: { type: "string", description: "Optional target agent for compatible workflow selection" },
197934
+ json: { type: "boolean", description: "Emit machine-readable JSON output" },
197935
+ briefJson: { type: "boolean", description: "Emit only the bounded agent brief and receipt JSON" }
197797
197936
  },
197798
197937
  async run({ args }) {
197799
197938
  await context_default.run?.({
@@ -197801,7 +197940,9 @@ var init_resume = __esm({
197801
197940
  _: [],
197802
197941
  input: args.task,
197803
197942
  refresh: args.refresh,
197943
+ agent: args.agent,
197804
197944
  json: args.json,
197945
+ briefJson: args.briefJson,
197805
197946
  resume: true
197806
197947
  },
197807
197948
  rawArgs: [],
@@ -198081,6 +198222,7 @@ async function attachTaskWorkset(input) {
198081
198222
  projectId: input.projectId,
198082
198223
  dataDir: input.dataDir,
198083
198224
  task: input.pack.task,
198225
+ ...input.agent ? { agent: input.agent } : {},
198084
198226
  lens: input.lens,
198085
198227
  currentFacts: input.currentFacts ?? [],
198086
198228
  ...input.codeState ? { codeState: input.codeState } : {},
@@ -198189,7 +198331,8 @@ function formatStatus(status, quality) {
198189
198331
  status.indexedAt ? `- Indexed at: ${status.indexedAt}` : "- Indexed at: never",
198190
198332
  ...quality ? [
198191
198333
  `- Persistent provider: ${status.provider} (heuristic local index)`,
198192
- `- External semantic CodeGraph: ${quality.external.state}` + (quality.external.reason ? ` (${quality.external.reason})` : "")
198334
+ `- External semantic CodeGraph: ${quality.external.state}` + (quality.external.reason ? ` (${quality.external.reason})` : ""),
198335
+ `- Task-scoped provider: ${quality.selected} (${quality.selectedQuality})`
198193
198336
  ] : []
198194
198337
  ].join("\n");
198195
198338
  }
@@ -198197,6 +198340,8 @@ function formatUsageHint() {
198197
198340
  return [
198198
198341
  "Usage:",
198199
198342
  " memorix codegraph refresh",
198343
+ " memorix codegraph init # explicit local CodeGraph initialization",
198344
+ " memorix codegraph sync # explicit local CodeGraph synchronization",
198200
198345
  " memorix codegraph status --json",
198201
198346
  " memorix codegraph diff [--from <snapshot>] [--to <snapshot>]",
198202
198347
  " memorix codegraph impact --path <relative-source-path>",
@@ -198251,6 +198396,12 @@ function compactFacts(project) {
198251
198396
  facts.push(formatGitFact(current.git));
198252
198397
  return { facts, dirty: current.git.dirty };
198253
198398
  }
198399
+ function coerceAgentTarget2(input) {
198400
+ const value = input?.trim().toLowerCase();
198401
+ if (!value) return void 0;
198402
+ if (WORKFLOW_AGENT_TARGETS.includes(value)) return value;
198403
+ throw new Error("agent must be one of: " + WORKFLOW_AGENT_TARGETS.join(", "));
198404
+ }
198254
198405
  var codegraph_default;
198255
198406
  var init_codegraph = __esm({
198256
198407
  "src/cli/commands/codegraph.ts"() {
@@ -198265,6 +198416,8 @@ var init_codegraph = __esm({
198265
198416
  init_task_lens();
198266
198417
  init_external_provider();
198267
198418
  init_resolved_config();
198419
+ init_context_receipt();
198420
+ init_workflows2();
198268
198421
  init_observations();
198269
198422
  init_visibility();
198270
198423
  init_operator_shared();
@@ -198274,19 +198427,21 @@ var init_codegraph = __esm({
198274
198427
  description: "Inspect and refresh CodeGraph Memory for the current project"
198275
198428
  },
198276
198429
  args: {
198277
- action: { type: "string", description: "Action: status, refresh, diff, impact, or context-pack" },
198430
+ action: { type: "string", description: "Action: status, refresh, diff, impact, init, sync, or context-pack" },
198278
198431
  task: { type: "string", description: "Task text for context-pack" },
198279
198432
  path: { type: "string", description: "Indexed relative source path for impact" },
198280
198433
  limit: { type: "string", description: "Max active memories to inspect for context-pack" },
198281
198434
  from: { type: "string", description: "Earlier CodeGraph snapshot id for diff" },
198282
198435
  to: { type: "string", description: "Later CodeGraph snapshot id for diff" },
198283
198436
  impactLimit: { type: "string", description: "Maximum graph relations to inspect for diff impact" },
198284
- json: { type: "boolean", description: "Emit machine-readable JSON output" }
198437
+ agent: { type: "string", description: "Optional target agent for compatible workflow selection" },
198438
+ json: { type: "boolean", description: "Emit machine-readable JSON output" },
198439
+ briefJson: { type: "boolean", description: "Emit only the bounded agent brief and receipt JSON for context-pack" }
198285
198440
  },
198286
198441
  run: async ({ args }) => {
198287
198442
  const positional = args._ ?? [];
198288
198443
  const action = (positional[0] || args.action || "status").toLowerCase();
198289
- const asJson = !!args.json;
198444
+ const asJson = !!args.json || !!args.briefJson;
198290
198445
  try {
198291
198446
  const { project, dataDir, reader } = await getCliProjectContext();
198292
198447
  const store2 = new CodeGraphStore();
@@ -198353,6 +198508,26 @@ ${formatUsageHint()}`;
198353
198508
  );
198354
198509
  return;
198355
198510
  }
198511
+ case "init":
198512
+ case "sync": {
198513
+ const lifecycle = await runExternalCodeGraphLifecycle({
198514
+ action,
198515
+ projectRoot: project.rootPath,
198516
+ mode: codegraphConfig.externalContext,
198517
+ command: codegraphConfig.externalCommand,
198518
+ timeoutMs: codegraphConfig.externalTimeoutMs
198519
+ });
198520
+ emitResult(
198521
+ { project, lifecycle, providerQuality: lifecycle.quality },
198522
+ [
198523
+ lifecycle.message,
198524
+ `- External semantic CodeGraph: ${lifecycle.health.state}`,
198525
+ `- Task-scoped provider: ${lifecycle.quality.selected} (${lifecycle.quality.selectedQuality})`
198526
+ ].join("\n"),
198527
+ asJson
198528
+ );
198529
+ return;
198530
+ }
198356
198531
  case "diff": {
198357
198532
  const snapshots = store2.listSnapshots(project.id, 2);
198358
198533
  const fromSnapshotId = args.from?.trim() || snapshots[1]?.id;
@@ -198437,13 +198612,18 @@ ${formatUsageHint()}`;
198437
198612
  ...external.outline ? { semanticCode: external.outline } : {},
198438
198613
  providerQuality: external.quality,
198439
198614
  ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
198440
- reader
198615
+ reader,
198616
+ agent: coerceAgentTarget2(args.agent)
198441
198617
  });
198442
- emitResult({ project, pack, providerQuality: external.quality }, buildContextPackPrompt(pack), asJson);
198618
+ emitResult(
198619
+ args.briefJson && pack.workset ? buildBoundedContextReceipt({ workset: pack.workset, providerQuality: external.quality }) : { project, pack, providerQuality: external.quality },
198620
+ buildContextPackPrompt(pack),
198621
+ asJson
198622
+ );
198443
198623
  return;
198444
198624
  }
198445
198625
  default:
198446
- emitError(`unknown codegraph action "${action}". Use "status", "refresh", "diff", "impact", or "context-pack".`, asJson);
198626
+ emitError(`unknown codegraph action "${action}". Use "status", "refresh", "init", "sync", "diff", "impact", or "context-pack".`, asJson);
198447
198627
  }
198448
198628
  } catch (error40) {
198449
198629
  emitError(error40 instanceof Error ? error40.message : String(error40), asJson);
@@ -258844,7 +259024,7 @@ The path should point to a directory containing a .git folder.`
258844
259024
  };
258845
259025
  const server = existingServer ?? new McpServer({
258846
259026
  name: "memorix",
258847
- version: true ? "1.5.1" : "1.0.1"
259027
+ version: true ? "1.6.0" : "1.0.1"
258848
259028
  });
258849
259029
  const originalRegisterTool = server.registerTool.bind(server);
258850
259030
  server.registerTool = ((name, ...args) => {
@@ -259678,13 +259858,28 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
259678
259858
  refresh: external_exports2.enum(["auto", "always", "never"]).optional().default("auto").describe(
259679
259859
  "Code Memory refresh policy. auto refreshes only when missing or stale."
259680
259860
  ),
259681
- format: external_exports2.enum(["prompt", "summary", "json"]).optional().default("prompt").describe(
259682
- 'Output format. "prompt" is agent-ready; "summary" is human-readable; "json" is structured.'
259861
+ format: external_exports2.enum(["prompt", "summary", "json", "receipt"]).optional().default("prompt").describe(
259862
+ 'Output format. "prompt" is agent-ready; "summary" is human-readable; "receipt" is bounded JSON; "json" is detailed diagnostics.'
259683
259863
  ),
259864
+ agent: external_exports2.enum([
259865
+ "windsurf",
259866
+ "cursor",
259867
+ "claude-code",
259868
+ "codex",
259869
+ "copilot",
259870
+ "antigravity",
259871
+ "gemini-cli",
259872
+ "openclaw",
259873
+ "hermes",
259874
+ "omp",
259875
+ "kiro",
259876
+ "opencode",
259877
+ "trae"
259878
+ ]).optional().describe("Optional target agent for compatible workflow selection."),
259684
259879
  limit: external_exports2.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
259685
259880
  }
259686
259881
  },
259687
- async ({ task, refresh, format }) => {
259882
+ async ({ task, refresh, format, agent }) => {
259688
259883
  const unresolved = requireResolvedProject("build project context for the current project");
259689
259884
  if (unresolved) return unresolved;
259690
259885
  const [
@@ -259696,12 +259891,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
259696
259891
  },
259697
259892
  { getObservationStore: getObservationStore2 },
259698
259893
  { MaintenanceJobStore: MaintenanceJobStore2 },
259699
- { enqueueCodegraphRefresh: enqueueCodegraphRefresh2 }
259894
+ { enqueueCodegraphRefresh: enqueueCodegraphRefresh2 },
259895
+ { buildBoundedContextReceipt: buildBoundedContextReceipt2 }
259700
259896
  ] = await Promise.all([
259701
259897
  Promise.resolve().then(() => (init_auto_context(), auto_context_exports)),
259702
259898
  Promise.resolve().then(() => (init_obs_store(), obs_store_exports)),
259703
259899
  Promise.resolve().then(() => (init_maintenance_jobs(), maintenance_jobs_exports)),
259704
- Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports))
259900
+ Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports)),
259901
+ Promise.resolve().then(() => (init_context_receipt(), context_receipt_exports))
259705
259902
  ]);
259706
259903
  const observations2 = filterReadableObservations(
259707
259904
  await getObservationStore2().loadByProject(project.id, { status: "active" }),
@@ -259712,6 +259909,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
259712
259909
  dataDir: projectDir2,
259713
259910
  observations: observations2,
259714
259911
  task,
259912
+ agent,
259715
259913
  refresh: refresh ?? "auto",
259716
259914
  reader: getObservationReader(),
259717
259915
  enqueueRefresh: () => {
@@ -259724,7 +259922,10 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
259724
259922
  });
259725
259923
  }
259726
259924
  });
259727
- const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
259925
+ const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "receipt" ? JSON.stringify(buildBoundedContextReceipt2({
259926
+ workset: context.workset,
259927
+ providerQuality: context.providerQuality
259928
+ }), null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
259728
259929
  autopilotRetrievalBoundary = {
259729
259930
  projectId: project.id,
259730
259931
  issuedAt: Date.now(),
File without changes