memorix 1.5.1 → 1.6.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +3 -3
  3. package/README.zh-CN.md +3 -3
  4. package/dist/cli/index.js +558 -102
  5. package/dist/cli/memcode.js +12 -1
  6. package/dist/index.js +221 -27
  7. package/dist/maintenance-runner.js +59 -11
  8. package/dist/media-audio-runner.js +59 -11
  9. package/dist/media-video-runner.js +59 -11
  10. package/dist/memcode-runtime/CHANGELOG.md +47 -0
  11. package/dist/sdk.js +220 -26
  12. package/dist/vector-backfill-runner.js +59 -11
  13. package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +1 -1
  14. package/docs/AGENT_OPERATOR_PLAYBOOK.md +11 -3
  15. package/docs/API_REFERENCE.md +2 -2
  16. package/docs/DEVELOPMENT.md +5 -3
  17. package/docs/DOCKER.md +5 -1
  18. package/docs/PERFORMANCE.md +2 -2
  19. package/docs/README.md +3 -1
  20. package/docs/SETUP.md +8 -2
  21. package/package.json +1 -1
  22. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  23. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  24. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  25. package/plugins/copilot/memorix/plugin.json +1 -1
  26. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  27. package/plugins/omp/memorix/package.json +1 -1
  28. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  29. package/plugins/pi/memorix/package.json +1 -1
  30. package/server.json +2 -2
  31. package/src/cli/commands/agent-integrations.ts +9 -3
  32. package/src/cli/commands/codegraph.ts +48 -5
  33. package/src/cli/commands/context.ts +20 -4
  34. package/src/cli/commands/doctor.ts +46 -15
  35. package/src/cli/commands/hook.ts +13 -1
  36. package/src/cli/commands/resume.ts +4 -0
  37. package/src/cli/commands/serve-http.ts +68 -7
  38. package/src/cli/heap.ts +76 -0
  39. package/src/cli/invocation.ts +7 -4
  40. package/src/codegraph/auto-context.ts +4 -1
  41. package/src/codegraph/context-pack.ts +3 -1
  42. package/src/codegraph/external-provider.ts +93 -0
  43. package/src/embedding/provider.ts +76 -6
  44. package/src/hooks/handler.ts +9 -18
  45. package/src/hooks/installers/index.ts +1 -1
  46. package/src/hooks/lifecycle.ts +173 -0
  47. package/src/hooks/official-skills.ts +3 -3
  48. package/src/hooks/rules/memorix-agent-rules.md +1 -1
  49. package/src/knowledge/context-receipt.ts +41 -0
  50. package/src/knowledge/workflows.ts +6 -3
  51. package/src/knowledge/workset.ts +56 -2
  52. package/src/server.ts +15 -3
@@ -2,7 +2,18 @@
2
2
  import {spawnSync as __ms} from "node:child_process";
3
3
  import {fileURLToPath as __fu} from "node:url";
4
4
  if(!process.env.__MEMORIX_HEAP){process.env.__MEMORIX_HEAP="1";
5
- let r=__ms(process.execPath,["--max-old-space-size=4096",__fu(import.meta.url),...process.argv.slice(2)],{stdio:"inherit",env:process.env,windowsHide:true});
5
+ const __args=process.argv.slice(2);
6
+ let __cmd;
7
+ for(let __i=0;__i<__args.length;__i++){
8
+ const __a=__args[__i];
9
+ if(__a==="--")break;
10
+ if(__a.startsWith("-")){if(!__a.includes("=")&&__args[__i+1]&&!__args[__i+1].startsWith("-"))__i++;continue;}
11
+ __cmd=__a;break;}
12
+ const __fallback=__cmd==="hook"?512:4096;
13
+ const __raw=__cmd==="hook"?process.env.MEMORIX_HOOK_HEAP_MB:process.env.MEMORIX_HEAP_MB;
14
+ const __n=Number(__raw);
15
+ const __heap=(Number.isFinite(__n)&&__n>=64&&__n<=16384)?String(Math.floor(__n)):String(__fallback);
16
+ let r=__ms(process.execPath,["--max-old-space-size="+__heap,__fu(import.meta.url),...process.argv.slice(2)],{stdio:"inherit",env:process.env,windowsHide:true});
6
17
  process.exit(r.status??1);}
7
18
  import {createRequire as __memorix_cjsRequire} from "module";
8
19
  const require = __memorix_cjsRequire(import.meta.url);
package/dist/index.js CHANGED
@@ -4438,6 +4438,7 @@ __export(provider_exports, {
4438
4438
  MAX_INLINE_EMBEDDING_BYTES: () => MAX_INLINE_EMBEDDING_BYTES,
4439
4439
  UnsupportedEmbeddingModalityError: () => UnsupportedEmbeddingModalityError,
4440
4440
  getEmbeddingProvider: () => getEmbeddingProvider,
4441
+ getEmbeddingRuntimeHealth: () => getEmbeddingRuntimeHealth,
4441
4442
  isEmbeddingExplicitlyDisabled: () => isEmbeddingExplicitlyDisabled,
4442
4443
  isVectorSearchAvailable: () => isVectorSearchAvailable,
4443
4444
  resetProvider: () => resetProvider,
@@ -4545,13 +4546,36 @@ function isTemporaryEmbeddingFailure(error) {
4545
4546
  if (!(error instanceof Error)) return false;
4546
4547
  return /embedding api error \(401\)/i.test(error.message) || /invalid_api_key/i.test(error.message) || /incorrect api key/i.test(error.message) || /unauthorized/i.test(error.message) || /embedding api timeout/i.test(error.message) || /embedding api error \((402|429|5\d\d)\)/i.test(error.message) || /quota exceeded/i.test(error.message) || /account balance/i.test(error.message) || /fetch failed/i.test(error.message) || /econnreset/i.test(error.message) || /econnrefused/i.test(error.message) || /temporarily unavailable/i.test(error.message);
4547
4548
  }
4549
+ function classifyEmbeddingFailure(error) {
4550
+ const message = error instanceof Error ? error.message : String(error);
4551
+ if (/embedding api error \(401\)|invalid_api_key|incorrect api key|unauthorized/i.test(message)) {
4552
+ return "authorization";
4553
+ }
4554
+ if (/embedding api error \(402\)|quota exceeded|account balance/i.test(message)) {
4555
+ return "billing";
4556
+ }
4557
+ if (/embedding api timeout|abort/i.test(message)) {
4558
+ return "timeout";
4559
+ }
4560
+ return "upstream";
4561
+ }
4548
4562
  function markTemporaryFailure(reason) {
4549
4563
  provider = null;
4550
4564
  initPromise = null;
4551
4565
  lastInitWasTemporaryFailure = true;
4552
4566
  lastFailureTimestamp = Date.now();
4567
+ lastEmbeddingFailure = {
4568
+ kind: classifyEmbeddingFailure(reason),
4569
+ occurredAt: lastFailureTimestamp
4570
+ };
4553
4571
  const message = reason instanceof Error ? reason.message : String(reason);
4554
- warnOnce(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);
4572
+ warnOnce(`[memorix] Embedding provider unavailable at runtime: ${message}`);
4573
+ }
4574
+ function markProviderReady(candidate) {
4575
+ provider = wrapProvider(candidate);
4576
+ lastInitWasTemporaryFailure = false;
4577
+ lastEmbeddingFailure = null;
4578
+ return provider;
4555
4579
  }
4556
4580
  async function createFastEmbedProvider() {
4557
4581
  try {
@@ -4667,35 +4691,35 @@ async function getEmbeddingProvider(options = {}) {
4667
4691
  if (mode === "fastembed") {
4668
4692
  const initialized = await createFastEmbedProvider();
4669
4693
  if (!initialized) return null;
4670
- provider = wrapProvider(initialized);
4694
+ provider = markProviderReady(initialized);
4671
4695
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4672
4696
  return provider;
4673
4697
  }
4674
4698
  if (mode === "transformers") {
4675
4699
  const initialized = await createTransformersProvider();
4676
4700
  if (!initialized) return null;
4677
- provider = wrapProvider(initialized);
4701
+ provider = markProviderReady(initialized);
4678
4702
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4679
4703
  return provider;
4680
4704
  }
4681
4705
  if (mode === "api") {
4682
4706
  const initialized = await createAPIProvider(options);
4683
4707
  if (!initialized) return null;
4684
- provider = wrapProvider(initialized);
4708
+ provider = markProviderReady(initialized);
4685
4709
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4686
4710
  return provider;
4687
4711
  }
4688
4712
  if (hasAPIEmbeddingConfig()) {
4689
4713
  const initialized = await createAPIProvider(options);
4690
4714
  if (initialized) {
4691
- provider = wrapProvider(initialized);
4715
+ provider = markProviderReady(initialized);
4692
4716
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4693
4717
  return provider;
4694
4718
  }
4695
4719
  }
4696
4720
  const localFallback = await createLocalFallbackProvider();
4697
4721
  if (localFallback) {
4698
- provider = wrapProvider(localFallback);
4722
+ provider = markProviderReady(localFallback);
4699
4723
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4700
4724
  return provider;
4701
4725
  }
@@ -4717,6 +4741,27 @@ async function isVectorSearchAvailable() {
4717
4741
  const p = await getEmbeddingProvider();
4718
4742
  return p !== null;
4719
4743
  }
4744
+ function getEmbeddingRuntimeHealth() {
4745
+ const mode = getEmbeddingMode2();
4746
+ if (mode === "off") return { status: "disabled" };
4747
+ if (lastInitWasTemporaryFailure && lastEmbeddingFailure) {
4748
+ return {
4749
+ status: "degraded",
4750
+ failure: {
4751
+ kind: lastEmbeddingFailure.kind,
4752
+ occurredAt: new Date(lastEmbeddingFailure.occurredAt).toISOString(),
4753
+ retryAfterMs: Math.max(0, RETRY_COOLDOWN_MS - (Date.now() - lastEmbeddingFailure.occurredAt))
4754
+ }
4755
+ };
4756
+ }
4757
+ if (provider) {
4758
+ return {
4759
+ status: "ready",
4760
+ provider: { name: provider.name, dimensions: provider.dimensions }
4761
+ };
4762
+ }
4763
+ return { status: "uninitialized" };
4764
+ }
4720
4765
  function isEmbeddingExplicitlyDisabled() {
4721
4766
  return getEmbeddingMode2() === "off";
4722
4767
  }
@@ -4725,10 +4770,11 @@ function resetProvider() {
4725
4770
  initPromise = null;
4726
4771
  lastInitWasTemporaryFailure = false;
4727
4772
  lastFailureTimestamp = 0;
4773
+ lastEmbeddingFailure = null;
4728
4774
  lastEmbeddingWarning = "";
4729
4775
  lastEmbeddingWarningAt = 0;
4730
4776
  }
4731
- var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4777
+ var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4732
4778
  var init_provider = __esm({
4733
4779
  "src/embedding/provider.ts"() {
4734
4780
  "use strict";
@@ -4753,6 +4799,7 @@ var init_provider = __esm({
4753
4799
  provider = null;
4754
4800
  initPromise = null;
4755
4801
  lastInitWasTemporaryFailure = false;
4802
+ lastEmbeddingFailure = null;
4756
4803
  lastEmbeddingWarning = "";
4757
4804
  lastEmbeddingWarningAt = 0;
4758
4805
  WARNING_COOLDOWN_MS = 3e4;
@@ -148858,6 +148905,7 @@ var init_task_lens = __esm({
148858
148905
  var workflows_exports = {};
148859
148906
  __export(workflows_exports, {
148860
148907
  WORKFLOW_ADAPTER_TARGETS: () => WORKFLOW_ADAPTER_TARGETS,
148908
+ WORKFLOW_AGENT_TARGETS: () => WORKFLOW_AGENT_TARGETS,
148861
148909
  applyWorkflowAdapter: () => applyWorkflowAdapter,
148862
148910
  importWindsurfWorkflows: () => importWindsurfWorkflows,
148863
148911
  parseWorkflowMarkdown: () => parseWorkflowMarkdown,
@@ -148923,7 +148971,7 @@ function optionalStatus(data) {
148923
148971
  return value;
148924
148972
  }
148925
148973
  function normalizeAgents(values) {
148926
- const unknown3 = values.filter((value) => !KNOWN_AGENTS.includes(value));
148974
+ const unknown3 = values.filter((value) => !WORKFLOW_AGENT_TARGETS.includes(value));
148927
148975
  if (unknown3.length > 0) {
148928
148976
  throw new Error("workflow frontmatter has unsupported agent: " + unknown3[0]);
148929
148977
  }
@@ -149199,7 +149247,7 @@ function taskScore(workflow, task) {
149199
149247
  return { score, reasons: [...new Set(reasons)] };
149200
149248
  }
149201
149249
  function selectWorkflows(input) {
149202
- const selected = input.workflows.filter((workflow) => workflow.status === "active").map((workflow) => {
149250
+ const selected = input.workflows.filter((workflow) => workflow.status === "active" && (!input.agent || workflow.compatibleAgents.includes(input.agent))).map((workflow) => {
149203
149251
  const match2 = taskScore(workflow, input.task);
149204
149252
  const cautions = input.store && input.projectId ? input.store.recentFailureCautions(input.projectId, workflow.id) : [];
149205
149253
  return {
@@ -149479,7 +149527,7 @@ async function selectWorkspaceWorkflows(input) {
149479
149527
  errors: synced.errors
149480
149528
  };
149481
149529
  }
149482
- var KNOWN_AGENTS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS, GENERIC_WORKFLOW_LENSES, GENERIC_WORKFLOW_TERMS;
149530
+ var WORKFLOW_AGENT_TARGETS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS, GENERIC_WORKFLOW_LENSES, GENERIC_WORKFLOW_TERMS;
149483
149531
  var init_workflows2 = __esm({
149484
149532
  "src/knowledge/workflows.ts"() {
149485
149533
  "use strict";
@@ -149491,7 +149539,7 @@ var init_workflows2 = __esm({
149491
149539
  init_workflow_store();
149492
149540
  init_outcome_store();
149493
149541
  init_task_lens();
149494
- KNOWN_AGENTS = [
149542
+ WORKFLOW_AGENT_TARGETS = [
149495
149543
  "windsurf",
149496
149544
  "cursor",
149497
149545
  "claude-code",
@@ -157127,6 +157175,15 @@ function workflowOutput(selection) {
157127
157175
  cautions: selection.cautions.map((caution) => short(caution, 22))
157128
157176
  };
157129
157177
  }
157178
+ function workflowLoadout(agent, selections) {
157179
+ if (!agent) return void 0;
157180
+ return {
157181
+ agent,
157182
+ workflowIds: selections.map((selection) => selection.workflow.id),
157183
+ requiredContext: unique(selections.flatMap((selection) => selection.workflow.requiredContext)).map((item) => short(item, 18)).slice(0, 4),
157184
+ allowedTools: unique(selections.flatMap((selection) => selection.workflow.allowedTools)).map((item) => short(item, 12)).slice(0, 6)
157185
+ };
157186
+ }
157130
157187
  function appendLine(lines, candidate, maxTokens, omitted, omittedKind, selected, receiptSelection) {
157131
157188
  const next = lines.length ? lines.join("\n") + "\n" + candidate : candidate;
157132
157189
  if (countTextTokens(next) <= maxTokens) {
@@ -157587,6 +157644,22 @@ function renderTaskWorksetPrompt(input) {
157587
157644
  );
157588
157645
  }
157589
157646
  }
157647
+ if (input.agentLoadout) {
157648
+ appendLine(lines, "", maxTokens, omitted, "agent-loadout-heading");
157649
+ appendLine(lines, "Agent loadout (" + input.agentLoadout.agent + ")", maxTokens, omitted, "agent-loadout-heading");
157650
+ for (const required of input.agentLoadout.requiredContext.slice(0, 2)) {
157651
+ appendLine(lines, "- Need: " + required, maxTokens, omitted, "agent-loadout-context");
157652
+ }
157653
+ if (input.agentLoadout.allowedTools.length > 0) {
157654
+ appendLine(
157655
+ lines,
157656
+ "- Workflow tools: " + input.agentLoadout.allowedTools.join(", "),
157657
+ maxTokens,
157658
+ omitted,
157659
+ "agent-loadout-tools"
157660
+ );
157661
+ }
157662
+ }
157590
157663
  if (input.verification.length > 0) {
157591
157664
  appendLine(lines, "", maxTokens, omitted, "verification-heading");
157592
157665
  appendLine(lines, "Verify", maxTokens, omitted, "verification-heading");
@@ -157678,6 +157751,7 @@ async function buildTaskWorkset(input) {
157678
157751
  let workspace;
157679
157752
  let pages = [];
157680
157753
  let workflows = [];
157754
+ let workflowSelections = [];
157681
157755
  try {
157682
157756
  workspace = await preferredWorkspace(input.projectId, input.dataDir);
157683
157757
  if (workspace) {
@@ -157694,14 +157768,15 @@ async function buildTaskWorkset(input) {
157694
157768
  if (task) {
157695
157769
  const workflowStore = new WorkflowStore();
157696
157770
  await workflowStore.init(input.dataDir);
157697
- const selected = selectWorkflows({
157771
+ workflowSelections = selectWorkflows({
157698
157772
  workflows: workflowStore.listWorkflows(workspace.id, "active"),
157699
157773
  task,
157700
157774
  projectId: input.projectId,
157701
157775
  store: workflowStore,
157776
+ ...input.agent ? { agent: input.agent } : {},
157702
157777
  limit: 2
157703
157778
  });
157704
- workflows = selected.map(workflowOutput);
157779
+ workflows = workflowSelections.map(workflowOutput);
157705
157780
  for (const workflow of workflows) {
157706
157781
  for (const caution of workflow.cautions) {
157707
157782
  cautions.push({ kind: "workflow-failed-verification", message: caution });
@@ -157723,6 +157798,10 @@ async function buildTaskWorkset(input) {
157723
157798
  workflows
157724
157799
  });
157725
157800
  const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
157801
+ const agentLoadout = workflowLoadout(
157802
+ input.agent,
157803
+ workflowSelections.filter((selection2) => governed.workflows.some((workflow) => workflow.id === selection2.workflow.id))
157804
+ );
157726
157805
  const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
157727
157806
  claim,
157728
157807
  evidenceByClaim.get(claim.id) ?? []
@@ -157767,6 +157846,7 @@ async function buildTaskWorkset(input) {
157767
157846
  pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
157768
157847
  durableMemory: governed.durableMemory,
157769
157848
  workflows: governed.workflows,
157849
+ ...agentLoadout ? { agentLoadout } : {},
157770
157850
  cautions: normalizedCautions,
157771
157851
  verification,
157772
157852
  evidenceIds,
@@ -157985,10 +158065,12 @@ var init_current_facts = __esm({
157985
158065
  var external_provider_exports = {};
157986
158066
  __export(external_provider_exports, {
157987
158067
  DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
158068
+ EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS: () => EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
157988
158069
  MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES: () => MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES,
157989
158070
  MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
157990
158071
  getExternalCodeGraphContext: () => getExternalCodeGraphContext,
157991
- inspectExternalCodeGraph: () => inspectExternalCodeGraph
158072
+ inspectExternalCodeGraph: () => inspectExternalCodeGraph,
158073
+ runExternalCodeGraphLifecycle: () => runExternalCodeGraphLifecycle
157992
158074
  });
157993
158075
  import { spawn as spawn5 } from "child_process";
157994
158076
  import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
@@ -158187,6 +158269,66 @@ async function inspectExternalCodeGraph(input) {
158187
158269
  const health = healthFromStatus(status);
158188
158270
  return { health, quality: providerQuality({ mode, health }) };
158189
158271
  }
158272
+ async function runExternalCodeGraphLifecycle(input) {
158273
+ const mode = input.mode ?? "auto";
158274
+ if (mode === "off") {
158275
+ const health = { state: "disabled", reason: "External CodeGraph is disabled by configuration." };
158276
+ return {
158277
+ action: input.action,
158278
+ performed: false,
158279
+ message: "External CodeGraph is disabled by configuration.",
158280
+ health,
158281
+ quality: providerQuality({ mode, health })
158282
+ };
158283
+ }
158284
+ const indexPath = join20(input.projectRoot, ".codegraph");
158285
+ if (input.action === "sync" && !existsSync15(indexPath)) {
158286
+ const health = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
158287
+ return {
158288
+ action: input.action,
158289
+ performed: false,
158290
+ message: 'Initialize CodeGraph first with "memorix codegraph init".',
158291
+ health,
158292
+ quality: providerQuality({ mode, health })
158293
+ };
158294
+ }
158295
+ if (input.action === "init" && existsSync15(indexPath)) {
158296
+ const inspected2 = await inspectExternalCodeGraph(input);
158297
+ return {
158298
+ action: input.action,
158299
+ performed: false,
158300
+ message: "A local CodeGraph directory already exists; no initialization was performed.",
158301
+ ...inspected2
158302
+ };
158303
+ }
158304
+ const result = await runSafely(input.runner ?? defaultRunner, {
158305
+ command: input.command,
158306
+ args: input.action === "init" ? ["init", input.projectRoot] : ["sync", input.projectRoot, "--quiet"],
158307
+ cwd: input.projectRoot,
158308
+ // A context read must stay fast; an explicit user-requested index sync is
158309
+ // a different operation and gets its own bounded maintenance window.
158310
+ timeoutMs: EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
158311
+ maxOutputBytes: MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES
158312
+ });
158313
+ if (!result.ok) {
158314
+ const health = unavailableHealth(result);
158315
+ return {
158316
+ action: input.action,
158317
+ performed: false,
158318
+ message: "CodeGraph " + input.action + " did not complete: " + (health.reason ?? "unknown local error"),
158319
+ health,
158320
+ quality: providerQuality({ mode, health })
158321
+ };
158322
+ }
158323
+ const inspected = await inspectExternalCodeGraph(input);
158324
+ const remainsStale = inspected.health.state === "stale";
158325
+ return {
158326
+ action: input.action,
158327
+ performed: true,
158328
+ 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.",
158329
+ ...inspected
158330
+ };
158331
+ }
158190
158332
  function safeRelativePath(projectRoot, value, exclude) {
158191
158333
  const path37 = safeText(value, 1024);
158192
158334
  if (!path37 || isAbsolute(path37)) return void 0;
@@ -158312,7 +158454,7 @@ async function getExternalCodeGraphContext(input) {
158312
158454
  quality: providerQuality({ mode, health: inspected.health, ...contributes ? { selected: "external" } : {} })
158313
158455
  };
158314
158456
  }
158315
- 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;
158457
+ 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;
158316
158458
  var init_external_provider = __esm({
158317
158459
  "src/codegraph/external-provider.ts"() {
158318
158460
  "use strict";
@@ -158322,6 +158464,7 @@ var init_external_provider = __esm({
158322
158464
  init_ids();
158323
158465
  DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 1200;
158324
158466
  MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 5e3;
158467
+ EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS = 3e4;
158325
158468
  MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES = 256 * 1024;
158326
158469
  MAX_EXTERNAL_NODE_COUNT = 16;
158327
158470
  MAX_EXTERNAL_EDGE_COUNT = 24;
@@ -159147,6 +159290,7 @@ async function buildAutoProjectContext(input) {
159147
159290
  projectId: input.project.id,
159148
159291
  dataDir: input.dataDir,
159149
159292
  ...task ? { task } : {},
159293
+ ...input.agent ? { agent: input.agent } : {},
159150
159294
  lens: lens.id,
159151
159295
  startHere,
159152
159296
  ...alwaysOn.profile.length > 0 || alwaysOn.state || alwaysOn.durable.length > 0 ? { alwaysOn } : {},
@@ -159483,6 +159627,34 @@ var init_auto_context = __esm({
159483
159627
  }
159484
159628
  });
159485
159629
 
159630
+ // src/knowledge/context-receipt.ts
159631
+ var context_receipt_exports = {};
159632
+ __export(context_receipt_exports, {
159633
+ buildBoundedContextReceipt: () => buildBoundedContextReceipt
159634
+ });
159635
+ function buildBoundedContextReceipt(input) {
159636
+ const provider2 = input.providerQuality ?? input.workset.provenance.codeProvider;
159637
+ return {
159638
+ schemaVersion: "1",
159639
+ task: input.workset.task,
159640
+ brief: input.workset.prompt,
159641
+ receipt: input.workset.receipt,
159642
+ code: {
159643
+ selected: provider2?.selected ?? "lite",
159644
+ quality: provider2?.selectedQuality ?? "heuristic",
159645
+ externalState: provider2?.external.state ?? "not-detected",
159646
+ ...input.workset.provenance.snapshotId ? { snapshotId: input.workset.provenance.snapshotId } : {}
159647
+ },
159648
+ ...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {}
159649
+ };
159650
+ }
159651
+ var init_context_receipt = __esm({
159652
+ "src/knowledge/context-receipt.ts"() {
159653
+ "use strict";
159654
+ init_esm_shims();
159655
+ }
159656
+ });
159657
+
159486
159658
  // src/codegraph/context-pack.ts
159487
159659
  var context_pack_exports = {};
159488
159660
  __export(context_pack_exports, {
@@ -159641,6 +159813,7 @@ async function attachTaskWorkset(input) {
159641
159813
  projectId: input.projectId,
159642
159814
  dataDir: input.dataDir,
159643
159815
  task: input.pack.task,
159816
+ ...input.agent ? { agent: input.agent } : {},
159644
159817
  lens: input.lens,
159645
159818
  currentFacts: input.currentFacts ?? [],
159646
159819
  ...input.codeState ? { codeState: input.codeState } : {},
@@ -164033,8 +164206,8 @@ var init_official_skills = __esm({
164033
164206
  "",
164034
164207
  "| Situation | Prefer | CLI fallback |",
164035
164208
  "|---|---|---|",
164036
- '| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --json` |',
164037
- '| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --json` |',
164209
+ '| 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` |',
164210
+ '| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --brief-json` |',
164038
164211
  '| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
164039
164212
  '| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
164040
164213
  '| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
@@ -164047,7 +164220,7 @@ var init_official_skills = __esm({
164047
164220
  "",
164048
164221
  "- 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.",
164049
164222
  "- 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.",
164050
- '- 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.',
164223
+ '- 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.',
164051
164224
  "- 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.",
164052
164225
  "- 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.",
164053
164226
  "- 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.",
@@ -165306,7 +165479,7 @@ alwaysApply: true
165306
165479
  "",
165307
165480
  `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.`,
165308
165481
  "",
165309
- '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.',
165482
+ '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.',
165310
165483
  "",
165311
165484
  "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.",
165312
165485
  "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.",
@@ -165970,7 +166143,7 @@ The path should point to a directory containing a .git folder.`
165970
166143
  };
165971
166144
  const server = existingServer ?? new McpServer({
165972
166145
  name: "memorix",
165973
- version: true ? "1.5.1" : "1.0.1"
166146
+ version: true ? "1.6.1" : "1.0.1"
165974
166147
  });
165975
166148
  const originalRegisterTool = server.registerTool.bind(server);
165976
166149
  server.registerTool = ((name, ...args) => {
@@ -166804,13 +166977,28 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
166804
166977
  refresh: z626.enum(["auto", "always", "never"]).optional().default("auto").describe(
166805
166978
  "Code Memory refresh policy. auto refreshes only when missing or stale."
166806
166979
  ),
166807
- format: z626.enum(["prompt", "summary", "json"]).optional().default("prompt").describe(
166808
- 'Output format. "prompt" is agent-ready; "summary" is human-readable; "json" is structured.'
166980
+ format: z626.enum(["prompt", "summary", "json", "receipt"]).optional().default("prompt").describe(
166981
+ 'Output format. "prompt" is agent-ready; "summary" is human-readable; "receipt" is bounded JSON; "json" is detailed diagnostics.'
166809
166982
  ),
166983
+ agent: z626.enum([
166984
+ "windsurf",
166985
+ "cursor",
166986
+ "claude-code",
166987
+ "codex",
166988
+ "copilot",
166989
+ "antigravity",
166990
+ "gemini-cli",
166991
+ "openclaw",
166992
+ "hermes",
166993
+ "omp",
166994
+ "kiro",
166995
+ "opencode",
166996
+ "trae"
166997
+ ]).optional().describe("Optional target agent for compatible workflow selection."),
166810
166998
  limit: z626.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
166811
166999
  }
166812
167000
  },
166813
- async ({ task, refresh, format }) => {
167001
+ async ({ task, refresh, format, agent }) => {
166814
167002
  const unresolved = requireResolvedProject("build project context for the current project");
166815
167003
  if (unresolved) return unresolved;
166816
167004
  const [
@@ -166822,12 +167010,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
166822
167010
  },
166823
167011
  { getObservationStore: getObservationStore2 },
166824
167012
  { MaintenanceJobStore: MaintenanceJobStore2 },
166825
- { enqueueCodegraphRefresh: enqueueCodegraphRefresh2 }
167013
+ { enqueueCodegraphRefresh: enqueueCodegraphRefresh2 },
167014
+ { buildBoundedContextReceipt: buildBoundedContextReceipt2 }
166826
167015
  ] = await Promise.all([
166827
167016
  Promise.resolve().then(() => (init_auto_context(), auto_context_exports)),
166828
167017
  Promise.resolve().then(() => (init_obs_store(), obs_store_exports)),
166829
167018
  Promise.resolve().then(() => (init_maintenance_jobs(), maintenance_jobs_exports)),
166830
- Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports))
167019
+ Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports)),
167020
+ Promise.resolve().then(() => (init_context_receipt(), context_receipt_exports))
166831
167021
  ]);
166832
167022
  const observations2 = filterReadableObservations(
166833
167023
  await getObservationStore2().loadByProject(project.id, { status: "active" }),
@@ -166838,6 +167028,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
166838
167028
  dataDir: projectDir2,
166839
167029
  observations: observations2,
166840
167030
  task,
167031
+ agent,
166841
167032
  refresh: refresh ?? "auto",
166842
167033
  reader: getObservationReader(),
166843
167034
  enqueueRefresh: () => {
@@ -166850,7 +167041,10 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
166850
167041
  });
166851
167042
  }
166852
167043
  });
166853
- const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
167044
+ const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "receipt" ? JSON.stringify(buildBoundedContextReceipt2({
167045
+ workset: context.workset,
167046
+ providerQuality: context.providerQuality
167047
+ }), null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
166854
167048
  autopilotRetrievalBoundary = {
166855
167049
  projectId: project.id,
166856
167050
  issuedAt: Date.now(),
@@ -170355,7 +170549,7 @@ var init_serve_shared = __esm({
170355
170549
 
170356
170550
  // src/cli/version.ts
170357
170551
  function getCliVersion() {
170358
- return true ? "1.5.1" : pkg.version;
170552
+ return true ? "1.6.1" : pkg.version;
170359
170553
  }
170360
170554
  var init_version3 = __esm({
170361
170555
  "src/cli/version.ts"() {