mixdog 1.0.4 → 1.0.5

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 (158) hide show
  1. package/README.md +10 -5
  2. package/package.json +18 -17
  3. package/scripts/gate-local.mjs +93 -0
  4. package/scripts/lib/gate-scheduler.mjs +24 -0
  5. package/scripts/lib/run-node-tests.mjs +5 -1
  6. package/scripts/release-paths.mjs +22 -1
  7. package/scripts/test-direct.mjs +2 -1
  8. package/scripts/test.mjs +3 -1
  9. package/src/defaults/agents.json +0 -12
  10. package/src/defaults/mixdog-config.template.json +1 -2
  11. package/src/defaults/skills/docx/SKILL.md +7 -4
  12. package/src/defaults/skills/docx/references/html.md +46 -0
  13. package/src/defaults/skills/docx/references/native-authoring.md +18 -4
  14. package/src/defaults/skills/pdf/SKILL.md +10 -2
  15. package/src/defaults/skills/pdf/references/html.md +64 -0
  16. package/src/defaults/skills/pptx/references/html.md +1 -1
  17. package/src/defaults/skills/xlsx/SKILL.md +7 -3
  18. package/src/defaults/skills/xlsx/references/html.md +40 -0
  19. package/src/defaults/skills/xlsx/references/report-design.md +21 -4
  20. package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch/preset.mjs +1 -1
  21. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -3
  22. package/src/runtime/agent/orchestrator/internal-agents.mjs +1 -1
  23. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +6 -5
  24. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +6 -3
  25. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +6 -2
  26. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +50 -9
  27. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +28 -1
  28. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +4 -1
  29. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +34 -8
  30. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +10 -2
  31. package/src/runtime/agent/orchestrator/session/transcript-restore/agent-envelope.mjs +1 -1
  32. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +1 -0
  33. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +3 -1
  34. package/src/runtime/attachments/pdf-extract.mjs +7 -3
  35. package/src/runtime/computer-bridge/client.mjs +1 -1
  36. package/src/runtime/memory/index.mjs +4 -15
  37. package/src/runtime/memory/lib/core-memory-store.mjs +1 -1
  38. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +0 -2
  39. package/src/runtime/memory/lib/cycle-scheduler/backlog-probe.mjs +3 -11
  40. package/src/runtime/memory/lib/cycle-scheduler/health-ledger.mjs +1 -3
  41. package/src/runtime/memory/lib/cycle-scheduler/scheduled-enqueue.mjs +1 -11
  42. package/src/runtime/memory/lib/cycle-scheduler/tick-loop.mjs +0 -2
  43. package/src/runtime/memory/lib/cycle-scheduler.mjs +4 -13
  44. package/src/runtime/memory/lib/cycle-signatures.mjs +0 -6
  45. package/src/runtime/memory/lib/cycle1/cycle1-rows.mjs +1 -1
  46. package/src/runtime/memory/lib/cycle1/cycle1-window.mjs +2 -2
  47. package/src/runtime/memory/lib/embedding-reindex.mjs +1 -1
  48. package/src/runtime/memory/lib/http-router/lifecycle-routes.mjs +0 -1
  49. package/src/runtime/memory/lib/memory-action-handlers/cycle-actions.mjs +7 -52
  50. package/src/runtime/memory/lib/memory-action-handlers/cycle-backfill-action.mjs +6 -22
  51. package/src/runtime/memory/lib/memory-action-handlers/cycle-rebuild-action.mjs +10 -17
  52. package/src/runtime/memory/lib/memory-action-handlers/maintenance-actions.mjs +1 -3
  53. package/src/runtime/memory/lib/memory-action-handlers/manage-actions.mjs +2 -4
  54. package/src/runtime/memory/lib/memory-action-handlers.mjs +2 -4
  55. package/src/runtime/memory/lib/memory-cycle-requests.mjs +1 -1
  56. package/src/runtime/memory/lib/{memory-cycle2-shared.mjs → memory-cycle-shared.mjs} +14 -16
  57. package/src/runtime/memory/lib/memory-cycle.mjs +3 -2
  58. package/src/runtime/memory/lib/memory-cycle1.mjs +1 -1
  59. package/src/runtime/memory/lib/memory-embed.mjs +14 -1
  60. package/src/runtime/memory/lib/memory-ops-policy.mjs +8 -11
  61. package/src/runtime/memory/lib/memory-schema/entries.mjs +0 -1
  62. package/src/runtime/memory/lib/memory.mjs +2 -6
  63. package/src/runtime/memory/lib/pg/adapter.mjs +1 -1
  64. package/src/runtime/memory/lib/query-handlers.mjs +1 -1
  65. package/src/runtime/memory/lib/query-hybrid-search.mjs +1 -1
  66. package/src/runtime/memory/lib/query-maintenance-handlers.mjs +0 -6
  67. package/src/runtime/memory/lib/recall-format.mjs +1 -1
  68. package/src/runtime/office/authoring/docx-html-build.mjs +375 -0
  69. package/src/runtime/office/authoring/docx-html-measure.mjs +561 -0
  70. package/src/runtime/office/authoring/docx-html-runner.mjs +102 -0
  71. package/src/runtime/office/authoring/html-browser.mjs +61 -0
  72. package/src/runtime/office/authoring/html-document-author.mjs +181 -0
  73. package/src/runtime/office/authoring/html-source-drift.mjs +36 -0
  74. package/src/runtime/office/authoring/pdf-author-action.mjs +266 -0
  75. package/src/runtime/office/authoring/pdf-html-charts.mjs +379 -0
  76. package/src/runtime/office/authoring/pdf-html-runner.mjs +317 -0
  77. package/src/runtime/office/authoring/pptx-author-action.mjs +44 -22
  78. package/src/runtime/office/authoring/pptx-author-session.mjs +12 -6
  79. package/src/runtime/office/authoring/pptx-html-build.mjs +23 -4
  80. package/src/runtime/office/authoring/pptx-html-measure.mjs +38 -44
  81. package/src/runtime/office/authoring/pptx-html-runner.mjs +18 -3
  82. package/src/runtime/office/authoring/pptx-receipt.mjs +39 -31
  83. package/src/runtime/office/authoring/pptx-review-artifacts.mjs +9 -1
  84. package/src/runtime/office/authoring/pptx-script-runner.mjs +6 -2
  85. package/src/runtime/office/authoring/xlsx-html-build.mjs +365 -0
  86. package/src/runtime/office/authoring/xlsx-html-measure.mjs +257 -0
  87. package/src/runtime/office/authoring/xlsx-html-runner.mjs +139 -0
  88. package/src/runtime/office/capabilities-catalog.mjs +8 -0
  89. package/src/runtime/office/capabilities-signatures.mjs +18 -6
  90. package/src/runtime/office/capabilities.mjs +26 -1
  91. package/src/runtime/office/com/office-com-host.ps1 +133 -17
  92. package/src/runtime/office/core/office-actions-batch.mjs +16 -1
  93. package/src/runtime/office/core/office-actions-inspect.mjs +3 -2
  94. package/src/runtime/office/core/office-actions-lifecycle.mjs +6 -2
  95. package/src/runtime/office/core/office-actions-render.mjs +4 -1
  96. package/src/runtime/office/core/office-finalize/review-stage.mjs +15 -2
  97. package/src/runtime/office/core/office-qa/design-review-stage.mjs +9 -0
  98. package/src/runtime/office/core/office-session-dispatch.mjs +3 -0
  99. package/src/runtime/office/core/office-sessionless-actions.mjs +7 -2
  100. package/src/runtime/office/core/office-sessions.mjs +19 -2
  101. package/src/runtime/office/pdf/pdf-writer.mjs +1 -1
  102. package/src/runtime/office/portable/docx-formatting.mjs +21 -0
  103. package/src/runtime/office/portable/ooxml-validator.mjs +22 -1
  104. package/src/runtime/office/portable/portable-chart.mjs +10 -2
  105. package/src/runtime/office/portable/portable-docx-edits.mjs +12 -6
  106. package/src/runtime/office/portable/portable-docx-operations.mjs +75 -1
  107. package/src/runtime/office/portable/portable-docx-xml.mjs +49 -6
  108. package/src/runtime/office/portable/portable-docx.mjs +2 -0
  109. package/src/runtime/office/portable/portable-snapshot-docx.mjs +2 -0
  110. package/src/runtime/office/portable/portable-validation.mjs +6 -3
  111. package/src/runtime/office/portable/portable-xlsx-cell-values.mjs +87 -0
  112. package/src/runtime/office/portable/portable-xlsx-charts.mjs +55 -13
  113. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +1 -1
  114. package/src/runtime/office/portable/xlsx-contract.mjs +82 -3
  115. package/src/runtime/office/quality/assurance-checklist.mjs +2 -2
  116. package/src/runtime/office/quality/assurance-rendered.mjs +27 -1
  117. package/src/runtime/office/quality/assurance-structure-docx.mjs +44 -0
  118. package/src/runtime/office/quality/assurance-structure-pptx.mjs +24 -6
  119. package/src/runtime/office/quality/assurance-structure-xlsx.mjs +50 -1
  120. package/src/runtime/office/quality/design-review-critique.mjs +3 -2
  121. package/src/runtime/office/quality/document-brief.mjs +44 -0
  122. package/src/runtime/office/quality/inline-audit.mjs +7 -2
  123. package/src/runtime/office/quality/quality-pipeline.mjs +9 -1
  124. package/src/runtime/office/tool-defs.mjs +2 -2
  125. package/src/runtime/shared/llm/quota-value-estimate.mjs +317 -0
  126. package/src/runtime/shared/llm/usage-ledger-quota.mjs +266 -63
  127. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +35 -0
  128. package/src/runtime/shared/llm/usage-ledger-worker.mjs +2 -1
  129. package/src/runtime/shared/llm/usage-ledger.mjs +10 -1
  130. package/src/runtime/shared/provider-accounts.mjs +11 -1
  131. package/src/runtime/shared/statusline/statusline-segments.mjs +4 -4
  132. package/src/runtime/shared/tool-execution-contract.mjs +1 -1
  133. package/src/runtime/shared/wait-until.test-support.mjs +33 -0
  134. package/src/session-runtime/boot/apis.mjs +1 -1
  135. package/src/session-runtime/services/channel-admin.mjs +4 -3
  136. package/src/session-runtime/services/usage-stats-model.mjs +22 -0
  137. package/src/session-runtime/setup-tool/settings-contract.mjs +6 -1
  138. package/src/session-runtime/turn/session-ops.mjs +15 -9
  139. package/src/session-runtime/usage-stats-api.mjs +34 -2
  140. package/src/standalone/agent-dispatch-broker.mjs +1 -1
  141. package/src/standalone/local-session-runtime.mjs +488 -0
  142. package/src/standalone/session-protocol.mjs +1 -0
  143. package/src/standalone/session-runtime-inline-host.mjs +1 -1
  144. package/src/tui/hooks/useSession.mjs +1 -1
  145. package/src/tui/session/session-api/commands.mjs +1 -1
  146. package/src/tui/session/session-api/integrations.mjs +3 -0
  147. package/src/tui/session/session-flow/auto-clear.mjs +6 -7
  148. package/src/tui/session/tool-card-results.mjs +1 -1
  149. package/src/tui/session/turn.mjs +5 -0
  150. package/src/tui/session-local.mjs +3 -488
  151. package/src/tui/session.mjs +1 -1
  152. package/src/ui/statusline-agents.mjs +0 -1
  153. package/src/rules/agent/41-cycle2-agent.md +0 -24
  154. package/src/runtime/memory/lib/cycle-scheduler/cycle2-runs.mjs +0 -120
  155. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +0 -110
  156. package/src/runtime/memory/lib/memory-cycle2-quarantine.mjs +0 -99
  157. package/src/runtime/memory/lib/memory-cycle2-review.mjs +0 -240
  158. package/src/runtime/memory/lib/memory-cycle2.mjs +0 -191
@@ -1,24 +1,21 @@
1
1
  /**
2
2
  * memory-action-handlers/cycle-backfill-action.mjs — the backfill action: one
3
3
  * driver run over a transcript window, with the whole-action mutex and the
4
- * per-iteration cancel checkpoints the driver's cycle1/cycle2 callbacks need.
4
+ * per-iteration cancel checkpoints the driver's cycle1 callback needs.
5
5
  */
6
- import { runCycle2 } from '../memory-cycle.mjs';
7
6
  import { runFullBackfill } from '../memory-ops-policy.mjs';
8
- import { throwIfAborted } from '../memory-cycle2-shared.mjs';
7
+ import { throwIfAborted } from '../memory-cycle-shared.mjs';
9
8
 
10
9
  export function createBackfillAction({
11
10
  getDb,
12
11
  dataDir,
13
12
  awaitCycle1Run,
14
- finalizeCycle2Run,
15
- withCycle2Llm,
16
13
  ingestTranscriptFile,
17
14
  cwdFromTranscriptPath,
18
15
  }) {
19
16
  // Whole-action backfill mutex (transport-agnostic). memory-cycle1's
20
17
  // _runCycle1InFlight only protects cycle1; ingest workers
21
- // (memory-ops-policy.mjs) and cycle2 can still overlap if a second backfill
18
+ // (memory-ops-policy.mjs) can still overlap if a second backfill
22
19
  // kicks in (timeout-retry, parallel callers, /api/tool vs /mcp vs
23
20
  // /admin/backfill). Track the in-flight promise here and reject overlaps
24
21
  // with 409.
@@ -35,10 +32,6 @@ export function createBackfillAction({
35
32
  const window = args.window != null ? String(args.window) : '7d';
36
33
  const scope = args.scope != null ? String(args.scope) : 'all';
37
34
  const limit = args.limit != null ? Math.max(1, Number(args.limit)) : null;
38
- // Capture the cycle2 envelope so it routes through finalizeCycle2Run
39
- // (which records cycle2_last_error and clears scheduler delay only on
40
- // ok:true) rather than stamping cycle2 unconditionally afterward.
41
- let capturedCycle2;
42
35
  const promise = runFullBackfill(db, {
43
36
  signal,
44
37
  window,
@@ -48,21 +41,15 @@ export function createBackfillAction({
48
41
  dataDir,
49
42
  ingestTranscriptFile,
50
43
  cwdFromTranscriptPath,
51
- // Re-check the IPC cancel signal at every cycle1/cycle2 iteration the
44
+ // Re-check the IPC cancel signal at every cycle1 iteration the
52
45
  // backfill driver dispatches. handleMemoryAction only checks once
53
46
  // before dispatch; without per-iteration checkpoints a long-running
54
- // backfill keeps spinning through ingest + cycle1 + cycle2 batches
47
+ // backfill keeps spinning through ingest + cycle1 batches
55
48
  // after the proxy has already responded "cancelled" to the caller.
56
49
  runCycle1: (_dbArg, cycle1Config = {}, options = {}, _dir) => {
57
50
  throwIfAborted(signal);
58
51
  return awaitCycle1Run(cycle1Config, { ...options, signal });
59
52
  },
60
- runCycle2: async (dbArg, c2Config, c2Options) => {
61
- throwIfAborted(signal);
62
- const r2 = await runCycle2(dbArg, c2Config, withCycle2Llm({ ...c2Options, signal }));
63
- capturedCycle2 = r2;
64
- return r2;
65
- },
66
53
  });
67
54
  backfillInFlight = promise;
68
55
  let result;
@@ -72,11 +59,8 @@ export function createBackfillAction({
72
59
  if (backfillInFlight === promise) backfillInFlight = null;
73
60
  }
74
61
  throwIfAborted(signal);
75
- if (capturedCycle2) {
76
- await finalizeCycle2Run(capturedCycle2);
77
- }
78
62
  return {
79
- text: `backfill: window=${result.window} scope=${result.scope} files=${result.files} ingested=${result.ingested} cycle1_iters=${result.cycle1_iters} reviewed=${result.reviewed} unclassified=${result.unclassified}${result.error ? ` error=${result.error}` : ''}`,
63
+ text: `backfill: window=${result.window} scope=${result.scope} files=${result.files} ingested=${result.ingested} cycle1_iters=${result.cycle1_iters} unclassified=${result.unclassified}${result.error ? ` error=${result.error}` : ''}`,
80
64
  isError: result.ok === false,
81
65
  };
82
66
  };
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * memory-action-handlers/cycle-rebuild-action.mjs — the destructive rebuild:
3
3
  * drain whatever cycle1 is still running, truncate every classification
4
- * column in one transaction, then re-run cycle1 and cycle2 over the reset
4
+ * column in one transaction, then re-run cycle1 over the reset
5
5
  * rows. The confirm phrase is the only guard the caller gets.
6
6
  */
7
- import { runCycle2 } from '../memory-cycle.mjs';
7
+ import { flushSearchEmbeddings } from '../memory-cycle.mjs';
8
8
  import { getInFlightCycle1 } from '../memory-cycle1.mjs';
9
- import { throwIfAborted } from '../memory-cycle2-shared.mjs';
9
+ import { throwIfAborted } from '../memory-cycle-shared.mjs';
10
10
 
11
11
  // Every root-classification column, cleared before demotion. Cleanup must run
12
12
  // BEFORE demotion: demoting normal roots (chunk_root = id) first and then
@@ -18,7 +18,7 @@ const REBUILD_RESET_ROOTS = `
18
18
  SET element = NULL, category = NULL, summary = NULL,
19
19
  status = 'pending', score = NULL, last_seen_at = NULL,
20
20
  embedding = NULL, summary_hash = NULL,
21
- reviewed_at = NULL, cycle2_reviewed_at = NULL, duplicate_of = NULL,
21
+ reviewed_at = NULL, duplicate_of = NULL,
22
22
  error_count = 0
23
23
  WHERE is_root = 1
24
24
  `;
@@ -28,7 +28,7 @@ const REBUILD_RESET_LEAVES = `
28
28
  element = NULL, category = NULL, summary = NULL,
29
29
  score = NULL, last_seen_at = NULL,
30
30
  embedding = NULL, summary_hash = NULL,
31
- reviewed_at = NULL, cycle2_reviewed_at = NULL, duplicate_of = NULL,
31
+ reviewed_at = NULL, duplicate_of = NULL,
32
32
  error_count = 0
33
33
  WHERE is_root = 0
34
34
  `;
@@ -52,18 +52,12 @@ async function drainCycle1(db, getSchedulerCycle1InFlight) {
52
52
  }
53
53
  }
54
54
 
55
- export function createRebuildAction({
56
- getDb,
57
- startCycle1Run,
58
- finalizeCycle2Run,
59
- getSchedulerCycle1InFlight,
60
- withCycle2Llm,
61
- }) {
55
+ export function createRebuildAction({ getDb, startCycle1Run, getSchedulerCycle1InFlight }) {
62
56
  return async function rebuild(args, config, signal) {
63
57
  const db = getDb();
64
58
  if (args.confirm !== 'REBUILD MEMORY') {
65
59
  return {
66
- text: 'rebuild requires confirm: "REBUILD MEMORY" (truncates classification columns and re-runs cycles)',
60
+ text: 'rebuild requires confirm: "REBUILD MEMORY" (truncates classification columns and re-runs summarization)',
67
61
  isError: true,
68
62
  };
69
63
  }
@@ -84,11 +78,10 @@ export function createRebuildAction({
84
78
  // and guarantees the newly demoted rows are read.
85
79
  const r1 = await startCycle1Run(config?.cycle1 || {}, { signal });
86
80
  throwIfAborted(signal);
87
- const r2 = await runCycle2(db, config?.cycle2 || {}, withCycle2Llm({ signal }));
88
- await finalizeCycle2Run(r2);
81
+ const embeddings = await flushSearchEmbeddings(db, { signal });
82
+ throwIfAborted(signal);
89
83
  return {
90
- text: `rebuild: cycle1 chunks=${r1.chunks} processed=${r1.processed}, cycle2 ${JSON.stringify(r2)}`,
91
- isError: r2.ok === false,
84
+ text: `rebuild: cycle1 chunks=${r1.chunks} processed=${r1.processed}, embeddings=${embeddings.succeeded}`,
92
85
  };
93
86
  };
94
87
  }
@@ -29,15 +29,13 @@ export function createMaintenanceActions({ getDb, entryStats, getCycleLastRun })
29
29
  const { dims, dimsErr } = await embeddingDims(db);
30
30
  const bootstrapComplete = await isBootstrapComplete(db);
31
31
  const lines = [
32
- `entries: total=${stats.total} roots=${stats.roots} cycle1_raw=${stats.unchunked_leaves} (unchunked leaves) cycle2_pending=${stats.cycle2_pending_roots} (awaiting cycle2 review)`,
32
+ `entries: total=${stats.total} roots=${stats.roots} cycle1_raw=${stats.unchunked_leaves} (unchunked leaves)`,
33
33
  `status: ${stats.byStatus.map((r) => `${r.status ?? '?'}:${r.c}`).join(', ') || 'empty'}`,
34
34
  `categories: ${stats.byCategory.map((r) => `${r.category ?? 'NULL'}:${r.c}`).join(', ') || 'empty'}`,
35
35
  `core_memory: user=${stats.core_entries} embed_null=${stats.core_embed_null}`,
36
36
  `embedding_index: ready dims=${dims}${dimsErr ? ` (meta_read_error: ${dimsErr})` : ''}`,
37
37
  `bootstrap: ${bootstrapComplete ? 'complete' : 'incomplete'}`,
38
38
  `last_cycle1: ${agoText(last.cycle1)}`,
39
- `last_cycle2: ${agoText(last.cycle2)}`,
40
- ...(last.cycle2_last_error ? [`last_cycle2_error: ${last.cycle2_last_error}`] : []),
41
39
  ];
42
40
  return { text: lines.join('\n') };
43
41
  }
@@ -154,14 +154,12 @@ export function createManageActions({ getDb, log }) {
154
154
  await db.transaction(async (tx) => {
155
155
  // Editing either side invalidates the duplicate equivalence, not
156
156
  // the original chunks or their lineage.
157
- await tx.query(`UPDATE entries SET duplicate_of = NULL, cycle2_reviewed_at = NULL WHERE duplicate_of = $1`, [
158
- id,
159
- ]);
157
+ await tx.query(`UPDATE entries SET duplicate_of = NULL WHERE duplicate_of = $1`, [id]);
160
158
  await tx.query(
161
159
  `
162
160
  UPDATE entries
163
161
  SET element = $1, summary = $2, category = $3, score = $4,
164
- last_seen_at = $5, content = $6, cycle2_reviewed_at = NULL, duplicate_of = NULL
162
+ last_seen_at = $5, content = $6, duplicate_of = NULL
165
163
  WHERE id = $7
166
164
  `,
167
165
  [finalElement, finalSummary, finalCategory, score, nowMs, composedContent, id]
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // The write/maintenance action cluster and the `memory`/`search_memories`/
4
4
  // `recall` tool dispatch. Actions are grouped by responsibility under
5
- // memory-action-handlers/: cycle-driven (cycle1/cycle2/flush/rebuild/
5
+ // memory-action-handlers/: cycle-driven (cycle1/flush/rebuild/
6
6
  // backfill), maintenance (status/prune/purge), `manage` (generated-history
7
7
  // roots) and `core` (user-curated entries). Live DB handle, config reader,
8
8
  // cycle scheduler primitives, cycle-LLM adapters, query handlers, and the
@@ -10,7 +10,7 @@
10
10
  // `db`, the scheduler, and lifecycle state.
11
11
 
12
12
  import { createToolCallHandler } from './tool-call-handler.mjs';
13
- import { throwIfAborted } from './memory-cycle2-shared.mjs';
13
+ import { throwIfAborted } from './memory-cycle-shared.mjs';
14
14
  import { createCycleActions } from './memory-action-handlers/cycle-actions.mjs';
15
15
  import { createMaintenanceActions } from './memory-action-handlers/maintenance-actions.mjs';
16
16
  import { createManageActions } from './memory-action-handlers/manage-actions.mjs';
@@ -28,8 +28,6 @@ export function createMemoryActionHandlers(deps) {
28
28
  const actions = {
29
29
  status: maintenance.status,
30
30
  cycle1: cycle.cycle1,
31
- cycle2: cycle.cycle2,
32
- sleep: cycle.cycle2,
33
31
  // Direct semantic-search surface for callers that want raw ranked rows
34
32
  // without going through the Lead-side recall synthesizer: the
35
33
  // handleSearch executor is exposed through the public `memory` tool
@@ -1,6 +1,6 @@
1
1
  import { __mixdogMemoryLog } from './memory-log.mjs';
2
2
 
3
- const VALID_CYCLES = new Set(['cycle1', 'cycle2']);
3
+ const VALID_CYCLES = new Set(['cycle1']);
4
4
  const KEY_PREFIX = 'cycle_request.';
5
5
  const _retryTimersByDb = new WeakMap();
6
6
 
@@ -1,6 +1,4 @@
1
- // Shared low-level helpers for the cycle2 cluster: logging, cancellation,
2
- // concurrency and store faults.
3
- // No cycle2 business logic; safe to import from any cycle2 sub-module.
1
+ // Shared memory helpers: logging, cancellation, concurrency and store faults.
4
2
 
5
3
  import { __mixdogMemoryLog } from './memory-log.mjs';
6
4
  export { __mixdogMemoryLog };
@@ -9,8 +7,13 @@ export function throwIfAborted(signal) {
9
7
  if (signal?.aborted) throw signal.reason ?? new Error('aborted');
10
8
  }
11
9
 
12
- // Tiny inline semaphore — bounds cycle fan-out (cycle1 windows, cycle2 review
13
- // packets). One implementation so the two concurrency caps cannot drift.
10
+ export function parseInterval(value) {
11
+ const match = /^(\d+(?:\.\d+)?)\s*(ms|s|m|h|d)$/.exec(String(value).trim());
12
+ if (!match) throw new Error(`[memory-cycle] invalid interval config: ${value}`);
13
+ return Number(match[1]) * { ms: 1, s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }[match[2]];
14
+ }
15
+
16
+ // Bounds concurrent summarization windows.
14
17
  export function createSemaphore(limit) {
15
18
  const cap = Math.max(1, Number(limit) || 1);
16
19
  let active = 0;
@@ -31,12 +34,11 @@ export function createSemaphore(limit) {
31
34
  };
32
35
  }
33
36
 
34
- // Two error classes travel through the cycle2 apply paths and must never be
35
- // confused:
37
+ // Store failures must not be confused with rejected or cancelled work:
36
38
  // * STORE FAULT — the database itself failed the write (transaction rolled
37
- // back, or its COMMIT outcome is unknown). Nothing about the verdict was
38
- // wrong, and the store's state is no longer known, so the run stops.
39
- // * verdict rejection — a guard refused the mutation (stale snapshot, status
39
+ // back, or its COMMIT outcome is unknown). The store's state is no longer
40
+ // known, so the run stops.
41
+ // * rejection — a guard refused the mutation (stale snapshot, status
40
42
  // moved, content changed). The store is healthy;
41
43
  // these return normally and are counted as ordinary rejections/errors.
42
44
  // Only writers raise store faults, via markStoreFault; callers branch on
@@ -49,12 +51,8 @@ export function createSemaphore(limit) {
49
51
  // reclassified because of how its text happens to read, and a store fault keeps
50
52
  // the original message verbatim so logs stay honest.
51
53
  //
52
- // Boundaries this signal actually crosses: none that serialize. The writer
53
- // (applyHistoryReview) throws and the cycle2 apply loop catches it in the
54
- // same process, same module registry, same
55
- // tick. runCycle2 converts it at its own boundary into a plain
56
- // { ok: false, error: <string>, storeFault: <boolean> } result, so the explicit
57
- // boolean — not a re-parsed Error — is what any IPC/worker hop carries onward.
54
+ // Embedding writers use this classification to retain ambiguous commit and
55
+ // rollback failures without disguising them as an empty successful flush.
58
56
  export const MEMORY_STORE_FAULT_CODE = 'MEMORY_STORE_FAULT';
59
57
 
60
58
  export class MemoryStoreFault extends Error {
@@ -1,9 +1,10 @@
1
- // Search-history maintenance: summarization and relationship/index maintenance.
1
+ // Search-history maintenance: summarization and embedding maintenance.
2
2
  export {
3
3
  syncRootEmbedding,
4
4
  flushEmbeddingDirty,
5
+ flushSearchEmbeddings,
5
6
  flushRawEmbeddings,
6
7
  inferChunkProjectId,
7
8
  } from './memory-embed.mjs';
8
9
  export { runCycle1 } from './memory-cycle1.mjs';
9
- export { runCycle2, parseInterval } from './memory-cycle2.mjs';
10
+ export { parseInterval } from './memory-cycle-shared.mjs';
@@ -2,7 +2,7 @@
2
2
  // the advisory lock and request coalescing; _runCycle1Impl orchestrates one
3
3
  // run out of the cycle1/ modules (plan, rows, window, result).
4
4
  import { __mixdogMemoryLog } from './memory-log.mjs';
5
- import { createSemaphore, throwIfAborted } from './memory-cycle2-shared.mjs';
5
+ import { createSemaphore, throwIfAborted } from './memory-cycle-shared.mjs';
6
6
 
7
7
  import { CYCLE1_INPUT_TOKEN_BUDGET, cycle1SourceBudget, partitionCycle1Rows } from './memory-chunk-quality.mjs';
8
8
  import { callAgentDispatch } from './agent-ipc.mjs';
@@ -4,7 +4,7 @@ import { embedTexts, getEmbeddingModelId, holdEmbeddingWarm } from './embedding-
4
4
  import { embeddingToSql } from './memory.mjs';
5
5
  import { createHash } from 'node:crypto';
6
6
  import { pruneEmbeddingCache, resolveEmbeddingCacheMaxRows } from './embedding-cache-retention.mjs';
7
- import { throwIfAborted, markStoreFault } from './memory-cycle2-shared.mjs';
7
+ import { throwIfAborted, markStoreFault } from './memory-cycle-shared.mjs';
8
8
 
9
9
  // Restart-survivable embedding dedup cache (DDL created on first flush).
10
10
  // Keyed per-db handle so a second DB instance in the same process re-runs the
@@ -635,6 +635,19 @@ async function syncBatchEmbeddings(db, ids, options = {}) {
635
635
  return writtenIds;
636
636
  }
637
637
 
638
+ // Explicit maintenance must propagate partial failures and caller cancellation,
639
+ // including callers sharing a flush that was started without their signal.
640
+ export async function flushSearchEmbeddings(db, options = {}) {
641
+ const result = await flushEmbeddingDirty(db, options);
642
+ throwIfAborted(options.signal);
643
+ if (result?.timedOut || result?.failed?.length) {
644
+ throw new Error(
645
+ `embedding maintenance incomplete: failed=${result.failed?.length || 0} timedOut=${Boolean(result.timedOut)}`
646
+ );
647
+ }
648
+ return result;
649
+ }
650
+
638
651
  // Embeds one root; true when its fresh vector was written.
639
652
  export async function syncRootEmbedding(db, rootId, options = {}) {
640
653
  const writtenIds = await syncBatchEmbeddings(db, [rootId], options);
@@ -3,7 +3,8 @@ import { __mixdogMemoryLog } from './memory-log.mjs';
3
3
  import fs from 'node:fs';
4
4
  import path from 'node:path';
5
5
  import { mixdogHome } from '../../shared/plugin-paths.mjs';
6
- import { throwIfAborted } from './memory-cycle2-shared.mjs';
6
+ import { throwIfAborted } from './memory-cycle-shared.mjs';
7
+ import { flushSearchEmbeddings } from './memory-embed.mjs';
7
8
  import { isSkippedWatchPath, isTranscriptJsonlName } from './ingest/transcript-discovery.mjs';
8
9
 
9
10
  function normalizeBackfillWindow(value) {
@@ -80,7 +81,7 @@ export async function runFullBackfill(
80
81
  ingestTranscriptFile,
81
82
  cwdFromTranscriptPath,
82
83
  runCycle1,
83
- runCycle2,
84
+ flushEmbeddings = flushSearchEmbeddings,
84
85
  now = Date.now(),
85
86
  projectsRoot = null,
86
87
  workspaceCwd = null,
@@ -91,8 +92,8 @@ export async function runFullBackfill(
91
92
  if (typeof ingestTranscriptFile !== 'function') {
92
93
  throw new Error('runFullBackfill: ingestTranscriptFile required');
93
94
  }
94
- if (typeof runCycle1 !== 'function' || typeof runCycle2 !== 'function') {
95
- throw new Error('runFullBackfill: runCycle1/runCycle2 required');
95
+ if (typeof runCycle1 !== 'function') {
96
+ throw new Error('runFullBackfill: runCycle1 required');
96
97
  }
97
98
 
98
99
  const normalizedWindow = normalizeBackfillWindow(window);
@@ -158,16 +159,13 @@ export async function runFullBackfill(
158
159
  prevUnclassified = nextUnclassified;
159
160
  }
160
161
 
161
- let reviewed = 0;
162
162
  try {
163
163
  throwIfAborted(signal);
164
- const c2 = await runCycle2(db, config?.cycle2 || {}, { signal });
165
- reviewed = Number(c2?.processed ?? 0);
166
- if (c2?.ok === false) throw new Error(c2.error || 'cycle2 failed');
164
+ await flushEmbeddings(db, { signal });
167
165
  } catch (err) {
168
166
  throwIfAborted(signal);
169
- errors.push({ stage: 'cycle2', error: err.message });
170
- __mixdogMemoryLog(`[backfill] cycle2 error: ${err.message}\n`);
167
+ errors.push({ stage: 'embedding', error: err.message });
168
+ __mixdogMemoryLog(`[backfill] embedding error: ${err.message}\n`);
171
169
  }
172
170
 
173
171
  const unclassified = await countUnclassified(db);
@@ -179,7 +177,6 @@ export async function runFullBackfill(
179
177
  files: selected.length,
180
178
  ingested,
181
179
  cycle1_iters: cycle1Iters,
182
- reviewed,
183
180
  unclassified,
184
181
  };
185
182
  }
@@ -27,7 +27,6 @@ export async function ensureEntriesSchema(db, dimCount) {
27
27
  score REAL,
28
28
  last_seen_at BIGINT,
29
29
  reviewed_at BIGINT,
30
- cycle2_reviewed_at BIGINT,
31
30
  error_count INTEGER NOT NULL DEFAULT 0,
32
31
  embedding halfvec(${dimCount}),
33
32
  summary_hash TEXT,
@@ -265,18 +265,14 @@ export async function ensureCurrentSchemaExtensions(db, dims, embeddingIdentity
265
265
  );
266
266
  }
267
267
  await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS chunk_quality jsonb`);
268
- // Separate maintenance progress from legacy importance/status verdicts.
269
- // Existing content and classification values remain untouched.
270
- await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS cycle2_reviewed_at bigint`);
268
+ // Existing retired review metadata is left untouched, but no longer created.
269
+ // Preserve the search relationships used by recall.
271
270
  await db.exec(
272
271
  `ALTER TABLE entries ADD COLUMN IF NOT EXISTS duplicate_of bigint REFERENCES entries(id) ON DELETE SET NULL`
273
272
  );
274
273
  await db.exec(
275
274
  `CREATE INDEX IF NOT EXISTS idx_entries_duplicate_of ON entries(duplicate_of) WHERE duplicate_of IS NOT NULL`
276
275
  );
277
- await db.exec(
278
- `CREATE INDEX IF NOT EXISTS idx_entries_cycle2_unreviewed ON entries(ts DESC, id DESC) WHERE is_root = 1 AND cycle2_reviewed_at IS NULL`
279
- );
280
276
  await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS time_source text`);
281
277
  await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS concept_id bigint`);
282
278
  await db.exec(`ALTER TABLE entries ADD COLUMN IF NOT EXISTS supersedes_id bigint`);
@@ -50,7 +50,7 @@ function installPoolErrorHandler(pool, label, { onConnectionLoss } = {}) {
50
50
  const logRecoveryFailure = (recoverErr) =>
51
51
  __mixdogMemoryLog(`[pg-adapter] ${label} client-error recovery failed: ${recoverErr?.message || recoverErr}\n`);
52
52
  // pg-pool deliberately removes its idle error listener while a Client is
53
- // checked out. Long-running advisory-lock owners (cycle1/2) can therefore
53
+ // checked out. Long-running advisory-lock owners (cycle1) can therefore
54
54
  // receive a socket-end `error` between queries with no listener at all,
55
55
  // which Node treats as an uncaught exception. Give every physical Client a
56
56
  // permanent last-resort listener; pg-pool's own idle listener still owns
@@ -26,7 +26,7 @@ import { readRawRowsInWindow } from './query-raw-window.mjs';
26
26
  import { recallSessionRows } from './query-session-recall.mjs';
27
27
  import { recallCoreRows } from './query-core-recall.mjs';
28
28
  import { browseEntries } from './query-window-browse.mjs';
29
- import { throwIfAborted } from './memory-cycle2-shared.mjs';
29
+ import { throwIfAborted } from './memory-cycle-shared.mjs';
30
30
 
31
31
  /** Cold-recall log throttle: one line per 10s window per memory runtime. */
32
32
  function createColdRecallNote(log) {
@@ -11,7 +11,7 @@ import {
11
11
  import { searchRelevantHybrid } from './memory-recall-store.mjs';
12
12
  import { retrieveEntries } from './memory-retrievers.mjs';
13
13
  import { compareRecallByScore, compareRecallNewestFirst } from './recall-order.mjs';
14
- import { throwIfAborted } from './memory-cycle2-shared.mjs';
14
+ import { throwIfAborted } from './memory-cycle-shared.mjs';
15
15
  import { expandRecallEventContext } from './recall-event-context.mjs';
16
16
  import { insertTraceEvents } from './trace-store.mjs';
17
17
  import {
@@ -150,11 +150,6 @@ export function createQueryMaintenanceHandlers({ getDb }) {
150
150
  await tx.query(`SELECT COUNT(*) c FROM entries WHERE is_root = 1 AND status = 'archived'`)
151
151
  ).rows[0].c;
152
152
  const unchunked_leaves = (await tx.query(`SELECT COUNT(*) c FROM entries WHERE chunk_root IS NULL`)).rows[0].c;
153
- const cycle2_pending_roots = (
154
- await tx.query(
155
- `SELECT COUNT(*) c FROM entries WHERE is_root = 1 AND cycle2_reviewed_at IS NULL AND duplicate_of IS NULL`
156
- )
157
- ).rows[0].c;
158
153
  const core_entries = (await tx.query(`SELECT COUNT(*) c FROM core_entries`)).rows[0].c;
159
154
  const core_embed_null = (await tx.query(`SELECT COUNT(*) c FROM core_entries WHERE embedding IS NULL`)).rows[0].c;
160
155
  const byStatus = (await tx.query(`SELECT status, COUNT(*) c FROM entries WHERE is_root = 1 GROUP BY status`))
@@ -168,7 +163,6 @@ export function createQueryMaintenanceHandlers({ getDb }) {
168
163
  active_roots,
169
164
  archived_roots,
170
165
  unchunked_leaves,
171
- cycle2_pending_roots,
172
166
  core_entries,
173
167
  core_embed_null,
174
168
  byStatus,
@@ -307,7 +307,7 @@ function rowMembers(r, { includeRootSource, sourceWindow }) {
307
307
 
308
308
  // Chunks present: each member is its own line. The root row is a grouping
309
309
  // artifact for retrieval — the caller wants the chunk content (cycle1 raw),
310
- // not the cycle2-compressed summary.
310
+ // not the stored summary.
311
311
  function memberUnits(r, members, render, preserveSource) {
312
312
  return members.map((m, memberIndex) => {
313
313
  const source = String(m.content ?? '');