pi-ui-extend 1.0.41 → 1.0.45

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 (236) hide show
  1. package/README.md +50 -13
  2. package/dist/app/app.d.ts +13 -0
  3. package/dist/app/app.js +158 -8
  4. package/dist/app/cli/install.js +2 -2
  5. package/dist/app/commands/command-controller.d.ts +4 -0
  6. package/dist/app/commands/command-controller.js +11 -0
  7. package/dist/app/commands/command-git-actions.d.ts +25 -0
  8. package/dist/app/commands/command-git-actions.js +381 -0
  9. package/dist/app/commands/command-host.d.ts +4 -0
  10. package/dist/app/commands/command-host.js +5 -2
  11. package/dist/app/commands/command-model-actions.d.ts +1 -0
  12. package/dist/app/commands/command-model-actions.js +57 -35
  13. package/dist/app/commands/command-navigation-actions.d.ts +1 -0
  14. package/dist/app/commands/command-navigation-actions.js +16 -3
  15. package/dist/app/commands/command-registry.d.ts +2 -0
  16. package/dist/app/commands/command-registry.js +15 -1
  17. package/dist/app/commands/command-session-actions.js +9 -3
  18. package/dist/app/commands/reload-context-inventory.d.ts +11 -0
  19. package/dist/app/commands/reload-context-inventory.js +70 -0
  20. package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
  21. package/dist/app/extensions/extension-actions-controller.js +6 -0
  22. package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
  23. package/dist/app/extensions/subagent-catalog-state.js +23 -0
  24. package/dist/app/input/autocomplete-controller.js +61 -34
  25. package/dist/app/input/input-action-controller.d.ts +2 -0
  26. package/dist/app/input/input-action-controller.js +8 -1
  27. package/dist/app/input/input-controller.d.ts +2 -1
  28. package/dist/app/input/input-controller.js +7 -2
  29. package/dist/app/input/prompt-enhancer-controller.js +53 -35
  30. package/dist/app/input/voice-controller.d.ts +41 -45
  31. package/dist/app/input/voice-controller.js +351 -419
  32. package/dist/app/model/model-usage-controller.js +17 -7
  33. package/dist/app/model/model-usage-status.d.ts +4 -1
  34. package/dist/app/model/model-usage-status.js +270 -46
  35. package/dist/app/popup/menu-items-controller.d.ts +13 -3
  36. package/dist/app/popup/menu-items-controller.js +37 -21
  37. package/dist/app/popup/popup-action-controller.d.ts +12 -2
  38. package/dist/app/popup/popup-action-controller.js +77 -24
  39. package/dist/app/popup/popup-menu-controller.d.ts +36 -14
  40. package/dist/app/popup/popup-menu-controller.js +239 -69
  41. package/dist/app/rendering/dcp-stats.d.ts +9 -4
  42. package/dist/app/rendering/dcp-stats.js +40 -425
  43. package/dist/app/rendering/editor-panels.js +10 -4
  44. package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
  45. package/dist/app/rendering/popup-menu-renderer.js +42 -37
  46. package/dist/app/rendering/render-controller.js +23 -2
  47. package/dist/app/rendering/status-line-renderer.d.ts +5 -0
  48. package/dist/app/rendering/status-line-renderer.js +41 -5
  49. package/dist/app/rendering/tab-line-renderer.js +26 -20
  50. package/dist/app/runtime.d.ts +12 -1
  51. package/dist/app/runtime.js +120 -12
  52. package/dist/app/screen/mouse-controller.d.ts +2 -0
  53. package/dist/app/screen/mouse-controller.js +17 -7
  54. package/dist/app/screen/status-controller.d.ts +4 -0
  55. package/dist/app/screen/status-controller.js +5 -0
  56. package/dist/app/session/lazy-session-manager.js +34 -0
  57. package/dist/app/session/session-event-controller.d.ts +1 -0
  58. package/dist/app/session/session-event-controller.js +10 -1
  59. package/dist/app/session/session-history.d.ts +1 -0
  60. package/dist/app/session/session-history.js +12 -1
  61. package/dist/app/session/session-lifecycle-controller.d.ts +7 -1
  62. package/dist/app/session/session-lifecycle-controller.js +16 -1
  63. package/dist/app/session/tabs-controller.d.ts +26 -1
  64. package/dist/app/session/tabs-controller.js +454 -147
  65. package/dist/app/subagents/subagents-files.js +60 -1
  66. package/dist/app/subagents/subagents-model.d.ts +1 -0
  67. package/dist/app/subagents/subagents-model.js +18 -2
  68. package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
  69. package/dist/app/subagents/subagents-widget-controller.js +6 -0
  70. package/dist/app/types.d.ts +16 -1
  71. package/dist/app/workspace/workspace-actions-controller.js +10 -2
  72. package/dist/app/workspace/workspace-undo.d.ts +1 -0
  73. package/dist/app/workspace/workspace-undo.js +1 -0
  74. package/dist/bundled-extensions/question/index.js +9 -1
  75. package/dist/bundled-extensions/question/remote.d.ts +4 -0
  76. package/dist/bundled-extensions/question/remote.js +33 -0
  77. package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
  78. package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
  79. package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
  80. package/dist/bundled-extensions/telegram-connector/config.js +87 -0
  81. package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
  82. package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
  83. package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
  84. package/dist/bundled-extensions/telegram-connector/index.js +195 -0
  85. package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
  86. package/dist/bundled-extensions/terminal-bell/index.js +0 -76
  87. package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
  88. package/dist/bundled-extensions/workspace-undo/index.js +191 -0
  89. package/dist/config.d.ts +21 -2
  90. package/dist/config.js +159 -32
  91. package/dist/default-pix-config.js +25 -5
  92. package/dist/schemas/index.d.ts +1 -0
  93. package/dist/schemas/index.js +1 -0
  94. package/dist/schemas/pi-tools-suite-schema.d.ts +88 -62
  95. package/dist/schemas/pi-tools-suite-schema.js +54 -83
  96. package/dist/schemas/pix-schema.d.ts +19 -2
  97. package/dist/schemas/pix-schema.js +47 -5
  98. package/dist/schemas/tasks-schema.d.ts +18 -0
  99. package/dist/schemas/tasks-schema.js +41 -0
  100. package/docs/concurrency.md +9 -1
  101. package/docs/desktop-mvp.md +22 -6
  102. package/docs/desktop-task-manager.md +148 -84
  103. package/docs/release.md +30 -6
  104. package/external/pi-tools-suite/README.md +197 -84
  105. package/external/pi-tools-suite/docs/evals.md +1 -1
  106. package/external/pi-tools-suite/docs/session-recovery.md +47 -14
  107. package/external/pi-tools-suite/docs/subagent-model-pools.md +48 -30
  108. package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
  109. package/external/pi-tools-suite/package.json +6 -1
  110. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
  111. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
  112. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
  113. package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
  114. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
  115. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
  116. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
  117. package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
  118. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
  119. package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
  120. package/external/pi-tools-suite/src/async-subagents/agents/research.md +5 -3
  121. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
  122. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
  123. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
  124. package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
  125. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
  126. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
  127. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
  128. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
  129. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
  130. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
  131. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
  132. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
  133. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
  134. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
  135. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
  136. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
  137. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
  138. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
  139. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
  140. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
  141. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
  142. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
  143. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
  144. package/external/pi-tools-suite/src/async-subagents/commands.ts +15 -71
  145. package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
  146. package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +5 -4
  147. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
  148. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +8 -5
  149. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
  150. package/external/pi-tools-suite/src/async-subagents/core/config.ts +160 -327
  151. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
  152. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
  153. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +21 -5
  154. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +40 -26
  155. package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
  156. package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
  157. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
  158. package/external/pi-tools-suite/src/async-subagents/index.ts +69 -5
  159. package/external/pi-tools-suite/src/async-subagents/lib.ts +16 -9
  160. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +8 -5
  161. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +5 -4
  162. package/external/pi-tools-suite/src/async-subagents/types.ts +1 -0
  163. package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
  164. package/external/pi-tools-suite/src/config.ts +55 -1
  165. package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
  166. package/external/pi-tools-suite/src/context-gateway/config.ts +77 -3
  167. package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
  168. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +222 -0
  169. package/external/pi-tools-suite/src/context-gateway/index.ts +206 -19
  170. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +7 -7
  171. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +101 -28
  172. package/external/pi-tools-suite/src/context-gateway/types.ts +16 -3
  173. package/external/pi-tools-suite/src/context-inventory.ts +99 -0
  174. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
  175. package/external/pi-tools-suite/src/dcp/auto-compress.ts +128 -49
  176. package/external/pi-tools-suite/src/dcp/commands.ts +32 -156
  177. package/external/pi-tools-suite/src/dcp/compress-tool.ts +177 -46
  178. package/external/pi-tools-suite/src/dcp/compression-blocks.ts +6 -58
  179. package/external/pi-tools-suite/src/dcp/compression-preview.ts +9 -0
  180. package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
  181. package/external/pi-tools-suite/src/dcp/config.ts +114 -17
  182. package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
  183. package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
  184. package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
  185. package/external/pi-tools-suite/src/dcp/index.ts +338 -66
  186. package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
  187. package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
  188. package/external/pi-tools-suite/src/dcp/prompts.ts +83 -192
  189. package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
  190. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +93 -3
  191. package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +6 -10
  192. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
  193. package/external/pi-tools-suite/src/dcp/pruner-tools.ts +6 -3
  194. package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
  195. package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
  196. package/external/pi-tools-suite/src/dcp/state.ts +9 -0
  197. package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
  198. package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
  199. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +78 -22
  200. package/external/pi-tools-suite/src/index.ts +7 -1
  201. package/external/pi-tools-suite/src/lib/project.ts +36 -1
  202. package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
  203. package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
  204. package/external/pi-tools-suite/src/resource-registry/index.ts +2551 -0
  205. package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
  206. package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
  207. package/external/pi-tools-suite/src/todo/index.ts +21 -0
  208. package/external/pi-tools-suite/src/todo/todo.ts +19 -1
  209. package/external/pi-tools-suite/src/tool-descriptions.ts +47 -19
  210. package/package.json +10 -9
  211. package/schemas/pi-tools-suite.json +466 -287
  212. package/schemas/pix.json +129 -11
  213. package/schemas/tasks.json +131 -0
  214. package/skills/simplify/SKILL.md +33 -5
  215. package/docs/desktop-markdown-media.md +0 -77
  216. package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -177
  217. package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
  218. package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
  219. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -54
  220. package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
  221. package/skills/playwright-cli/SKILL.md +0 -420
  222. package/skills/playwright-cli/references/element-attributes.md +0 -23
  223. package/skills/playwright-cli/references/playwright-tests.md +0 -50
  224. package/skills/playwright-cli/references/request-mocking.md +0 -87
  225. package/skills/playwright-cli/references/running-code.md +0 -241
  226. package/skills/playwright-cli/references/session-management.md +0 -273
  227. package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
  228. package/skills/playwright-cli/references/storage-state.md +0 -290
  229. package/skills/playwright-cli/references/test-generation.md +0 -142
  230. package/skills/playwright-cli/references/tracing.md +0 -154
  231. package/skills/playwright-cli/references/video-recording.md +0 -147
  232. package/skills/spec-lite/SKILL.md +0 -140
  233. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
  234. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
  235. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
  236. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
@@ -128,6 +128,16 @@ function validateExactBlock(value: unknown): asserts value is CompressionBlock {
128
128
  throw new DcpJournalError(`DCP journal block b${value.id} has invalid ${key}`);
129
129
  }
130
130
  }
131
+ if (value.commitMetrics !== undefined) {
132
+ const m = value.commitMetrics;
133
+ if (!isRecord(m) || typeof m.operationId !== "string" || !m.operationId ||
134
+ !["manual", "auto", "consolidation"].includes(m.kind as string) ||
135
+ !finiteNonNegativeInteger(m.beforeTokens) || !finiteNonNegativeInteger(m.afterTokens) ||
136
+ !finiteNonNegativeInteger(m.netGainTokens) || m.netGainTokens <= 0 ||
137
+ m.beforeTokens - m.afterTokens !== m.netGainTokens) {
138
+ throw new DcpJournalError(`DCP journal block b${value.id} has invalid commit metrics`);
139
+ }
140
+ }
131
141
  for (const key of ["sourceMembers", "mutationMembers"] as const) {
132
142
  const members = value[key];
133
143
  if (!Array.isArray(members) || members.length === 0) {
@@ -438,13 +448,125 @@ function journalBranch(ctx: ExtensionContext): unknown[] {
438
448
  }
439
449
  }
440
450
 
451
+ function indexBranchParents(entries: readonly unknown[], requireFullChain: boolean): Map<string, string | null> | undefined {
452
+ const parents = new Map<string, string | null>();
453
+ let previousId: string | null = null;
454
+ for (const entry of entries) {
455
+ if (!isRecord(entry) || typeof entry.id !== "string" || !entry.id
456
+ || parents.has(entry.id)) return undefined;
457
+ let parentId: string | null = null;
458
+ if (entry.parentId !== null) {
459
+ if (typeof entry.parentId !== "string" || !entry.parentId) return undefined;
460
+ parentId = entry.parentId;
461
+ }
462
+ if (requireFullChain && parentId !== previousId) return undefined;
463
+ parents.set(entry.id, parentId);
464
+ previousId = entry.id;
465
+ }
466
+ return parents;
467
+ }
468
+
469
+ /**
470
+ * getBranch() on Pix's lazy manager is a JSONL presentation tail: it may omit
471
+ * older ancestors AND interleave abandoned branches. Do not "simplify" this
472
+ * into a positional prefix/suffix comparison or an ID-membership test.
473
+ *
474
+ * Walk parentId from the captured current leaf. Only the full read may supply
475
+ * ancestors missing from the tail; overlapping IDs must have identical parents
476
+ * (SDK entry identities/parent links are immutable). Both the old leaf and the
477
+ * read tip must lie on that walk. A side-branch tip merely present in the tail
478
+ * is not evidence. Missing links/cycles/conflicts deny the retry.
479
+ *
480
+ * This proves permission to re-read, NOT a publishable merged snapshot. Never
481
+ * return the tail/union as history or hydrate synchronously to validate it.
482
+ * Contract + counterexample: specs/dcp-statistics.md#lazy-tail-retry-invariant.
483
+ */
484
+ function readSnapshotFollowsCurrentBranch(
485
+ entries: readonly unknown[],
486
+ currentEntries: readonly unknown[],
487
+ previousLeafId: string,
488
+ currentLeafId: string,
489
+ ): boolean {
490
+ const readParents = indexBranchParents(entries, true);
491
+ const currentParents = indexBranchParents(currentEntries, false);
492
+ if (!readParents?.has(previousLeafId) || !currentParents?.has(currentLeafId)) return false;
493
+
494
+ const readTipId = (entries.at(-1) as { id: string }).id;
495
+ const visited = new Set<string>();
496
+ let cursor: string | null = currentLeafId;
497
+ let reachedPrevious = false;
498
+ let reachedReadTip = false;
499
+ while (cursor !== null) {
500
+ if (visited.has(cursor)) return false;
501
+ visited.add(cursor);
502
+ const currentParent = currentParents.get(cursor);
503
+ const readParent = readParents.get(cursor);
504
+ if (currentParent !== undefined && readParent !== undefined && currentParent !== readParent) return false;
505
+ // An absent old ancestor may be supplied by the full read, but a missing
506
+ // new descendant cannot be guessed. Null is a root, not a missing value.
507
+ const parent = currentParent !== undefined ? currentParent : readParent;
508
+ if (parent === undefined) return false;
509
+ reachedPrevious ||= cursor === previousLeafId;
510
+ reachedReadTip ||= cursor === readTipId;
511
+ cursor = parent;
512
+ }
513
+ return reachedPrevious && reachedReadTip;
514
+ }
515
+
441
516
  export async function readDcpJournalBranch(ctx: ExtensionContext): Promise<unknown[]> {
442
517
  const manager = ctx.sessionManager as any;
443
- if (typeof manager.readFullBranchEntries === "function") {
444
- const entries = await manager.readFullBranchEntries();
445
- return Array.isArray(entries) ? entries : [];
518
+ const sessionId = manager.getSessionId?.();
519
+ const hasLeafIdentity = typeof manager.getLeafId === "function";
520
+ const readFullBranch = typeof manager.readFullBranchEntries === "function"
521
+ ? () => manager.readFullBranchEntries()
522
+ : undefined;
523
+
524
+ // Lazy full-history reads yield to the event loop. A normal append on the
525
+ // same active branch (for example, tool results arriving while a reloaded
526
+ // runtime is replaying its journal) advances the leaf without changing the
527
+ // branch owner. Retry that transient race so startup does not permanently
528
+ // block DCP. A real branch move/fork, owner replacement, or a branch that
529
+ // keeps moving still fails closed.
530
+ const maxAttempts = readFullBranch ? 3 : 1;
531
+ for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
532
+ const leafId = manager.getLeafId?.();
533
+ const entries = readFullBranch ? await readFullBranch() : manager.getBranch();
534
+ if (ctx.sessionManager !== manager || manager.getSessionId?.() !== sessionId) {
535
+ throw new DcpJournalError("DCP branch changed during history read; rebuild context");
536
+ }
537
+ if (!Array.isArray(entries)) throw new DcpJournalError("DCP full branch is unavailable");
538
+ // A presentation cursor is not a complete SDK branch, even if it contains
539
+ // recent users or journal deltas. Never silently initialize from that tail.
540
+ if (entries[0]?.parentId != null) throw new DcpJournalError("DCP received an incomplete branch (presentation tail)");
541
+
542
+ const currentLeafId = manager.getLeafId?.();
543
+ if (currentLeafId === leafId) {
544
+ if (hasLeafIdentity) {
545
+ const readLeafId = entries.at(-1)?.id;
546
+ if ((leafId == null && entries.length > 0) || (leafId != null && readLeafId !== leafId)) {
547
+ throw new DcpJournalError("DCP branch changed during history read; rebuild context");
548
+ }
549
+ }
550
+ return entries;
551
+ }
552
+
553
+ let sameBranchAdvance = false;
554
+ if (leafId && currentLeafId) {
555
+ try {
556
+ const currentEntries = manager.getBranch();
557
+ sameBranchAdvance = Array.isArray(currentEntries)
558
+ && manager.getLeafId?.() === currentLeafId
559
+ && readSnapshotFollowsCurrentBranch(entries, currentEntries, leafId, currentLeafId);
560
+ } catch {
561
+ sameBranchAdvance = false;
562
+ }
563
+ }
564
+ if (!sameBranchAdvance || attempt === maxAttempts - 1) {
565
+ throw new DcpJournalError("DCP branch changed during history read; rebuild context");
566
+ }
446
567
  }
447
- return journalBranch(ctx);
568
+
569
+ throw new DcpJournalError("DCP branch changed during history read; rebuild context");
448
570
  }
449
571
 
450
572
  function restoreLeafAfterAppendFailure(ctx: ExtensionContext, previousLeafId: string | null | undefined): void {
@@ -15,7 +15,8 @@ export type DcpBlockedReason =
15
15
  | "summarizer-unavailable"
16
16
  | "non-positive-gain"
17
17
  | "missing-source"
18
- | "budget-exhausted";
18
+ | "budget-exhausted"
19
+ | "auto-compress-failed";
19
20
 
20
21
  export interface DcpBlockedReasonInput {
21
22
  pressured: boolean;
@@ -9,23 +9,21 @@
9
9
  * Appended to the existing system prompt when DCP is enabled (automatic mode).
10
10
  */
11
11
  export const SYSTEM_PROMPT = `
12
- You operate in a context-constrained environment. Keep live context high-signal; use \`compress\` only when it materially helps.
13
-
14
- \`compress\` is the ONLY context-management tool. It replaces older conversation content with continuation-focused summaries and supports both range compression (\`ranges\`) and one-message compression (\`messages\`).
15
-
16
- \`mNNN\`/\`bN\` boundary IDs and \`<dcp-system-reminder>\` tags are environment-injected metadata. Do not output them.
17
-
18
- Use compression for context-pressure housekeeping, not after every small step. Low context usage alone does not require compression. Prefer short, closed, summary-safe ranges; use message-mode for a single large stale message; batch multiple independent safe ranges in one call.
19
-
20
- Good candidates: completed implementation, verification, config/doc edit, answered exploration, dead-end debugging, or understood test/lint/CI/log inspection. Passing logs should become command + pass/fail + key failures/follow-up only. Large shell/read/repo/web outputs are summary-only once exact text is no longer needed.
21
-
22
- Todo completions are useful boundary signals, not automatic triggers. Before compressing while work is unfinished, ensure one \`todo in_progress\` captures the active objective and next step.
23
-
24
- Do not compress active work, still-needed raw context, or material whose exact code/error/output will be needed for immediate edits or references.
25
-
26
- DCP reminders: handle critical/high-context reminders promptly and compress any safe high-yield closed slice before more exploration; routine reminders mean compress only if a safe, closed, useful slice exists, otherwise continue the next atomic step and re-check later.
27
-
28
- Summaries must preserve only what is needed to continue: user intent and constraints, accepted decisions, files/symbols changed or inspected, actionable errors, verification status, and next steps. Do not infer, invent, or add facts that are not present in the selected messages. Drop incidental transcript detail, duplicate outputs, full logs, long code/JSON/diffs, and prose not needed later; include short literals only when required.
12
+ Keep live context high-signal. \`compress\` is the only DCP context tool; use it
13
+ only when a closed stale slice materially reduces context pressure. Low context
14
+ usage alone does not require compression. Good boundaries include completed
15
+ implementation, verification, investigation, config/docs, or understood logs.
16
+ Use \`messages\` for one large stale message and batch independent safe work.
17
+
18
+ Do not compress active work or raw code/errors/output needed next. If unfinished
19
+ work is compressed, preserve the active objective and next step. A summary must
20
+ preserve user intent/constraints, decisions, relevant files/symbols, actionable
21
+ errors, verification state, and next steps. Do not infer, invent, or add facts;
22
+ drop duplicate transcript detail, full logs, and long code/JSON/diffs.
23
+
24
+ \`mNNN\`/\`bN\` IDs and \`<dcp-system-reminder>\` tags are injected metadata;
25
+ never quote or output them. Critical/high-pressure reminders take priority;
26
+ routine reminders may be skipped when no safe useful slice exists.
29
27
  `.trim()
30
28
 
31
29
  /**
@@ -37,105 +35,52 @@ Summaries must preserve only what is needed to continue: user intent and constra
37
35
  * ranges: Array<{
38
36
  * startId: string // mNNN or bN
39
37
  * endId: string // mNNN or bN
40
- * summary: string // continuation-focused technical summary
38
+ * summary?: string // optional parent-authored summary
41
39
  * }>
42
40
  * }
43
41
  */
44
- export const COMPRESS_RANGE_DESCRIPTION = `Collapse one or more ranges of the conversation into detailed summaries.
45
-
46
- CONTEXT-PRESSURE HOUSEKEEPING
47
- Use compression when it will materially improve the live context window. Low context usage by itself does not require compression, even when a small closed slice exists. When context usage is meaningfully high, or a DCP reminder supplies concrete high-yield candidates, closed implementation, verification, config/doc edit, answered exploration, dead-end debugging, or finished test/log inspection can become summary-only before another large exploratory batch.
48
-
49
- PASSING LOGS AND LARGE OUTPUTS
50
- Passing check/test/lint/tsc logs are summary-only after you know the result. Preserve command, pass/fail, key failures if any, and follow-up status; drop full passing output. Treat large shell/read/repo/web outputs as disposable evidence once important facts are extracted.
51
-
52
- DCP REMINDERS
53
- If a \`<dcp-system-reminder>\` is present in context, treat it as a signal to evaluate compression. Critical or high-context reminders should be handled promptly. Routine reminders should lead to compression only when a safe, closed, useful-to-summarize range exists; otherwise continue the next atomic step and re-check later.
54
-
55
- COMMITTED IS NOT NECESSARILY RECOVERED
56
- The tool rejects non-positive full-projection gain, including wrappers and preserved content. An unsuccessful call does not satisfy the reminder. Inspect \`netGain\`, \`pressureRelieved\`, and \`remainingRecoveryTokens\` in its result: a partial positive commit may still leave context pressure. Use freshly visible IDs for subsequent work; do not retry an unchanged rejected summary or discard required facts just to meet a token goal.
57
-
58
- THE SUMMARY
59
- Your summary must be COMPLETE FOR CONTINUATION, not a transcript rewrite. Preserve only information that will plausibly matter later: user intent, accepted constraints, decisions, files/symbols changed or inspected, exact errors that are still actionable, verification status, and next steps.
60
-
61
- Do not infer, invent, or add facts that are not present in the selected range. If the source is uncertain or incomplete, preserve that uncertainty instead of filling gaps.
62
-
63
- If active unfinished work exists, start with \`Active objective\` and \`Next step\`.
64
-
65
- Default to a compact structured summary (roughly 4-10 bullets for a normal completed work slice). Grow beyond that only when the compressed range contains multiple independent decisions, unresolved blockers, or precise state that is genuinely required to continue.
66
-
67
- Do not copy long raw code, JSON, diffs, logs, or tool output into summaries. Prefer semantic descriptions such as “updated foo.json so scene_assets_1.zai-svg has maxConcurrentRuns set to 5.” Include exact snippets only when the literal text is required for safe continuation, and keep them short and single-line.
68
-
69
- SUMMARY ARGUMENT SAFETY
70
- The summary is passed as a JSON string argument to the compress tool. Avoid raw double-quoted JSON fragments, multiline object literals, and diff hunks because they can make tool-call arguments malformed. If a literal field name matters, prefer plain prose or quote-light code spans such as \`maxConcurrentRuns: 5\` instead of raw \`"maxConcurrentRuns": 5\` blocks.
71
-
72
- USER INTENT FIDELITY
73
- When the compressed range includes user messages, preserve the user's intent with extra care. Do not change scope, constraints, priorities, acceptance criteria, or requested outcomes.
74
- Directly quote user messages when they are short enough to include safely. Direct quotes are preferred when they best preserve exact meaning.
75
-
76
- Be LEAN. Strip away full logs, repeated search/read output, duplicate summaries, incidental failed attempts, and line-by-line edit history. What remains should be pure signal with enough detail to resume work confidently.
77
-
78
- TWO COMPRESSION MODES
79
- You may use either or both modes in one call:
80
-
81
- - \`ranges\`: collapse contiguous conversation spans using \`startId\`, \`endId\`, and \`summary\`.
82
- - \`messages\`: collapse individual raw messages using \`messageId\`, optional \`topic\`, and \`summary\`.
83
-
84
- Use \`messages\` for a single large stale message when surrounding messages should remain raw. \`messages\` accepts only raw \`mNNN\` IDs, not \`bN\` compressed block IDs.
85
-
86
- PROTECTED PROMPT CONTENT
87
- If selected user text contains \`<protect>...</protect>\` content, preserve that protected content verbatim in your summary. The tool may append protected text automatically, but you should still account for it semantically.
88
-
89
- COMPRESSED BLOCK PLACEHOLDERS
90
- When rolling up compressed blocks, summarize their continuation-relevant meaning instead of copying the full old summaries. Every block carries a protected-fragment ledger, and those fragments are preserved separately. A block missing that ledger is invalid and must not be rolled up.
91
-
92
- Only when the full previous summary is genuinely needed verbatim, use this exact placeholder format:
93
-
94
- - \`(bN)\`
95
-
96
- Compressed block sections in context are clearly marked with a header:
97
-
98
- - \`[Compressed conversation section]\`
99
-
100
- Compressed block IDs always use the \`bN\` form (never \`mNNN\`) and are represented as hidden DCP metadata.
101
-
102
- Rules:
103
-
104
- - Placeholders are optional, not required for every covered modern block. Each explicit placeholder expands the full old summary and may eliminate the intended savings. Include an intentionally preserved block at most once.
105
- - Do not invent placeholders for blocks outside the selected range.
106
- - Treat \`(bN)\` placeholders as RESERVED TOKENS. Do not emit \`(bN)\` text anywhere except intentional placeholders.
107
- - If you need to mention a block in prose, use plain text like \`compressed bN\` (not as a placeholder).
108
- - Preflight check before finalizing: each placeholder must refer to a known selected block whose full text you deliberately need to preserve. Otherwise write a concise factual summary in your own words.
109
-
110
- These placeholders are semantic references. They will be replaced with the full stored compressed block content when the tool processes your output.
111
-
112
- FLOW PRESERVATION WITH PLACEHOLDERS
113
- When you use compressed block placeholders, write the surrounding summary text so it still reads correctly AFTER placeholder expansion.
114
-
115
- - Treat each placeholder as a stand-in for a full conversation segment, not as a short label.
116
- - Ensure transitions before and after each placeholder preserve chronology and causality.
117
- - Do not write text that depends on the placeholder staying literal (for example, "as noted in \`(b2)\`").
118
- - Your final meaning must be coherent once each placeholder is replaced with its full compressed block content.
119
-
120
- BOUNDARY IDS
121
- You specify boundaries by ID using the injected metadata IDs present in the conversation context:
122
-
123
- - \`mNNN\` IDs identify raw messages (3 digits, zero-padded, e.g. \`m001\`, \`m042\`)
124
- - \`bN\` IDs identify previously compressed blocks
125
-
126
- Raw message IDs are provided in hidden DCP control metadata attached to stable user/tool-result carriers. IDs may be sparse; determine range order from where their carriers appear in context, not from the numeric suffix.
127
- Some message-compression candidate hints include a low/medium/high priority; prefer high-priority stale message IDs for message-mode compression when a full range would be too broad.
128
- Each carrier's metadata labels that carrier and any immediately preceding assistant message(s).
129
- Treat these reference lines as boundary metadata only, not as tool result content.
130
-
131
- Rules:
132
-
133
- - Use only injected IDs in current context; \`startId\` must precede \`endId\`. Do not invent IDs.
134
- - For \`ranges\`, never split a tool group: include the calling assistant and all its tool results, including parallel calls.
135
- - If \`compress\` fails with \`Unknown message ID\`, treat those IDs as stale; retry at most once using only the error's listed current raw IDs or eligible \`bN\` blocks, or skip if no closed range is safe.
136
-
137
- BATCHING
138
- When multiple independent ranges or individual messages are ready, include all of them in one \`compress\` call. Range entries must not overlap. Message entries should each summarize exactly one raw message.`
42
+ export const COMPRESS_RANGE_DESCRIPTION = `Replace closed stale context with continuation-focused summaries.
43
+
44
+ WHEN: compress only when it materially improves live context or a DCP reminder
45
+ identifies useful stale work. Do not compress active/still-needed material. Passing
46
+ test/lint/build logs may become command + outcome + actionable failures; discard
47
+ raw logs/read/search output after their facts are captured.
48
+
49
+ SUMMARY: make it COMPLETE FOR CONTINUATION, not a transcript rewrite. Preserve
50
+ user intent/constraints, decisions, files/symbols changed or inspected, exact
51
+ errors that are still actionable, verification state, unresolved blockers, and
52
+ next steps. If work remains unfinished include \`Active objective\` and \`Next
53
+ step\`. Do not infer, invent, or add facts. Preserve uncertainty. Do not copy long
54
+ raw code, JSON, diffs, logs, or tool output; use short literals only when needed.
55
+ Normally omit \`summary\`: DCP generates it. An explicit \`summary\` overrides
56
+ generation when parent-authored continuation wording is genuinely required.
57
+
58
+ MODES:
59
+ - \`ranges\`: contiguous \`startId..endId\` spans.
60
+ - \`messages\`: one raw \`mNNN\` body when neighbours should remain raw. Use
61
+ \`messages\` for a single large stale message; it does not accept \`bN\`.
62
+ Batch independent non-overlapping selections in one call.
63
+
64
+ BOUNDARIES: use only injected IDs currently visible on stable user/tool-result
65
+ carriers. \`mNNN\` is raw, \`bN\` is an active compressed block; IDs may be sparse
66
+ and order is the conversation order, not the number. Carrier metadata labels the
67
+ carrier plus immediately preceding assistant message(s): \`a\`=assistant,
68
+ \`u\`=user, \`t\`=tool result, \`x\`=bash result, \`b\`=block alias. Do not invent IDs. For
69
+ \`ranges\`, never split a tool group: include the calling assistant and all its
70
+ tool results, including parallel calls. On \`Unknown message ID\`, retry at most
71
+ once using the current IDs reported by the tool.
72
+
73
+ PROTECTION/ROLLUP: preserve \`<protect>...</protect>\` text verbatim. When a
74
+ selected range contains compressed blocks, summarize their continuation-relevant
75
+ meaning; their protected-fragment ledgers survive separately. Placeholders are
76
+ optional: use \`(bN)\` only when the full selected prior summary is genuinely
77
+ required verbatim, at most once, and never invent a placeholder. Otherwise refer
78
+ to it in prose as \`compressed bN\`.
79
+
80
+ RESULT: the tool rejects non-positive full-projection gain. An unsuccessful call
81
+ does not satisfy a reminder. Inspect \`netGain\`, \`pressureRelieved\`, and
82
+ \`remainingRecoveryTokens\`; a positive partial commit can still leave pressure.
83
+ Do not discard required facts merely to hit a token target.`
139
84
 
140
85
  /**
141
86
  * Injected into messages when context usage exceeds maxContextPercent.
@@ -143,29 +88,11 @@ When multiple independent ranges or individual messages are ready, include all o
143
88
  */
144
89
  export const CONTEXT_LIMIT_NUDGE_STRONG = `<dcp-system-reminder>
145
90
  CRITICAL WARNING: MAX CONTEXT LIMIT REACHED
146
-
147
- You are at or beyond the configured max context threshold. This is an emergency context-recovery moment.
148
-
149
- You MUST use the \`compress\` tool now. Do not continue normal exploration until compression is handled.
150
-
151
- If you are in the middle of a critical atomic operation, finish that atomic step first, then compress immediately.
152
- If any closed slice exists (finished implementation, verification, config/doc edit, answered exploration, dead end, or test/log inspection), compress it before replying or starting another task. Passing logs should become command + pass/fail + follow-up status only.
153
- Recently completed todo/task/subtask items are preferred boundaries when they form a high-yield closed slice.
154
-
155
- RANGE STRATEGY (MANDATORY)
156
- Prioritize one large, closed, high-yield compression range first.
157
- This overrides the normal preference for many small compressions.
158
- Only split into multiple compressions if one large range would reduce summary quality or make boundary selection unsafe.
159
-
160
- RANGE SELECTION
161
- Start from older, resolved history and capture as much stale context as safely possible in one pass.
162
- Avoid the newest active working slice unless it is clearly closed.
163
- Use injected boundary IDs for compression (\`mNNN\` for messages, \`bN\` for compressed blocks), and ensure \`startId\` appears before \`endId\`.
164
- For a single large stale message, use the \`messages\` array with its injected \`mNNN\` ID.
165
-
166
- SUMMARY REQUIREMENTS
167
- Your summary must cover all essential details from the selected range so work can continue without reopening raw messages, but it should not restate raw code, JSON, logs, or diffs unless a short literal is required.
168
- If the compressed range includes user messages, preserve user intent exactly. Prefer direct quotes for short user messages to avoid semantic drift.
91
+ You MUST use the \`compress\` tool now, after any critical atomic step. Prefer one
92
+ large, older, closed high-yield range; split only for safety/summary quality. Keep
93
+ the newest active slice raw. Preserve user intent exactly and all state needed to
94
+ continue, but not full logs/code/diffs. Use current injected IDs; use \`messages\`
95
+ for one isolated large stale message.
169
96
  </dcp-system-reminder>`
170
97
 
171
98
  /**
@@ -174,20 +101,11 @@ If the compressed range includes user messages, preserve user intent exactly. Pr
174
101
  */
175
102
  export const CONTEXT_LIMIT_NUDGE_SOFT = `<dcp-system-reminder>
176
103
  ACTION REQUIRED: Context usage is high.
177
-
178
- Before doing more exploration, look for a high-yield closed range that no longer needs to stay raw. Compress it now if one is safe and useful.
179
-
180
- This is context-pressure guidance, not a request to compress tiny or still-needed slices. If completed research, implementation, verification, config/doc edit, CI-log inspection, or dead-end debugging is large enough to reduce signal, call the \`compress\` tool before continuing normal work.
181
- Recently completed todo/task/subtask items are preferred candidates when they form a non-trivial closed slice; do not compress merely because a tiny todo was completed.
182
- High-priority stale shell/read/repo/web outputs should be compressed once no exact raw text is needed. Passing logs should not remain raw after they are understood.
183
-
184
- RANGE SELECTION
185
- Prefer older, resolved history. Avoid the newest active working slice unless it is clearly done.
186
- Use injected boundary IDs (\`mNNN\` for messages, \`bN\` for compressed blocks) and ensure \`startId\` appears before \`endId\`.
187
- For a single large stale message, use message-mode compression via the \`messages\` array.
188
-
189
- If multiple independent high-yield ranges are ready, batch them in a single \`compress\` call.
190
- If nothing is cleanly closed and worth summarizing yet, continue with the next atomic step and re-check later.
104
+ Before more exploration, compress a high-yield older closed slice if one is safe
105
+ and useful. Keep active/tiny slices raw; understood logs/search/read output are
106
+ good candidates. Batch independent ranges; use message-mode compression for one
107
+ large stale message. If nothing is cleanly closed, continue with the next atomic
108
+ step and re-check later.
191
109
  </dcp-system-reminder>`
192
110
 
193
111
  /**
@@ -196,18 +114,10 @@ If nothing is cleanly closed and worth summarizing yet, continue with the next a
196
114
  */
197
115
  export const TURN_NUDGE = `<dcp-system-reminder>
198
116
  CONTEXT CHECK: Evaluate whether compression would materially improve the live context.
199
-
200
- If a range is cleanly closed, non-trivial, and unlikely to be needed verbatim again, use the \`compress\` tool. If direction has shifted, consider whether earlier ranges are now less relevant.
201
-
202
- If a todo/task/subtask was just completed, treat that completed work as a preferred compression boundary when it is large enough and no longer needed raw; completion alone is not a reason to compress while context is still low.
203
-
204
- Do not compress just because a small slice closed while context is still low. Prefer compression before another large batch of searches, reads, CI log fetches, or tests when a high-yield stale slice exists.
205
- High-priority stale shell/read/repo/web outputs and understood passing logs should be compressed once no exact raw text is needed.
206
-
207
- Prefer small, closed-range compressions over one broad compression.
208
- Use message-mode compression for isolated large stale messages.
209
- The goal is to filter meaningful noise and distill key information so context accumulation stays under control.
210
- Keep active context uncompressed.
117
+ Compress only a non-trivial closed stale slice that no longer needs verbatim text,
118
+ especially before another large tool batch. Do not compress just because a small
119
+ slice closed. Prefer closed ranges; use message-mode compression for an isolated
120
+ large stale message. Keep active context uncompressed.
211
121
  </dcp-system-reminder>`
212
122
 
213
123
  /**
@@ -215,15 +125,10 @@ Keep active context uncompressed.
215
125
  */
216
126
  export const ITERATION_NUDGE = `<dcp-system-reminder>
217
127
  CONTEXT CHECK: You've been iterating for a while after the last user message.
218
-
219
- Pause before the next large non-atomic tool batch. If there is a closed portion that is unlikely to be referenced immediately and is worth summarizing (for example, finished research before implementation, completed config edit, completed CI-log triage, a verified fix, or a dead-end investigation), use the \`compress\` tool on it.
220
-
221
- If a todo/task/subtask was just completed, prefer that completed work as the compression boundary when it is non-trivial and safe to summarize; do not compress merely because the todo status changed.
222
-
223
- Avoid accumulating large tool outputs while a high-yield completed slice remains raw. If only small or still-needed ranges are closed, continue the next atomic step and re-check later.
224
-
225
- Prefer multiple short, closed ranges over one large range when several independent slices are ready.
226
- Use message-mode compression for isolated large stale messages.
128
+ Before another large tool batch, compress completed non-trivial work that no longer
129
+ needs raw detail. Prefer closed ranges; use message-mode compression for an
130
+ isolated large stale message. If only small or still-needed ranges are closed,
131
+ continue the next atomic step and re-check later.
227
132
  </dcp-system-reminder>`
228
133
 
229
134
  /**
@@ -233,25 +138,11 @@ Use message-mode compression for isolated large stale messages.
233
138
  */
234
139
  export const MANUAL_MODE_SYSTEM_PROMPT = `
235
140
  You are operating in DCP manual mode for context management.
236
-
237
- \`mNNN\`/\`bN\` DCP boundary IDs and \`<dcp-system-reminder>\` tags are environment-injected metadata. Do not output them.
238
-
239
- In manual mode you do NOT proactively compress conversation content. Compression is a deliberate, user-directed action.
240
-
241
- WHEN TO COMPRESS
242
- - Only when the user explicitly asks you to compress
243
- - Only when a \`<dcp-system-reminder>\` nudge instructs you to (context-limit emergency)
244
- - Never as background housekeeping or on your own initiative
245
-
246
- WHEN YOU DO COMPRESS
247
- Apply the same quality standards as always:
248
-
249
- - Summaries must be complete for continuation, not transcript-sized; keep only file paths, decisions, findings, exact constraints, unresolved blockers, and verification state that may matter later
250
- - Avoid raw JSON/code/diff/log blocks in summary strings; describe changes in prose or use very short quote-light code spans when literals are necessary
251
- - Preserve user intent precisely; prefer direct quotes for short user messages
252
- - Use only boundary IDs present in context (\`mNNN\` for messages, \`bN\` for compressed blocks)
253
- - Batch independent ranges in a single \`compress\` call when possible
254
- - Use message-mode compression for isolated large stale messages when directed by a context-limit nudge
255
-
256
- Do not compress active, still-needed context. Only compress ranges that are genuinely closed and whose raw form is no longer required.
141
+ Do NOT proactively compress. Use \`compress\` only when the user explicitly asks
142
+ or a \`<dcp-system-reminder>\` requires context-limit recovery. Preserve user
143
+ intent precisely and enough decisions/files/errors/verification/next state to
144
+ continue; omit long raw code/JSON/diffs/logs. Use only visible \`mNNN\`/\`bN\`
145
+ IDs, batch independent safe ranges, and use message-mode for one large stale
146
+ message. Do not compress active, still-needed context. Injected DCP IDs/reminder
147
+ tags are metadata; never output them.
257
148
  `.trim()