@cortexkit/opencode-magic-context 0.34.0 → 0.34.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 (78) hide show
  1. package/README.md +20 -3
  2. package/dist/config/migrate-experimental.d.ts +2 -1
  3. package/dist/config/migrate-experimental.d.ts.map +1 -1
  4. package/dist/config/project-security.d.ts +2 -0
  5. package/dist/config/project-security.d.ts.map +1 -1
  6. package/dist/config/schema/magic-context.d.ts +8 -15
  7. package/dist/config/schema/magic-context.d.ts.map +1 -1
  8. package/dist/features/magic-context/dreamer/classify.d.ts +1 -0
  9. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  10. package/dist/features/magic-context/dreamer/map-memories.d.ts +1 -0
  11. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  12. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +1 -0
  13. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  14. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts +2 -0
  15. package/dist/features/magic-context/dreamer/storage-dream-runs.d.ts.map +1 -1
  16. package/dist/features/magic-context/dreamer/task-executor.d.ts +4 -1
  17. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  18. package/dist/features/magic-context/dreamer/task-gates.d.ts +19 -1
  19. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/task-registry.d.ts +28 -0
  21. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +7 -1
  23. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  24. package/dist/features/magic-context/dreamer/verify.d.ts +1 -0
  25. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  26. package/dist/features/magic-context/migrations.d.ts +23 -1
  27. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  28. package/dist/features/magic-context/mural/compress-cues.d.ts +1 -0
  29. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  30. package/dist/features/magic-context/storage-db.d.ts +3 -2
  31. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  32. package/dist/features/magic-context/storage.d.ts +1 -1
  33. package/dist/features/magic-context/storage.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/command-handler.d.ts +1 -0
  35. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  36. package/dist/hooks/magic-context/execute-status.d.ts +5 -1
  37. package/dist/hooks/magic-context/execute-status.d.ts.map +1 -1
  38. package/dist/hooks/magic-context/hook.d.ts +3 -5
  39. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  40. package/dist/hooks/magic-context/inject-compartments.d.ts +1 -1
  41. package/dist/hooks/magic-context/live-session-state.d.ts +3 -0
  42. package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +1 -1
  44. package/dist/hooks/magic-context/transform.d.ts +2 -2
  45. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  46. package/dist/{index-56yjaeb2.js → index-2y0ybv5x.js} +11 -1
  47. package/dist/{index-s0mdn690.js → index-x8spt5wy.js} +110 -28
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +389 -104
  50. package/dist/plugin/dream-timer.d.ts +4 -2
  51. package/dist/plugin/dream-timer.d.ts.map +1 -1
  52. package/dist/plugin/hooks/create-session-hooks.d.ts +1 -1
  53. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  54. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  55. package/dist/{recomp-orchestrator-8e82vmvb.js → recomp-orchestrator-k72ejkkh.js} +1 -1
  56. package/dist/shared/rpc-types.d.ts +5 -0
  57. package/dist/shared/rpc-types.d.ts.map +1 -1
  58. package/dist/shared/rpc-utils.d.ts +19 -0
  59. package/dist/shared/rpc-utils.d.ts.map +1 -1
  60. package/dist/shared/tui-runtime-specifiers.d.ts +20 -0
  61. package/dist/shared/tui-runtime-specifiers.d.ts.map +1 -0
  62. package/dist/{task-config-5nx3qfz8.js → task-config-gbp7r23g.js} +1 -1
  63. package/package.json +2 -2
  64. package/src/config/index.test.ts +32 -0
  65. package/src/config/migrate-experimental.test.ts +41 -0
  66. package/src/config/migrate-experimental.ts +36 -10
  67. package/src/config/project-security.test.ts +22 -0
  68. package/src/config/project-security.ts +23 -0
  69. package/src/config/schema/magic-context.test.ts +2 -1
  70. package/src/config/schema/magic-context.ts +12 -23
  71. package/src/features/magic-context/dreamer/task-registry.ts +47 -0
  72. package/src/shared/rpc-types.ts +9 -0
  73. package/src/shared/rpc-utils.test.ts +157 -0
  74. package/src/shared/rpc-utils.ts +137 -0
  75. package/src/shared/tui-runtime-specifiers.ts +32 -0
  76. package/src/tui/slots/sidebar-content.tsx +50 -8
  77. package/src/tui/tui-compiled-runtime-imports.test.ts +151 -0
  78. package/src/tui-compiled/slots/sidebar-content.tsx +234 -145
package/dist/index.js CHANGED
@@ -2,11 +2,13 @@ import {
2
2
  CANONICAL_DREAM_TASKS,
3
3
  buildDreamTaskRuntimeConfigs,
4
4
  compareTaskOrder,
5
+ formatDreamTaskBacklogs,
5
6
  isCanonicalDreamTask,
6
7
  leaseKeyFor,
7
8
  leaseKindFor,
9
+ processedDreamTaskItems,
8
10
  userMemoryCollectionEnabled
9
- } from "./index-56yjaeb2.js";
11
+ } from "./index-2y0ybv5x.js";
10
12
  import {
11
13
  AGE_RECLAIM_MIN_TOKENS,
12
14
  AdmissionClass,
@@ -206,6 +208,7 @@ import {
206
208
  hasLengthCappedOutput,
207
209
  hasMemoryClassifiedAtColumn,
208
210
  hasMemoryShareableColumn,
211
+ hasMuralCueColumns,
209
212
  hasRunnableCompartmentWindow,
210
213
  injectM0M1,
211
214
  injectTemporalMarkers,
@@ -369,7 +372,7 @@ import {
369
372
  upsertCommits,
370
373
  verificationFileExists,
371
374
  withContentLanguageDirective
372
- } from "./index-s0mdn690.js";
375
+ } from "./index-x8spt5wy.js";
373
376
  import {
374
377
  deriveHistorianChunkTokens,
375
378
  deriveTriggerBudget,
@@ -9165,9 +9168,10 @@ function migrateLegacyExperimental(rawConfig, warnings) {
9165
9168
  const exp = experimental;
9166
9169
  const hasUM = "user_memories" in exp;
9167
9170
  const hasPKF = "pin_key_files" in exp;
9171
+ const hasMural = "mural" in exp;
9168
9172
  const TOP_LEVEL_GRADUATED = ["temporal_awareness", "caveman_text_compression"];
9169
9173
  const MEMORY_GRADUATED = ["auto_search", "git_commit_indexing"];
9170
- const hasGraduated = TOP_LEVEL_GRADUATED.some((k) => (k in exp)) || MEMORY_GRADUATED.some((k) => (k in exp));
9174
+ const hasGraduated = TOP_LEVEL_GRADUATED.some((k) => (k in exp)) || MEMORY_GRADUATED.some((k) => (k in exp)) || hasMural;
9171
9175
  if (!hasUM && !hasPKF && !hasGraduated) {
9172
9176
  return rawConfig;
9173
9177
  }
@@ -9175,6 +9179,15 @@ function migrateLegacyExperimental(rawConfig, warnings) {
9175
9179
  const dreamer = typeof patched.dreamer === "object" && patched.dreamer !== null ? { ...patched.dreamer } : {};
9176
9180
  const memory = typeof patched.memory === "object" && patched.memory !== null ? { ...patched.memory } : {};
9177
9181
  const newExperimental = { ...exp };
9182
+ const coerceToObject = (value) => {
9183
+ if (typeof value === "boolean") {
9184
+ return { enabled: value };
9185
+ }
9186
+ if (typeof value === "object" && value !== null) {
9187
+ return { ...value };
9188
+ }
9189
+ return;
9190
+ };
9178
9191
  const relocate = (key, dest, destLabel) => {
9179
9192
  if (!(key in exp))
9180
9193
  return;
@@ -9195,15 +9208,20 @@ function migrateLegacyExperimental(rawConfig, warnings) {
9195
9208
  relocate(key, patched, "");
9196
9209
  for (const key of MEMORY_GRADUATED)
9197
9210
  relocate(key, memory, "memory.");
9198
- const coerceToObject = (value) => {
9199
- if (typeof value === "boolean") {
9200
- return { enabled: value };
9201
- }
9202
- if (typeof value === "object" && value !== null) {
9203
- return { ...value };
9211
+ if (hasMural) {
9212
+ const oldMural = coerceToObject(exp.mural);
9213
+ const existingMural = patched.mural;
9214
+ if (existingMural === undefined) {
9215
+ patched.mural = oldMural ?? exp.mural;
9216
+ warnings.push('Deprecated "experimental.mural"; use top-level "mural" instead (migrated in memory; run `doctor` to persist).');
9217
+ } else if (oldMural !== undefined && typeof existingMural === "object" && existingMural !== null && !Array.isArray(existingMural)) {
9218
+ patched.mural = {
9219
+ ...oldMural,
9220
+ ...existingMural
9221
+ };
9204
9222
  }
9205
- return;
9206
- };
9223
+ delete newExperimental.mural;
9224
+ }
9207
9225
  if (hasUM) {
9208
9226
  const oldUM = coerceToObject(exp.user_memories);
9209
9227
  if (oldUM !== undefined) {
@@ -9419,6 +9437,17 @@ function stripUnsafeProjectConfigFields(projectRaw) {
9419
9437
  warnings.push(`Ignoring historian.${removed.join("/")} from project config ` + "(security: historian model selection is user-level only; a repository cannot force extra compaction cost).");
9420
9438
  }
9421
9439
  }
9440
+ const mural = projectRaw.mural;
9441
+ if (isPlainObject(mural) && "model" in mural) {
9442
+ delete mural.model;
9443
+ warnings.push("Ignoring mural.model from project config (security: the mural cue-compressor model is a user-level setting; a repository cannot choose where project memory is sent).");
9444
+ }
9445
+ const experimental = projectRaw.experimental;
9446
+ const legacyMural = isPlainObject(experimental) ? experimental.mural : undefined;
9447
+ if (isPlainObject(legacyMural) && "model" in legacyMural) {
9448
+ delete legacyMural.model;
9449
+ warnings.push("Ignoring experimental.mural.model from project config (security: the mural cue-compressor model is a user-level setting; use user-level mural.model).");
9450
+ }
9422
9451
  for (const agentKey of HIDDEN_AGENT_KEYS) {
9423
9452
  const block = projectRaw[agentKey];
9424
9453
  if (!isPlainObject(block))
@@ -10448,7 +10477,7 @@ function formatFailClosedBlockingMessage(reason) {
10448
10477
  }
10449
10478
  if (reason.kind === "schema_fence") {
10450
10479
  return [
10451
- `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (database schema v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
10480
+ `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (upstream migration lane v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
10452
10481
  `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10453
10482
  ].join(" ");
10454
10483
  }
@@ -11786,6 +11815,7 @@ function createLiveSessionState() {
11786
11815
  deferredMaterializationSessions: new Set,
11787
11816
  sessionDirectoryBySession: new Map,
11788
11817
  recompProgressBySession: new Map,
11818
+ dreamerProgressByProject: new Map,
11789
11819
  internalChildSessions: new Set
11790
11820
  };
11791
11821
  }
@@ -13044,6 +13074,7 @@ async function runCompressCues(args) {
13044
13074
  result.skipped += outcome.skipped;
13045
13075
  result.remaining -= outcome.compressed;
13046
13076
  result.chunks += 1;
13077
+ args.onProgress?.(result.compressed + result.skipped);
13047
13078
  if (outcome.failure?.class === "timeout") {
13048
13079
  consecutiveTimeouts += 1;
13049
13080
  timeoutStreakElapsedMs.push(outcome.failure.elapsedMs);
@@ -13852,6 +13883,7 @@ async function runClassify(args) {
13852
13883
  result.changed += counts.changed;
13853
13884
  result.remaining -= counts.classified;
13854
13885
  result.chunks += 1;
13886
+ args.onProgress?.(result.classified);
13855
13887
  }
13856
13888
  result.complete = result.remaining === 0;
13857
13889
  log(`[dreamer] classify: stage=${stage} classified=${result.classified} changed=${result.changed} chunks=${result.chunks} remaining=${result.remaining} complete=${result.complete}`);
@@ -16005,6 +16037,7 @@ async function mapMemories(args) {
16005
16037
  result.independent += counts.independent;
16006
16038
  result.remaining -= counts.mapped + counts.independent;
16007
16039
  result.batches += 1;
16040
+ args.onProgress?.(result.mapped + result.independent);
16008
16041
  }
16009
16042
  result.complete = result.remaining === 0;
16010
16043
  log(`[dreamer] map-memories: mapped=${result.mapped} independent=${result.independent} batches=${result.batches} remaining=${result.remaining} complete=${result.complete}`);
@@ -16606,6 +16639,7 @@ async function refreshPrimers(args) {
16606
16639
  result.refreshed += 1;
16607
16640
  else
16608
16641
  result.skipped += 1;
16642
+ args.onProgress?.(result.refreshed + result.skipped);
16609
16643
  }
16610
16644
  log(`[dreamer] refresh-primers: refreshed=${result.refreshed} skipped=${result.skipped}`);
16611
16645
  return result;
@@ -16875,6 +16909,191 @@ function insertDreamRun(db, run) {
16875
16909
  getInsertDreamRunStatement(db).run(run.projectPath, run.startedAt, run.finishedAt, run.holderId, JSON.stringify(run.tasks), run.tasksSucceeded, run.tasksFailed, run.smartNotesSurfaced, run.smartNotesPending, run.memoryChanges ? JSON.stringify(run.memoryChanges) : null, run.parentSessionId ?? null);
16876
16910
  }
16877
16911
 
16912
+ // src/features/magic-context/dreamer/task-gates.ts
16913
+ function countActiveMemories(db, projectPath) {
16914
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM memories WHERE project_path = ? AND status IN ('active','permanent')").get(projectPath);
16915
+ return row?.cnt ?? 0;
16916
+ }
16917
+ function countUnmappedActiveMemories(db, projectPath) {
16918
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16919
+ FROM memories m
16920
+ WHERE m.project_path = ?
16921
+ AND m.status IN ('active','permanent')
16922
+ AND NOT EXISTS (
16923
+ SELECT 1 FROM memory_verifications v WHERE v.memory_id = m.id
16924
+ )`).get(projectPath);
16925
+ return row?.cnt ?? 0;
16926
+ }
16927
+ function countCompartmentsSince(db, projectPath, since) {
16928
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16929
+ FROM compartments c
16930
+ JOIN session_projects sp ON sp.session_id = c.session_id
16931
+ WHERE sp.project_path = ? AND c.created_at > ?`).get(projectPath, since);
16932
+ return row?.cnt ?? 0;
16933
+ }
16934
+ function countProjectSessionsSince(db, projectPath, since) {
16935
+ const row = since === null ? db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ?").get(projectPath) : db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ? AND updated_at > ?").get(projectPath, since);
16936
+ return row?.cnt ?? 0;
16937
+ }
16938
+ function countMappedMemories(db, projectPath) {
16939
+ const row = db.prepare(`SELECT COUNT(DISTINCT m.id) AS cnt
16940
+ FROM memories m
16941
+ JOIN memory_verifications v ON v.memory_id = m.id
16942
+ WHERE m.project_path = ?
16943
+ AND m.status IN ('active','permanent')
16944
+ AND v.file_path <> ''`).get(projectPath);
16945
+ return row?.cnt ?? 0;
16946
+ }
16947
+ function countUnverifiedMappedMemories(db, projectPath) {
16948
+ const row = db.prepare(`SELECT COUNT(DISTINCT m.id) AS cnt
16949
+ FROM memories m
16950
+ JOIN memory_verifications v ON v.memory_id = m.id
16951
+ WHERE m.project_path = ?
16952
+ AND m.status IN ('active','permanent')
16953
+ AND v.file_path <> ''
16954
+ AND v.verified_at = 0`).get(projectPath);
16955
+ return row?.cnt ?? 0;
16956
+ }
16957
+ function countCueCandidates(db, projectPath) {
16958
+ if (!hasMuralCueColumns(db))
16959
+ return countActiveMemories(db, projectPath);
16960
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16961
+ FROM memories
16962
+ WHERE project_path = ?
16963
+ AND status IN ('active','permanent')
16964
+ AND (mural_cue IS NULL OR mural_cue_hash IS NULL OR updated_at > mural_cue_at)`).get(projectPath);
16965
+ return row?.cnt ?? 0;
16966
+ }
16967
+ function countStalePrimers(db, projectPath) {
16968
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16969
+ FROM primers
16970
+ WHERE project_path = ?
16971
+ AND status = 'active'
16972
+ AND (answer IS NULL OR TRIM(answer) = '' OR answer_refreshed_at IS NULL
16973
+ OR last_observed_at > answer_refreshed_at)`).get(projectPath);
16974
+ return row?.cnt ?? 0;
16975
+ }
16976
+ function countUnclassifiedActiveMemories(db, projectPath) {
16977
+ if (!hasMemoryClassifiedAtColumn(db))
16978
+ return countActiveMemories(db, projectPath);
16979
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
16980
+ FROM memories
16981
+ WHERE project_path = ?
16982
+ AND status IN ('active','permanent')
16983
+ AND classified_at IS NULL`).get(projectPath);
16984
+ return row?.cnt ?? 0;
16985
+ }
16986
+ function countPendingSmartNotes(db, projectPath) {
16987
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM notes WHERE project_path = ? AND type = 'smart' AND status = 'pending'").get(projectPath);
16988
+ return row?.cnt ?? 0;
16989
+ }
16990
+ function countUserMemoryCandidates(db) {
16991
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM user_memory_candidates").get();
16992
+ return row?.cnt ?? 0;
16993
+ }
16994
+ function countActivePrimers(db, projectPath) {
16995
+ const row = db.prepare("SELECT COUNT(*) AS cnt FROM primers WHERE project_path = ? AND status = 'active'").get(projectPath);
16996
+ return row?.cnt ?? 0;
16997
+ }
16998
+ function getDreamTaskBacklog(db, projectPath, task, options = {}) {
16999
+ switch (task) {
17000
+ case "map-memories": {
17001
+ const total = countActiveMemories(db, projectPath);
17002
+ return { pending: countUnmappedActiveMemories(db, projectPath), total };
17003
+ }
17004
+ case "verify": {
17005
+ return {
17006
+ pending: countUnverifiedMappedMemories(db, projectPath),
17007
+ total: countMappedMemories(db, projectPath)
17008
+ };
17009
+ }
17010
+ case "verify-broad": {
17011
+ const total = countMappedMemories(db, projectPath);
17012
+ return { pending: total, total };
17013
+ }
17014
+ case "curate": {
17015
+ const total = countActiveMemories(db, projectPath);
17016
+ return { pending: total, total };
17017
+ }
17018
+ case "compress-cues": {
17019
+ const total = countActiveMemories(db, projectPath);
17020
+ return { pending: countCueCandidates(db, projectPath), total };
17021
+ }
17022
+ case "classify-memories": {
17023
+ const total = countActiveMemories(db, projectPath);
17024
+ return { pending: countUnclassifiedActiveMemories(db, projectPath), total };
17025
+ }
17026
+ case "retrospective": {
17027
+ const pending = countProjectSessionsSince(db, projectPath, options.retrospectiveWatermarkMs ?? null);
17028
+ return { pending, total: pending };
17029
+ }
17030
+ case "maintain-docs": {
17031
+ const total = countCompartmentsSince(db, projectPath, 0);
17032
+ const pending = countCompartmentsSince(db, projectPath, options.lastRunAt ?? 0);
17033
+ return { pending, total };
17034
+ }
17035
+ case "evaluate-smart-notes": {
17036
+ const pending = countPendingSmartNotes(db, projectPath);
17037
+ return { pending, total: pending };
17038
+ }
17039
+ case "review-user-memories": {
17040
+ const pending = countUserMemoryCandidates(db);
17041
+ return { pending, total: pending };
17042
+ }
17043
+ case "promote-primers": {
17044
+ const pending = countPrimerCandidatesForProject(db, projectPath);
17045
+ return { pending, total: pending };
17046
+ }
17047
+ case "refresh-primers": {
17048
+ const total = countActivePrimers(db, projectPath);
17049
+ return { pending: countStalePrimers(db, projectPath), total };
17050
+ }
17051
+ default: {
17052
+ const _exhaustive = task;
17053
+ return _exhaustive;
17054
+ }
17055
+ }
17056
+ }
17057
+ function getDreamTaskBacklogs(db, projectPath, tasks = CANONICAL_DREAM_TASKS, options = {}) {
17058
+ const result = {};
17059
+ for (const task of tasks)
17060
+ result[task] = getDreamTaskBacklog(db, projectPath, task, options);
17061
+ return result;
17062
+ }
17063
+ function evaluateTaskGate(task, ctx) {
17064
+ const { db, projectIdentity: project, lastRunAt } = ctx;
17065
+ switch (task) {
17066
+ case "map-memories":
17067
+ return countUnmappedActiveMemories(db, project) > 0;
17068
+ case "verify":
17069
+ return countActiveMemories(db, project) > 0;
17070
+ case "verify-broad":
17071
+ return countActiveMemories(db, project) > 0;
17072
+ case "curate":
17073
+ return countActiveMemories(db, project) > 0;
17074
+ case "compress-cues":
17075
+ return countActiveMemories(db, project) > 0;
17076
+ case "classify-memories":
17077
+ return countActiveMemories(db, project) > 0;
17078
+ case "retrospective":
17079
+ return countProjectSessionsSince(db, project, ctx.retrospectiveWatermarkMs ?? null) > 0;
17080
+ case "maintain-docs":
17081
+ return countCompartmentsSince(db, project, lastRunAt ?? 0) > 0;
17082
+ case "evaluate-smart-notes":
17083
+ return getSmartNotesNeedingCompilation(db, project, Date.now(), 1).length > 0 || getStaleCompiledSmartNotes(db, project, Date.now(), 1).length > 0 || getPendingSmartNotes(db, project).some((note) => note.checkStatus === "fallback");
17084
+ case "review-user-memories":
17085
+ return getUserMemoryCandidates(db).length >= ctx.promotionThreshold;
17086
+ case "promote-primers":
17087
+ return countPrimerCandidatesForProject(db, project) >= (ctx.promotionThreshold ?? 2);
17088
+ case "refresh-primers":
17089
+ return getActivePrimers(db, project).some((primer) => !primer.answer.trim() || primer.answerRefreshedAt == null || (primer.lastObservedAt ?? 0) > primer.answerRefreshedAt);
17090
+ default: {
17091
+ const _exhaustive = task;
17092
+ return Boolean(_exhaustive);
17093
+ }
17094
+ }
17095
+ }
17096
+
16878
17097
  // src/features/magic-context/dreamer/verify.ts
16879
17098
  import { createHash as createHash5 } from "node:crypto";
16880
17099
 
@@ -17074,6 +17293,7 @@ async function runVerify(args) {
17074
17293
  result.archived += counts.archived;
17075
17294
  result.remaining -= counts.verified + counts.updated + counts.archived;
17076
17295
  result.batches += 1;
17296
+ args.onProgress?.(result.verified + result.updated + result.archived);
17077
17297
  }
17078
17298
  result.complete = result.remaining === 0;
17079
17299
  log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: verified=${result.verified} updated=${result.updated} archived=${result.archived} batches=${result.batches} remaining=${result.remaining} complete=${result.complete}`);
@@ -17365,6 +17585,20 @@ function createDreamTaskExecutor(deps) {
17365
17585
  const { db, projectIdentity, holderId, leaseKey } = ctx;
17366
17586
  const startedAt = Date.now();
17367
17587
  const deadline = startedAt + config.timeoutMinutes * 60 * 1000;
17588
+ const backlogAtStart = getDreamTaskBacklog(db, projectIdentity, config.task);
17589
+ const reportProgress = (processed) => {
17590
+ deps.onProgress?.({
17591
+ task: config.task,
17592
+ processed: Math.max(0, processed),
17593
+ total: backlogAtStart.pending,
17594
+ startedAt
17595
+ });
17596
+ };
17597
+ reportProgress(0);
17598
+ const incompleteMessage = (remaining) => {
17599
+ const processed = processedDreamTaskItems(backlogAtStart.pending, remaining);
17600
+ return `${config.task} incomplete: ${remaining} remain (was ${backlogAtStart.pending} at run start; processed ${processed} this run)`;
17601
+ };
17368
17602
  const parent = await resolveParentSessionId();
17369
17603
  let moduleRoute;
17370
17604
  if (config.task === "map-memories" || config.task === "compress-cues" || config.task === "verify" || config.task === "verify-broad" || config.task === "retrospective") {
@@ -17393,7 +17627,19 @@ function createDreamTaskExecutor(deps) {
17393
17627
  name: config.task,
17394
17628
  durationMs: Date.now() - startedAt,
17395
17629
  resultChars: 0,
17396
- ...error ? { error } : {}
17630
+ ...error ? { error } : {},
17631
+ backlog: (() => {
17632
+ const end = getDreamTaskBacklog(db, projectIdentity, config.task);
17633
+ const processed = processedDreamTaskItems(backlogAtStart.pending, end.pending);
17634
+ const value = {
17635
+ pendingAtStart: backlogAtStart.pending,
17636
+ totalAtStart: backlogAtStart.total,
17637
+ pendingAtEnd: end.pending,
17638
+ totalAtEnd: end.total,
17639
+ processed
17640
+ };
17641
+ return value;
17642
+ })()
17397
17643
  }
17398
17644
  ],
17399
17645
  tasksSucceeded: status === "completed" ? 1 : 0,
@@ -17427,8 +17673,8 @@ function createDreamTaskExecutor(deps) {
17427
17673
  }
17428
17674
  try {
17429
17675
  if (config.task === "compress-cues") {
17430
- if (deps.experimentalMural?.enabled !== true) {
17431
- log("[dreamer] compress-cues: skipped (experimental.mural is not enabled)");
17676
+ if (deps.mural?.enabled !== true) {
17677
+ log("[dreamer] compress-cues: skipped (mural is not enabled)");
17432
17678
  recordRun("completed", null);
17433
17679
  return { status: "completed" };
17434
17680
  }
@@ -17447,12 +17693,13 @@ function createDreamTaskExecutor(deps) {
17447
17693
  holderId,
17448
17694
  leaseKey,
17449
17695
  deadline,
17450
- model: config.model ?? deps.experimentalMural.model ?? deps.dreamerModel,
17451
- fallbackModels: config.fallbackModels
17696
+ model: config.model ?? deps.mural.model ?? deps.dreamerModel,
17697
+ fallbackModels: config.fallbackModels,
17698
+ onProgress: (processed) => reportProgress(processed)
17452
17699
  });
17453
17700
  log(`[dreamer] compress-cues: compressed=${result.compressed} skipped=${result.skipped} chunks=${result.chunks} remaining=${result.remaining}`);
17454
17701
  if (!result.complete) {
17455
- const error = `compress-cues incomplete: ${result.remaining} selected memories remain`;
17702
+ const error = incompleteMessage(result.remaining);
17456
17703
  recordRun("failed", error);
17457
17704
  return { status: "failed", transient: true, error };
17458
17705
  }
@@ -17489,11 +17736,12 @@ function createDreamTaskExecutor(deps) {
17489
17736
  deadline,
17490
17737
  model: config.model,
17491
17738
  fallbackModels: config.fallbackModels,
17492
- moduleRoute
17739
+ moduleRoute,
17740
+ onProgress: (processed) => reportProgress(processed)
17493
17741
  });
17494
17742
  log(`[dreamer] map-memories: mapped=${result.mapped} independent=${result.independent} batches=${result.batches} remaining=${result.remaining}`);
17495
17743
  if (!result.complete) {
17496
- const error = `map-memories incomplete: ${result.remaining} selected memories remain`;
17744
+ const error = incompleteMessage(result.remaining);
17497
17745
  recordRun("failed", error);
17498
17746
  return { status: "failed", transient: true, error };
17499
17747
  }
@@ -17515,10 +17763,11 @@ function createDreamTaskExecutor(deps) {
17515
17763
  model: config.model,
17516
17764
  fallbackModels: config.fallbackModels,
17517
17765
  language: config.language ?? deps.language,
17518
- moduleRoute
17766
+ moduleRoute,
17767
+ onProgress: (processed) => reportProgress(processed)
17519
17768
  });
17520
17769
  if (!result.complete) {
17521
- const error = `${config.task} incomplete: ${result.remaining} selected memories remain`;
17770
+ const error = incompleteMessage(result.remaining);
17522
17771
  recordRun("failed", error, {
17523
17772
  memoryChanges: computeMemoryDelta(memoryBefore)
17524
17773
  });
@@ -17577,11 +17826,12 @@ function createDreamTaskExecutor(deps) {
17577
17826
  deadline,
17578
17827
  model: config.model,
17579
17828
  fallbackModels: config.fallbackModels,
17580
- ...moduleArgs
17829
+ ...moduleArgs,
17830
+ onProgress: (processed) => reportProgress(processed)
17581
17831
  });
17582
17832
  log(`[dreamer] classify-memories: stage=${result.stage} classified=${result.classified} changed=${result.changed} chunks=${result.chunks} remaining=${result.remaining}`);
17583
17833
  if (!result.complete) {
17584
- const error = `classify-memories incomplete: ${result.remaining} selected memories remain`;
17834
+ const error = incompleteMessage(result.remaining);
17585
17835
  recordRun("failed", error);
17586
17836
  return { status: "failed", transient: true, error };
17587
17837
  }
@@ -17617,7 +17867,8 @@ function createDreamTaskExecutor(deps) {
17617
17867
  model: config.model,
17618
17868
  fallbackModels: config.fallbackModels,
17619
17869
  language: config.language ?? deps.language,
17620
- rawProviderFactory: deps.primerRawProviderFactory
17870
+ rawProviderFactory: deps.primerRawProviderFactory,
17871
+ onProgress: (processed) => reportProgress(processed)
17621
17872
  });
17622
17873
  recordRun("completed", null);
17623
17874
  log(`[dreamer] refresh-primers: refreshed=${result.refreshed} skipped=${result.skipped}`);
@@ -17671,6 +17922,8 @@ function createDreamTaskExecutor(deps) {
17671
17922
  recordRun("failed", brief);
17672
17923
  log(`[dreamer] task ${config.task} failed (transient=${transient}): ${brief}`);
17673
17924
  return { status: "failed", transient, error: brief };
17925
+ } finally {
17926
+ deps.onProgress?.(null, config.task);
17674
17927
  }
17675
17928
  };
17676
17929
  }
@@ -18046,66 +18299,6 @@ async function runAgenticTask(config, ctx, helpers) {
18046
18299
  }
18047
18300
  }
18048
18301
 
18049
- // src/features/magic-context/dreamer/task-gates.ts
18050
- function countActiveMemories(db, projectPath) {
18051
- const row = db.prepare("SELECT COUNT(*) AS cnt FROM memories WHERE project_path = ? AND status IN ('active','permanent')").get(projectPath);
18052
- return row?.cnt ?? 0;
18053
- }
18054
- function countUnmappedActiveMemories(db, projectPath) {
18055
- const row = db.prepare(`SELECT COUNT(*) AS cnt
18056
- FROM memories m
18057
- WHERE m.project_path = ?
18058
- AND m.status IN ('active','permanent')
18059
- AND NOT EXISTS (
18060
- SELECT 1 FROM memory_verifications v WHERE v.memory_id = m.id
18061
- )`).get(projectPath);
18062
- return row?.cnt ?? 0;
18063
- }
18064
- function countCompartmentsSince(db, projectPath, since) {
18065
- const row = db.prepare(`SELECT COUNT(*) AS cnt
18066
- FROM compartments c
18067
- JOIN session_projects sp ON sp.session_id = c.session_id
18068
- WHERE sp.project_path = ? AND c.created_at > ?`).get(projectPath, since);
18069
- return row?.cnt ?? 0;
18070
- }
18071
- function countProjectSessionsSince(db, projectPath, since) {
18072
- const row = since === null ? db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ?").get(projectPath) : db.prepare("SELECT COUNT(*) AS cnt FROM session_projects WHERE project_path = ? AND updated_at > ?").get(projectPath, since);
18073
- return row?.cnt ?? 0;
18074
- }
18075
- function evaluateTaskGate(task, ctx) {
18076
- const { db, projectIdentity: project, lastRunAt } = ctx;
18077
- switch (task) {
18078
- case "map-memories":
18079
- return countUnmappedActiveMemories(db, project) > 0;
18080
- case "verify":
18081
- return countActiveMemories(db, project) > 0;
18082
- case "verify-broad":
18083
- return countActiveMemories(db, project) > 0;
18084
- case "curate":
18085
- return countActiveMemories(db, project) > 0;
18086
- case "compress-cues":
18087
- return countActiveMemories(db, project) > 0;
18088
- case "classify-memories":
18089
- return countActiveMemories(db, project) > 0;
18090
- case "retrospective":
18091
- return countProjectSessionsSince(db, project, ctx.retrospectiveWatermarkMs ?? null) > 0;
18092
- case "maintain-docs":
18093
- return countCompartmentsSince(db, project, lastRunAt ?? 0) > 0;
18094
- case "evaluate-smart-notes":
18095
- return getSmartNotesNeedingCompilation(db, project, Date.now(), 1).length > 0 || getStaleCompiledSmartNotes(db, project, Date.now(), 1).length > 0 || getPendingSmartNotes(db, project).some((note) => note.checkStatus === "fallback");
18096
- case "review-user-memories":
18097
- return getUserMemoryCandidates(db).length >= ctx.promotionThreshold;
18098
- case "promote-primers":
18099
- return countPrimerCandidatesForProject(db, project) >= (ctx.promotionThreshold ?? 2);
18100
- case "refresh-primers":
18101
- return getActivePrimers(db, project).some((primer) => !primer.answer.trim() || primer.answerRefreshedAt == null || (primer.lastObservedAt ?? 0) > primer.answerRefreshedAt);
18102
- default: {
18103
- const _exhaustive = task;
18104
- return Boolean(_exhaustive);
18105
- }
18106
- }
18107
- }
18108
-
18109
18302
  // src/features/magic-context/dreamer/task-scheduler.ts
18110
18303
  var MAX_TASK_RETRIES = 3;
18111
18304
  function ensureSeeded(db, projectIdentity, config, now) {
@@ -18253,10 +18446,10 @@ async function runDomainGroup(deps, group, cb) {
18253
18446
  cb?.onRan?.(due.config.task);
18254
18447
  } else if (outcome.transient) {
18255
18448
  recordTransientFailure(db, projectIdentity, due, finishedAt, outcome.error ?? null);
18256
- cb?.onFailed?.(due.config.task);
18449
+ cb?.onFailed?.(due.config.task, outcome.error);
18257
18450
  } else {
18258
18451
  advanceAfterRun(db, projectIdentity, due, finishedAt, "failed", outcome.error ?? null);
18259
- cb?.onFailed?.(due.config.task);
18452
+ cb?.onFailed?.(due.config.task, outcome.error);
18260
18453
  }
18261
18454
  }
18262
18455
  } finally {
@@ -18265,7 +18458,15 @@ async function runDomainGroup(deps, group, cb) {
18265
18458
  }
18266
18459
  async function runManualDream(deps) {
18267
18460
  const now = Date.now();
18268
- const result = { ran: [], skippedNoWork: [], deferredBusy: [], failed: [] };
18461
+ const result = {
18462
+ ran: [],
18463
+ skippedNoWork: [],
18464
+ deferredBusy: [],
18465
+ failed: [],
18466
+ failureDetails: [],
18467
+ backlogBefore: {},
18468
+ backlogAfter: {}
18469
+ };
18269
18470
  let selected;
18270
18471
  let forceGate = false;
18271
18472
  if (deps.task) {
@@ -18279,6 +18480,9 @@ async function runManualDream(deps) {
18279
18480
  }
18280
18481
  if (selected.length === 0)
18281
18482
  return result;
18483
+ const selectedTaskNames = selected.map((config) => config.task);
18484
+ result.backlogBefore = getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames);
18485
+ result.backlogAfter = { ...result.backlogBefore };
18282
18486
  for (const cfg of selected)
18283
18487
  ensureSeeded(deps.db, deps.projectIdentity, cfg, now);
18284
18488
  const dueAll = selected.map((config) => ({ config, scheduledAt: now }));
@@ -18300,8 +18504,10 @@ async function runManualDream(deps) {
18300
18504
  else
18301
18505
  result.skippedNoWork.push(d.config.task);
18302
18506
  }
18303
- if (gated.length === 0)
18507
+ if (gated.length === 0) {
18508
+ result.backlogAfter = getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames);
18304
18509
  return result;
18510
+ }
18305
18511
  const groups = new Map;
18306
18512
  for (const d of gated) {
18307
18513
  const kind = leaseKindFor(d.config.task);
@@ -18313,9 +18519,14 @@ async function runManualDream(deps) {
18313
18519
  forceGate,
18314
18520
  leaseWaitMs: MANUAL_RUN_LEASE_WAIT_MS,
18315
18521
  onRan: (t) => result.ran.push(t),
18316
- onFailed: (t) => result.failed.push(t),
18522
+ onFailed: (task, error) => {
18523
+ result.failed.push(task);
18524
+ if (error)
18525
+ result.failureDetails?.push(`${task}: ${error}`);
18526
+ },
18317
18527
  onBusy: (t) => result.deferredBusy.push(t)
18318
18528
  })));
18529
+ result.backlogAfter = getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames);
18319
18530
  return result;
18320
18531
  }
18321
18532
  async function runDueTasksForProject(deps) {
@@ -18888,10 +19099,11 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
18888
19099
  ensureProjectRegistered: reg.ensureRegistered,
18889
19100
  language: reg.language,
18890
19101
  dreamerModel: dreamerConfig.model,
18891
- experimentalMural: reg.experimentalMural,
19102
+ mural: reg.mural,
18892
19103
  memoryInjectionBudgetTokens: reg.memoryInjectionBudgetTokens,
18893
19104
  transformMode: reg.transformMode,
18894
- moduleClient: reg.moduleClient
19105
+ moduleClient: reg.moduleClient,
19106
+ onProgress: (progress, completedTask) => reg.onDreamerProgress?.(progress, completedTask)
18895
19107
  });
18896
19108
  const ran = await runDueTasksForProject({
18897
19109
  db,
@@ -20347,7 +20559,7 @@ function formatExecuteThreshold(detail, contextLimit) {
20347
20559
  }
20348
20560
  return `${percentage}%${clampNote}`;
20349
20561
  }
20350
- function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit) {
20562
+ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageConfig = DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, liveModelKey, historyBudgetPercentage, commitClusterTrigger, executeThresholdTokens, contextLimit, dreamer) {
20351
20563
  const thresholdDetail = resolveExecuteThresholdDetail(executeThresholdPercentageConfig, liveModelKey, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, {
20352
20564
  tokensConfig: executeThresholdTokens,
20353
20565
  contextLimit,
@@ -20402,6 +20614,11 @@ function executeStatus(db, sessionId, protectedTags, executeThresholdPercentageC
20402
20614
  `**Protected tags:** ${protectedTags}`,
20403
20615
  `**Subagent session:** ${meta.isSubagent}`
20404
20616
  ];
20617
+ if (dreamer?.backlog && Object.keys(dreamer.backlog).length > 0) {
20618
+ lines.push("", "### Dreamer", ...dreamer.progress ? [
20619
+ `- Running: ${dreamer.progress.task} — ${dreamer.progress.processed}/${dreamer.progress.total} processed`
20620
+ ] : [], ...formatDreamTaskBacklogs(dreamer.backlog).split("\\n"));
20621
+ }
20405
20622
  if (meta.lastContextPercentage > 0 || meta.lastInputTokens > 0) {
20406
20623
  lines.push("", "### Context Usage", `- Last percentage: ${meta.lastContextPercentage.toFixed(1)}%`, `- Last input tokens: ${meta.lastInputTokens.toLocaleString()}`, `- Resolved context limit: ${displayContextLimit > 0 ? displayContextLimit.toLocaleString() : "unknown"}`, `- Proactive compartment evaluation: ${proactiveCompartmentTrigger}%`, `- Post-drop target for historian: ${(executeThresholdPercentage * POST_DROP_TARGET_RATIO).toFixed(0)}% (${executeThresholdPercentage}% * ${POST_DROP_TARGET_RATIO})`, `- Commit cluster trigger: ${commitClusterTrigger?.enabled !== false ? `enabled (min ${commitClusterTrigger?.min_clusters ?? 3} clusters)` : "disabled"}, tail-size trigger: > 3x compartment budget`);
20407
20624
  }
@@ -20424,6 +20641,12 @@ ${c.content}
20424
20641
  lines.push(`- §${op.tagId}§ → ${op.operation}`);
20425
20642
  }
20426
20643
  }
20644
+ if (dreamer?.backlog && Object.keys(dreamer.backlog).length > 0) {
20645
+ lines.push("", "### Dreamer Backlog", formatDreamTaskBacklogs(dreamer.backlog));
20646
+ }
20647
+ if (dreamer?.progress) {
20648
+ lines.push("", "### Dreamer Progress", `- ${dreamer.progress.task}: ${dreamer.progress.processed}/${dreamer.progress.total} processed this run`);
20649
+ }
20427
20650
  return lines.join(`
20428
20651
  `);
20429
20652
  } catch (error) {
@@ -20659,16 +20882,32 @@ ${sidekickResult}
20659
20882
  await sendUserPrompt(deps.sidekick.client, sessionId, augmentedPrompt);
20660
20883
  throwSentinel("CTX-AUG");
20661
20884
  }
20885
+ function readDreamTaskBacklogsSafely(db, projectPath, tasks) {
20886
+ try {
20887
+ return getDreamTaskBacklogs(db, projectPath, tasks);
20888
+ } catch {
20889
+ return {};
20890
+ }
20891
+ }
20662
20892
  function summarizeManualDream(s) {
20663
20893
  const lines = ["## /ctx-dream", ""];
20664
20894
  if (s.ran.length > 0)
20665
20895
  lines.push(`Ran: ${s.ran.join(", ")}`);
20666
20896
  if (s.failed.length > 0)
20667
20897
  lines.push(`Failed: ${s.failed.join(", ")}`);
20898
+ if ((s.failureDetails?.length ?? 0) > 0) {
20899
+ lines.push("Failure details:", ...(s.failureDetails ?? []).map((detail) => `- ${detail}`));
20900
+ }
20668
20901
  if (s.skippedNoWork.length > 0)
20669
20902
  lines.push(`Skipped (no work): ${s.skippedNoWork.join(", ")}`);
20670
20903
  if (s.deferredBusy.length > 0)
20671
20904
  lines.push(`Busy: ${s.deferredBusy.join(", ")} — another dream task holds this domain's lease; retry in a minute`);
20905
+ if (Object.keys(s.backlogBefore ?? {}).length > 0) {
20906
+ lines.push("", "Backlog at run start:", formatDreamTaskBacklogs(s.backlogBefore ?? {}));
20907
+ }
20908
+ if (Object.keys(s.backlogAfter ?? {}).length > 0) {
20909
+ lines.push("", "Backlog at run end:", formatDreamTaskBacklogs(s.backlogAfter ?? {}));
20910
+ }
20672
20911
  if (s.ran.length === 0 && s.failed.length === 0 && s.skippedNoWork.length === 0 && s.deferredBusy.length === 0) {
20673
20912
  lines.push("No enabled dream tasks to run.");
20674
20913
  }
@@ -20696,7 +20935,17 @@ Unknown task "${requested}". Valid tasks: ${CANONICAL_DREAM_TASKS.join(", ")}.`,
20696
20935
  }
20697
20936
  task = requested;
20698
20937
  }
20699
- await deps.sendNotification(sessionId, task ? `Running dream task "${task}"...` : "Starting dream run...", dreamNotificationParams);
20938
+ const backlogTasks = task ? [task] : CANONICAL_DREAM_TASKS;
20939
+ const backlogBefore = readDreamTaskBacklogsSafely(deps.db, deps.dreamer.projectPath, backlogTasks);
20940
+ await deps.sendNotification(sessionId, [
20941
+ "## /ctx-dream",
20942
+ "",
20943
+ task ? `Running dream task "${task}"...` : "Starting dream run...",
20944
+ "",
20945
+ "Backlog before starting:",
20946
+ formatDreamTaskBacklogs(backlogBefore, backlogTasks)
20947
+ ].join(`
20948
+ `), dreamNotificationParams);
20700
20949
  const summary = await deps.dreamer.runManual(task);
20701
20950
  await deps.sendNotification(sessionId, summarizeManualDream(summary), dreamNotificationParams);
20702
20951
  throwSentinel("CTX-DREAM");
@@ -20834,7 +21083,10 @@ Embedding status is unavailable.`;
20834
21083
  }
20835
21084
  const liveModelKey = deps.getLiveModelKey?.(sessionId);
20836
21085
  const liveContextLimit = deps.getContextLimit?.(sessionId);
20837
- const statusOutput = executeStatus(deps.db, sessionId, deps.protectedTags, deps.executeThresholdPercentage, liveModelKey, deps.historyBudgetPercentage, deps.commitClusterTrigger, deps.executeThresholdTokens, liveContextLimit);
21086
+ const statusOutput = executeStatus(deps.db, sessionId, deps.protectedTags, deps.executeThresholdPercentage, liveModelKey, deps.historyBudgetPercentage, deps.commitClusterTrigger, deps.executeThresholdTokens, liveContextLimit, deps.dreamer ? {
21087
+ backlog: readDreamTaskBacklogsSafely(deps.db, deps.dreamer.projectPath, CANONICAL_DREAM_TASKS),
21088
+ progress: deps.getDreamerProgress?.() ?? null
21089
+ } : undefined);
20838
21090
  const moduleStatus = rustStatus ? `
20839
21091
 
20840
21092
  ${formatRustStatusText(rustStatus)}` : "";
@@ -31411,7 +31663,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
31411
31663
  historyBudgetTokens,
31412
31664
  temporalAwareness: deps.experimentalTemporalAwareness,
31413
31665
  hardSignals: m0HardSignals,
31414
- muralEnabled: deps.experimentalMuralEnabled
31666
+ muralEnabled: deps.muralEnabled
31415
31667
  }
31416
31668
  });
31417
31669
  passOutcome.markFinalized();
@@ -33152,6 +33404,7 @@ function createMagicContextHook(deps) {
33152
33404
  const sessionDirectoryBySession = deps.liveSessionState?.sessionDirectoryBySession ?? new Map;
33153
33405
  const internalChildSessions = deps.liveSessionState?.internalChildSessions ?? new Set;
33154
33406
  const recompProgressBySession = deps.liveSessionState?.recompProgressBySession ?? new Map;
33407
+ const dreamerProgressByProject = deps.liveSessionState?.dreamerProgressByProject ?? new Map;
33155
33408
  const channel1StateBySession = new Map;
33156
33409
  const channel2DirectiveTextBySession = new Map;
33157
33410
  const resolveLiveModel = (sessionId) => {
@@ -33192,6 +33445,7 @@ function createMagicContextHook(deps) {
33192
33445
  deferredMaterializationSessions,
33193
33446
  sessionDirectoryBySession,
33194
33447
  recompProgressBySession,
33448
+ dreamerProgressByProject,
33195
33449
  internalChildSessions
33196
33450
  },
33197
33451
  directory: deps.directory,
@@ -33602,7 +33856,7 @@ function createMagicContextHook(deps) {
33602
33856
  compactionOff,
33603
33857
  experimentalUserMemories: userMemoryCollectionEnabled(dreamerConfig),
33604
33858
  experimentalTemporalAwareness: deps.config.temporal_awareness === true,
33605
- experimentalMuralEnabled: deps.config.experimental?.mural?.enabled === true,
33859
+ muralEnabled: deps.config.mural?.enabled === true,
33606
33860
  historianTwoPass: deps.config.historian?.two_pass === true,
33607
33861
  liveModelBySession,
33608
33862
  sessionDirectoryBySession,
@@ -33696,7 +33950,14 @@ function createMagicContextHook(deps) {
33696
33950
  userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreaming),
33697
33951
  language: deps.config.language,
33698
33952
  transformMode: deps.config.transform_mode,
33699
- moduleClient: rustModeModuleClient
33953
+ moduleClient: rustModeModuleClient,
33954
+ onProgress: (progress, completedTask) => {
33955
+ if (progress) {
33956
+ dreamerProgressByProject.set(projectPath, progress);
33957
+ } else if (dreamerProgressByProject.get(projectPath)?.task === completedTask) {
33958
+ dreamerProgressByProject.delete(projectPath);
33959
+ }
33960
+ }
33700
33961
  });
33701
33962
  runDueTasksForProject({
33702
33963
  db,
@@ -33723,6 +33984,7 @@ function createMagicContextHook(deps) {
33723
33984
  const model = resolveLiveModel(sessionId);
33724
33985
  return model ? `${model.providerID}/${model.modelID}` : undefined;
33725
33986
  },
33987
+ getDreamerProgress: () => dreamerProgressByProject.get(projectPath) ?? null,
33726
33988
  getContextLimit: (sessionId) => {
33727
33989
  const model = resolveLiveModel(sessionId);
33728
33990
  if (!model)
@@ -33770,10 +34032,17 @@ function createMagicContextHook(deps) {
33770
34032
  }),
33771
34033
  userMemoryCollectionEnabled: userMemoryCollectionEnabled(dreamerConfig),
33772
34034
  language: deps.config.language,
33773
- experimentalMural: deps.config.experimental?.mural,
34035
+ mural: deps.config.mural,
33774
34036
  memoryInjectionBudgetTokens: deps.config.memory?.injection_budget_tokens,
33775
34037
  transformMode: deps.config.transform_mode,
33776
- moduleClient: rustModeModuleClient
34038
+ moduleClient: rustModeModuleClient,
34039
+ onProgress: (progress, completedTask) => {
34040
+ if (progress) {
34041
+ dreamerProgressByProject.set(projectPath, progress);
34042
+ } else if (dreamerProgressByProject.get(projectPath)?.task === completedTask) {
34043
+ dreamerProgressByProject.delete(projectPath);
34044
+ }
34045
+ }
33777
34046
  }),
33778
34047
  task
33779
34048
  })
@@ -34385,6 +34654,13 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
34385
34654
  const docsTokens = m0Blocks.docsTokens;
34386
34655
  const profileTokens = m0Blocks.profileTokens;
34387
34656
  let lastDreamerRunAt = null;
34657
+ let dreamerBacklog;
34658
+ const dreamerProgress = projectIdentity ? liveSessionState?.dreamerProgressByProject?.get(projectIdentity) ?? null : null;
34659
+ if (projectIdentity) {
34660
+ try {
34661
+ dreamerBacklog = getDreamTaskBacklogs(db, projectIdentity, CANONICAL_DREAM_TASKS);
34662
+ } catch {}
34663
+ }
34388
34664
  if (projectIdentity) {
34389
34665
  try {
34390
34666
  lastDreamerRunAt = getMostRecentTaskRunAt(db, projectIdentity);
@@ -34480,6 +34756,8 @@ function buildSidebarSnapshot(db, sessionId, directory, liveSessionState, inject
34480
34756
  lastTransformError: meta?.last_transform_error ? String(meta.last_transform_error) : null,
34481
34757
  lastDreamerRunAt,
34482
34758
  projectIdentity,
34759
+ dreamerBacklog,
34760
+ dreamerProgress,
34483
34761
  compartmentTokens: calibrated.compartmentTokens,
34484
34762
  factTokens: calibrated.factTokens,
34485
34763
  memoryTokens: calibrated.memoryTokens,
@@ -34721,7 +34999,7 @@ function registerRpcHandlers(rpcServer, args) {
34721
34999
  const buildManagedCtx = async (db) => {
34722
35000
  const { deriveHistorianChunkTokens: deriveHistorianChunkTokens2, resolveHistorianContextLimit: resolveHistorianContextLimit2 } = await import("./derive-budgets-9crp0cvd.js");
34723
35001
  const { resolveFallbackChain: resolveFallbackChain2 } = await import("./resolve-fallbacks-5n5tvge1.js");
34724
- const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-5nx3qfz8.js");
35002
+ const { userMemoryCollectionEnabled: userMemoryCollectionEnabled2 } = await import("./task-config-gbp7r23g.js");
34725
35003
  const DEFAULT_HISTORIAN_TIMEOUT_MS2 = 600000;
34726
35004
  return {
34727
35005
  client: args.client,
@@ -34746,7 +35024,7 @@ function registerRpcHandlers(rpcServer, args) {
34746
35024
  const db = getDb();
34747
35025
  if (!db)
34748
35026
  return { ok: false, error: "db unavailable" };
34749
- const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-8e82vmvb.js");
35027
+ const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-k72ejkkh.js");
34750
35028
  const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
34751
35029
  log(`[rpc] recomp requested for session ${sessionId}`);
34752
35030
  const ctx = await buildManagedCtx(db);
@@ -34762,7 +35040,7 @@ function registerRpcHandlers(rpcServer, args) {
34762
35040
  const db = getDb();
34763
35041
  if (!db)
34764
35042
  return { ok: false, error: "db unavailable" };
34765
- const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-8e82vmvb.js");
35043
+ const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-k72ejkkh.js");
34766
35044
  const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-6njqewzk.js");
34767
35045
  log(`[rpc] session-upgrade requested for session ${sessionId}`);
34768
35046
  const ctx = await buildManagedCtx(db);
@@ -37014,13 +37292,20 @@ var server = async (ctx) => {
37014
37292
  embeddingConfig: pluginConfig.embedding,
37015
37293
  memoryEnabled: pluginConfig.memory?.enabled === true,
37016
37294
  memoryInjectionBudgetTokens: pluginConfig.memory?.injection_budget_tokens,
37017
- experimentalMural: pluginConfig.experimental?.mural,
37295
+ mural: pluginConfig.mural,
37018
37296
  gitCommitIndexing: pluginConfig.memory.git_commit_indexing?.enabled ? {
37019
37297
  enabled: true,
37020
37298
  since_days: pluginConfig.memory.git_commit_indexing.since_days,
37021
37299
  max_commits: pluginConfig.memory.git_commit_indexing.max_commits
37022
37300
  } : undefined,
37023
37301
  ensureRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
37302
+ onDreamerProgress: (progress, completedTask) => {
37303
+ if (progress) {
37304
+ liveSessionState.dreamerProgressByProject.set(timerProjectIdentity, progress);
37305
+ } else if (liveSessionState.dreamerProgressByProject.get(timerProjectIdentity)?.task === completedTask) {
37306
+ liveSessionState.dreamerProgressByProject.delete(timerProjectIdentity);
37307
+ }
37308
+ },
37024
37309
  moduleClient: classifyModuleClient
37025
37310
  };
37026
37311
  try {