pi-ui-extend 1.0.42 → 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 (233) hide show
  1. package/README.md +41 -12
  2. package/dist/app/app.d.ts +10 -0
  3. package/dist/app/app.js +132 -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 +3 -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 +51 -34
  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 +14 -0
  17. package/dist/app/commands/reload-context-inventory.js +12 -1
  18. package/dist/app/input/autocomplete-controller.js +61 -34
  19. package/dist/app/input/input-action-controller.d.ts +2 -0
  20. package/dist/app/input/input-action-controller.js +8 -1
  21. package/dist/app/input/input-controller.d.ts +2 -1
  22. package/dist/app/input/input-controller.js +7 -2
  23. package/dist/app/input/prompt-enhancer-controller.js +53 -35
  24. package/dist/app/input/voice-controller.d.ts +41 -45
  25. package/dist/app/input/voice-controller.js +351 -419
  26. package/dist/app/model/model-usage-controller.js +17 -7
  27. package/dist/app/model/model-usage-status.d.ts +4 -1
  28. package/dist/app/model/model-usage-status.js +270 -46
  29. package/dist/app/popup/menu-items-controller.d.ts +13 -3
  30. package/dist/app/popup/menu-items-controller.js +37 -21
  31. package/dist/app/popup/popup-action-controller.d.ts +12 -2
  32. package/dist/app/popup/popup-action-controller.js +77 -24
  33. package/dist/app/popup/popup-menu-controller.d.ts +36 -14
  34. package/dist/app/popup/popup-menu-controller.js +239 -69
  35. package/dist/app/rendering/dcp-stats.d.ts +9 -4
  36. package/dist/app/rendering/dcp-stats.js +40 -425
  37. package/dist/app/rendering/popup-menu-renderer.d.ts +3 -5
  38. package/dist/app/rendering/popup-menu-renderer.js +42 -37
  39. package/dist/app/rendering/render-controller.js +23 -2
  40. package/dist/app/rendering/status-line-renderer.d.ts +5 -0
  41. package/dist/app/rendering/status-line-renderer.js +41 -5
  42. package/dist/app/rendering/tab-line-renderer.js +26 -20
  43. package/dist/app/runtime.d.ts +12 -1
  44. package/dist/app/runtime.js +120 -12
  45. package/dist/app/screen/mouse-controller.d.ts +2 -0
  46. package/dist/app/screen/mouse-controller.js +17 -7
  47. package/dist/app/screen/status-controller.d.ts +4 -0
  48. package/dist/app/screen/status-controller.js +5 -0
  49. package/dist/app/session/lazy-session-manager.js +34 -0
  50. package/dist/app/session/session-event-controller.d.ts +1 -0
  51. package/dist/app/session/session-event-controller.js +10 -1
  52. package/dist/app/session/session-history.d.ts +1 -0
  53. package/dist/app/session/session-history.js +12 -1
  54. package/dist/app/session/session-lifecycle-controller.d.ts +6 -1
  55. package/dist/app/session/session-lifecycle-controller.js +10 -1
  56. package/dist/app/session/tabs-controller.d.ts +25 -1
  57. package/dist/app/session/tabs-controller.js +442 -153
  58. package/dist/app/subagents/subagents-widget-controller.d.ts +1 -0
  59. package/dist/app/subagents/subagents-widget-controller.js +6 -0
  60. package/dist/app/types.d.ts +11 -1
  61. package/dist/app/workspace/workspace-actions-controller.js +10 -2
  62. package/dist/app/workspace/workspace-undo.d.ts +1 -0
  63. package/dist/app/workspace/workspace-undo.js +1 -0
  64. package/dist/bundled-extensions/question/index.js +9 -1
  65. package/dist/bundled-extensions/question/remote.d.ts +4 -0
  66. package/dist/bundled-extensions/question/remote.js +33 -0
  67. package/dist/bundled-extensions/telegram-connector/bot.d.ts +43 -0
  68. package/dist/bundled-extensions/telegram-connector/bot.js +166 -0
  69. package/dist/bundled-extensions/telegram-connector/config.d.ts +8 -0
  70. package/dist/bundled-extensions/telegram-connector/config.js +87 -0
  71. package/dist/bundled-extensions/telegram-connector/coordinator.d.ts +66 -0
  72. package/dist/bundled-extensions/telegram-connector/coordinator.js +413 -0
  73. package/dist/bundled-extensions/telegram-connector/index.d.ts +3 -0
  74. package/dist/bundled-extensions/telegram-connector/index.js +195 -0
  75. package/dist/bundled-extensions/terminal-bell/index.d.ts +0 -8
  76. package/dist/bundled-extensions/terminal-bell/index.js +0 -76
  77. package/dist/bundled-extensions/workspace-undo/index.d.ts +26 -0
  78. package/dist/bundled-extensions/workspace-undo/index.js +191 -0
  79. package/dist/config.d.ts +21 -2
  80. package/dist/config.js +159 -32
  81. package/dist/default-pix-config.js +20 -10
  82. package/dist/schemas/pi-tools-suite-schema.d.ts +8 -4
  83. package/dist/schemas/pi-tools-suite-schema.js +11 -5
  84. package/dist/schemas/pix-schema.d.ts +12 -2
  85. package/dist/schemas/pix-schema.js +37 -9
  86. package/dist/schemas/tasks-schema.js +1 -1
  87. package/docs/concurrency.md +3 -1
  88. package/docs/desktop-mvp.md +10 -5
  89. package/docs/desktop-task-manager.md +81 -28
  90. package/docs/release.md +30 -6
  91. package/external/pi-tools-suite/README.md +165 -39
  92. package/external/pi-tools-suite/docs/session-recovery.md +7 -0
  93. package/external/pi-tools-suite/docs/subagent-model-pools.md +12 -5
  94. package/external/pi-tools-suite/docs/ui-qa-subagent.md +440 -0
  95. package/external/pi-tools-suite/package.json +6 -1
  96. package/external/pi-tools-suite/src/antigravity-auth/auth-store.ts +2 -1
  97. package/external/pi-tools-suite/src/antigravity-auth/constants.ts +9 -3
  98. package/external/pi-tools-suite/src/antigravity-auth/headers.ts +41 -3
  99. package/external/pi-tools-suite/src/antigravity-auth/models.ts +94 -21
  100. package/external/pi-tools-suite/src/antigravity-auth/oauth.ts +5 -17
  101. package/external/pi-tools-suite/src/antigravity-auth/payload.ts +72 -7
  102. package/external/pi-tools-suite/src/antigravity-auth/stream.ts +13 -1
  103. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +1 -1
  104. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/browser.mjs +346 -0
  105. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/desktop.mjs +1038 -0
  106. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/backends/tui.mjs +759 -0
  107. package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/scripts/browser-qa-runner.mjs +32 -23
  108. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/chrome-devtools/chrome-devtools-provider.mjs +895 -0
  109. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/linux/linux-atspi.py +494 -0
  110. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/macos/macos-accessibility.swift +1085 -0
  111. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/bridge-client.mjs +50 -0
  112. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/native-terminal/native-terminal-host.mjs +501 -0
  113. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/drivers/windows/windows-uia.ps1 +454 -0
  114. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-auth.md +114 -0
  115. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-chrome-devtools.md +91 -0
  116. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser-playwright.md +145 -0
  117. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/browser.md +82 -0
  118. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-linux.md +26 -0
  119. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-macos.md +29 -0
  120. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop-windows.md +23 -0
  121. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/desktop.md +54 -0
  122. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-native-terminal.md +59 -0
  123. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui-pty.md +37 -0
  124. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/guides/tui.md +60 -0
  125. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa/scripts/ui-qa-runner.mjs +535 -0
  126. package/external/pi-tools-suite/src/async-subagents/agents/ui-qa.md +75 -0
  127. package/external/pi-tools-suite/src/async-subagents/commands.ts +1 -1
  128. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
  129. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +0 -2
  130. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +16 -2
  131. package/external/pi-tools-suite/src/async-subagents/core/config.ts +40 -17
  132. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +2 -1
  133. package/external/pi-tools-suite/src/async-subagents/core/registry.ts +158 -33
  134. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +7 -4
  135. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +34 -24
  136. package/external/pi-tools-suite/src/async-subagents/core/ultrawork-auto.ts +51 -45
  137. package/external/pi-tools-suite/src/async-subagents/lib.ts +9 -1
  138. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +0 -1
  139. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +2 -2
  140. package/external/pi-tools-suite/src/coding-discipline/index.ts +90 -59
  141. package/external/pi-tools-suite/src/config.ts +14 -0
  142. package/external/pi-tools-suite/src/context-gateway/accounting-log.ts +282 -0
  143. package/external/pi-tools-suite/src/context-gateway/config.ts +66 -1
  144. package/external/pi-tools-suite/src/context-gateway/efficiency.ts +414 -0
  145. package/external/pi-tools-suite/src/context-gateway/enforcement.ts +123 -3
  146. package/external/pi-tools-suite/src/context-gateway/index.ts +137 -4
  147. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +5 -5
  148. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +2 -2
  149. package/external/pi-tools-suite/src/context-gateway/types.ts +8 -1
  150. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +39 -4
  151. package/external/pi-tools-suite/src/dcp/auto-compress.ts +41 -14
  152. package/external/pi-tools-suite/src/dcp/commands.ts +14 -156
  153. package/external/pi-tools-suite/src/dcp/compress-tool.ts +8 -2
  154. package/external/pi-tools-suite/src/dcp/compression-progress.ts +22 -0
  155. package/external/pi-tools-suite/src/dcp/config.ts +58 -4
  156. package/external/pi-tools-suite/src/dcp/conversation-index.ts +36 -9
  157. package/external/pi-tools-suite/src/dcp/diagnostics.ts +41 -0
  158. package/external/pi-tools-suite/src/dcp/fresh-tool-results.ts +38 -0
  159. package/external/pi-tools-suite/src/dcp/index.ts +338 -66
  160. package/external/pi-tools-suite/src/dcp/journal.ts +126 -4
  161. package/external/pi-tools-suite/src/dcp/progress-controller.ts +2 -1
  162. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +92 -2
  163. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +36 -33
  164. package/external/pi-tools-suite/src/dcp/pruner.ts +1 -0
  165. package/external/pi-tools-suite/src/dcp/routine-pressure.ts +86 -0
  166. package/external/pi-tools-suite/src/dcp/state.ts +9 -0
  167. package/external/pi-tools-suite/src/dcp/statistics.d.ts +8 -0
  168. package/external/pi-tools-suite/src/dcp/statistics.js +156 -0
  169. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +68 -16
  170. package/external/pi-tools-suite/src/lib/project.ts +36 -1
  171. package/external/pi-tools-suite/src/model-tools/index.ts +10 -7
  172. package/external/pi-tools-suite/src/repo-discovery/index.ts +304 -4
  173. package/external/pi-tools-suite/src/resource-registry/index.ts +282 -21
  174. package/external/pi-tools-suite/src/session-recovery/index.ts +17 -0
  175. package/external/pi-tools-suite/src/todo/index.ts +21 -0
  176. package/external/pi-tools-suite/src/todo/todo.ts +19 -1
  177. package/external/pi-tools-suite/src/tool-descriptions.ts +44 -15
  178. package/package.json +7 -8
  179. package/schemas/pi-tools-suite.json +44 -12
  180. package/schemas/pix.json +109 -15
  181. package/schemas/tasks.json +1 -2
  182. package/skills/simplify/SKILL.md +33 -5
  183. package/external/pi-tools-suite/docs/browser-qa-subagent.md +0 -196
  184. package/external/pi-tools-suite/src/async-subagents/agents/browser-qa.md +0 -598
  185. package/skills/playwright-cli/SKILL.md +0 -420
  186. package/skills/playwright-cli/references/element-attributes.md +0 -23
  187. package/skills/playwright-cli/references/playwright-tests.md +0 -50
  188. package/skills/playwright-cli/references/request-mocking.md +0 -87
  189. package/skills/playwright-cli/references/running-code.md +0 -241
  190. package/skills/playwright-cli/references/session-management.md +0 -273
  191. package/skills/playwright-cli/references/spec-driven-testing.md +0 -311
  192. package/skills/playwright-cli/references/storage-state.md +0 -290
  193. package/skills/playwright-cli/references/test-generation.md +0 -142
  194. package/skills/playwright-cli/references/tracing.md +0 -154
  195. package/skills/playwright-cli/references/video-recording.md +0 -147
  196. package/skills/spec-wiki/SKILL.md +0 -55
  197. package/skills/spec-wiki/evals/evals.json +0 -132
  198. package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +0 -14
  199. package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +0 -4
  200. package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +0 -9
  201. package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +0 -17
  202. package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +0 -12
  203. package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +0 -11
  204. package/skills/spec-wiki/evals/files/focused/src/session.ts +0 -5
  205. package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +0 -17
  206. package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +0 -2
  207. package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +0 -3
  208. package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +0 -18
  209. package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +0 -5
  210. package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +0 -24
  211. package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +0 -7
  212. package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +0 -7
  213. package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +0 -17
  214. package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +0 -3
  215. package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +0 -3
  216. package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +0 -4
  217. package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +0 -9
  218. package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +0 -15
  219. package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +0 -6
  220. package/skills/spec-wiki/evals/maintenance_regression.py +0 -311
  221. package/skills/spec-wiki/evals/retrieval-eval.md +0 -37
  222. package/skills/spec-wiki/evals/retrieval-evals.json +0 -37
  223. package/skills/spec-wiki/evals/trigger-evals.json +0 -94
  224. package/skills/spec-wiki/references/bootstrap.md +0 -100
  225. package/skills/spec-wiki/references/focused-spec.md +0 -117
  226. package/skills/spec-wiki/references/index-schema.md +0 -330
  227. package/skills/spec-wiki/references/maintenance.md +0 -134
  228. package/skills/spec-wiki/references/query.md +0 -74
  229. package/skills/spec-wiki/scripts/spec_wiki.py +0 -2076
  230. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-auth.example.jsonc +0 -0
  231. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/examples/qa-flow.example.jsonc +0 -0
  232. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.LICENSE +0 -0
  233. /package/external/pi-tools-suite/src/async-subagents/agents/{browser-qa → ui-qa/browser}/vendor/fflate.mjs +0 -0
@@ -0,0 +1,156 @@
1
+ // Shared, dependency-free presentation for the extension, TUI and ACP. Plain
2
+ // ESM is intentional: the compiled host can import the shipped extension source
3
+ // without loading TypeScript or bringing the extension runtime into the host.
4
+
5
+ /** @param {any} v */
6
+ const finite = (v) => typeof v === "number" && Number.isFinite(v);
7
+ /** @param {any} v */
8
+ const num = (v) => finite(v) ? Math.round(v).toLocaleString("en-US") : "unknown";
9
+ /** @param {any} n @param {any} d */
10
+ const percent = (n, d) => finite(n) && finite(d) && d > 0 ? `${(100 * n / d).toFixed(1)}%` : "unknown";
11
+ /** @param {any} v */
12
+ const mode = (v) => typeof v === "boolean" ? (v ? "on" : "off") : "unknown";
13
+ /** @param {any} m */
14
+ const modelRef = (m) => m?.provider && m?.id ? `${m.provider}/${m.id}` : undefined;
15
+ /** @param {any} v */
16
+ const record = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
17
+
18
+ /** Read-only diagnostic reducer. Never runs the pruner, a model, or a mutation.
19
+ * @param {import('./statistics.js').DcpStatisticsInput} input */
20
+ export function collectDcpStatistics(input) {
21
+ const entries = input.branch ?? [];
22
+ const blocks = new Map(), pruned = new Map(), operations = new Map(), measured = new Map();
23
+ let journal = "absent", previous = null, anchors = [], manualMode;
24
+ let epoch, snapshot, lastReminder, ignored, evidenceEpoch = false;
25
+ let projections = 0, attempts = 0, completed = 0, rejected = 0;
26
+ const publishedIds = new Set();
27
+ const attemptIds = new Set(), completionIds = new Set(), manualFailures = new Set();
28
+ const diagnostics = [];
29
+ for (const entry of entries) {
30
+ if (entry?.type === "custom" && entry.customType === "dcp-journal") {
31
+ const op = entry.data;
32
+ if (!record(op) || op.schemaVersion !== 1 || !["init", "delta"].includes(op.kind) || typeof op.operationId !== "string") {
33
+ journal = "invalid/unsupported"; break;
34
+ }
35
+ if (operations.has(op.operationId)) {
36
+ if (operations.get(op.operationId) !== JSON.stringify(op)) { journal = "conflicting operations"; break; }
37
+ continue;
38
+ }
39
+ if ((op.kind === "init" && (previous !== null || op.previousOperationId !== null)) ||
40
+ (op.kind === "delta" && (previous === null || op.previousOperationId !== previous))) {
41
+ journal = "incomplete/broken chain"; break;
42
+ }
43
+ previous = op.operationId;
44
+ operations.set(previous, JSON.stringify(op));
45
+ journal = "chain verified";
46
+ for (const b of op.blocks ?? []) {
47
+ if (!record(b) || !finite(b.id) || typeof b.active !== "boolean" || blocks.has(b.id)) { journal = "invalid blocks"; break; }
48
+ blocks.set(b.id, { ...b });
49
+ const m = b.commitMetrics;
50
+ if (record(m) && typeof m.operationId === "string" && finite(m.netGainTokens) && m.netGainTokens > 0 &&
51
+ finite(m.beforeTokens) && finite(m.afterTokens) && m.beforeTokens - m.afterTokens === m.netGainTokens) measured.set(m.operationId, m);
52
+ }
53
+ if (journal !== "chain verified") break;
54
+ for (const update of op.blockStates ?? []) {
55
+ const b = blocks.get(update.id);
56
+ if (!b || typeof update.active !== "boolean" || (!b.active && update.active)) { journal = "invalid block states"; break; }
57
+ b.active = update.active;
58
+ }
59
+ if (journal !== "chain verified") break;
60
+ for (const p of op.prunedTools ?? []) if (typeof p?.toolCallId === "string") pruned.set(p.toolCallId, p);
61
+ if (Array.isArray(op.nudgeAnchors)) {
62
+ anchors = op.nudgeAnchors;
63
+ for (const anchor of anchors) publishedIds.add(anchor.id);
64
+ }
65
+ if (typeof op.manualMode === "boolean") manualMode = op.manualMode;
66
+ }
67
+ if (entry?.type === "custom" && entry.customType === "dcp-nudge") {
68
+ const e = entry.data;
69
+ if (["emitted", "reapplied", "upgraded"].includes(e?.event)) { projections++; lastReminder = e; }
70
+ }
71
+ if (entry?.type === "custom" && entry.customType === "dcp-diagnostic" && entry.data?.version === 1) diagnostics.push(entry.data);
72
+ if (entry?.type === "message" && entry.message?.role === "toolResult" && entry.message.toolName === "compress" && entry.message.isError) {
73
+ manualFailures.add(entry.message.toolCallId ?? entry.id);
74
+ }
75
+ }
76
+ // Epoch markers invalidate live measurements/evidence, not durable history.
77
+ for (const d of diagnostics) {
78
+ if (d.event === "epoch") { epoch = d.epoch; snapshot = undefined; ignored = 0; evidenceEpoch = true; }
79
+ if (d.event === "request" && d.epoch === epoch) {
80
+ snapshot = d.snapshot;
81
+ if (finite(snapshot?.ignored)) ignored = snapshot.ignored;
82
+ if (d.reminder && !attemptIds.has(d.id)) { attempts++; attemptIds.add(d.id); }
83
+ }
84
+ if (d.event === "completion" && d.epoch === epoch && !completionIds.has(d.id) && (!d.reminder || attemptIds.has(d.id))) {
85
+ if (d.reminder) completed++;
86
+ completionIds.add(d.id); ignored = d.ignored;
87
+ }
88
+ if (d.event === "auto-rejected") rejected++;
89
+ }
90
+ const valid = journal === "chain verified" && input.historyStatus !== "unavailable";
91
+ const all = valid ? [...blocks.values()] : [];
92
+ const active = all.filter((b) => b.active);
93
+ const activity = { manual: new Set(), auto: new Set(), consolidation: new Set(), unknownBlocks: 0 };
94
+ for (const b of all) {
95
+ const kind = b.commitMetrics?.kind ?? (b.createdByToolCallId ? "manual" : b.autoSummaryRepresentation
96
+ ? ((b.coveredBlockIds?.length ?? 0) >= 2 && b.sourceCoverage?.itemCount === b.coveredBlockIds.length ? "consolidation" : "auto") : undefined);
97
+ const bucket = kind === "manual" ? activity.manual : kind === "auto" ? activity.auto : kind === "consolidation" ? activity.consolidation : undefined;
98
+ if (bucket) bucket.add(b.commitMetrics?.operationId ?? (kind === "manual" ? `manual:${b.createdByToolCallId}` : `auto:${b.id}`));
99
+ else activity.unknownBlocks++;
100
+ }
101
+ const currentWindow = input.model?.contextWindow;
102
+ const snapshotMatchesModel = snapshot && modelRef(input.model) === snapshot.model &&
103
+ (!finite(currentWindow) || currentWindow === snapshot.contextWindow);
104
+ return { valid, journal, operations: operations.size, all, active, pruned: valid ? pruned.size : undefined,
105
+ summaryTokens: valid && active.every((b) => finite(b.summaryTokenEstimate)) ? active.reduce((s,b) => s + b.summaryTokenEstimate, 0) : undefined,
106
+ manualMode, activity, measured: valid ? measured.size : undefined,
107
+ measuredGain: valid && measured.size ? [...measured.values()].reduce((s,m) => s + m.netGainTokens, 0) : valid && all.length === 0 ? 0 : undefined,
108
+ snapshot: snapshotMatchesModel ? snapshot : undefined, snapshotStale: Boolean(snapshot && !snapshotMatchesModel),
109
+ published: publishedIds.size, projections, attempts: evidenceEpoch ? attempts : undefined, completed: evidenceEpoch ? completed : undefined,
110
+ ignored: snapshotMatchesModel ? ignored : undefined, anchors: valid ? anchors : [], lastReminder,
111
+ rejected: evidenceEpoch ? rejected : undefined, manualFailures: manualFailures.size };
112
+ }
113
+
114
+ /** @param {import('./statistics.js').DcpStatisticsInput} input */
115
+ export function formatDcpStatistics(input) {
116
+ let s;
117
+ try { s = collectDcpStatistics(input); }
118
+ catch { return "DCP Session Statistics\n\nHistory unavailable: malformed diagnostic/journal records. No zero statistics inferred."; }
119
+ const usage = input.usage ?? {}, m = input.model, snap = s.snapshot;
120
+ const window = finite(m?.contextWindow) && m.contextWindow > 0 ? m.contextWindow : usage.contextWindow;
121
+ const lines = ["DCP Session Statistics:", "Context",
122
+ ` Model: ${modelRef(m) ?? "unknown"}`,
123
+ ` SDK usage: ${num(usage.tokens)} / ${num(window)} (${percent(usage.tokens, window)}; may lag)`,
124
+ ];
125
+ if (snap) {
126
+ lines.push(` Last DCP request: ~${num(snap.projectedTokens)} tokens; ${snap.pressure} (${snap.reason})`,
127
+ ` Input capacity: ${num(snap.inputCapacityTokens)}; reserved output: ${num(snap.reservedOutputTokens)}`,
128
+ ` Resolved thresholds: routine ${percent(snap.routineTokens, snap.contextWindow)} / strong ${percent(snap.strongTokens, snap.contextWindow)} / hard ${percent(snap.hardTokens, snap.contextWindow)}`,
129
+ ` Modes (last request): DCP ${mode(snap.enabled)}, manual ${mode(snap.manualMode)}, auto ${mode(snap.autoEnabled)}`,
130
+ ` Snapshot: ${finite(snap.createdAt) && Math.abs(snap.createdAt) < 8.64e15 ? new Date(snap.createdAt).toISOString() : "unknown time"} (last request)`);
131
+ } else lines.push(` DCP budget/thresholds: ${s.snapshotStale ? "stale (model/window changed); awaiting projection" : "not recorded; awaiting projection"}`);
132
+ lines.push("History projection (active branch)");
133
+ if (!s.valid) {
134
+ lines.push(` Unavailable: ${input.historyStatus === "unavailable" ? "full history could not be read" : s.journal}`,
135
+ " Blocks, gains and reminders: unknown (not zero)");
136
+ return lines.join("\n");
137
+ }
138
+ lines.push(` Blocks: ${s.active.length} active / ${s.all.length - s.active.length} retired / ${s.all.length} total`,
139
+ ` Active summaries: ~${num(s.summaryTokens)} tokens; result bodies pruned: ${num(s.pruned)}`);
140
+ if (snap) lines.push(` Input/projection: ~${num(snap.rawTokens)} -> ~${num(snap.projectedTokens)} (reduction ~${num(snap.rawTokens - snap.projectedTokens)})`);
141
+ lines.push("Compression activity",
142
+ ` Commits: ${s.activity.manual.size} model/tool, ${s.activity.auto.size} auto, ${s.activity.consolidation.size} consolidations`);
143
+ if (s.activity.unknownBlocks) lines.push(` Provenance unknown: ${s.activity.unknownBlocks} blocks`);
144
+ lines.push(` Measured commit gain: ${num(s.measuredGain)} tokens (${num(s.measured)} measured commits)`,
145
+ ` Rejections recorded: ${num(s.rejected)} auto; ${num(s.manualFailures)} failed compress results`,
146
+ "Reminder delivery",
147
+ ` Anchors journaled: ${s.published}; projection events: ${s.projections} (not sends)`,
148
+ ` Recorded provider attempts with reminder: ${num(s.attempts)}`,
149
+ ` confirmed completed opportunities: ${num(s.completed)}`,
150
+ ` Outstanding consecutive opportunities (last sample): ${num(s.ignored)}`,
151
+ ` Active anchors: ${s.anchors.length}${s.anchors.length ? " (" + s.anchors.map((/** @type {any} */ a) => `${a.type}/${a.anchorRole ?? "unknown carrier"}`).join(", ") + ")" : ""}`,
152
+ ` Last published/reapplied: ${s.lastReminder ? `${s.lastReminder.type} / ${s.lastReminder.anchorRole ?? "unknown carrier"}` : "none recorded"}`,
153
+ `Journal: ${s.journal} (${s.operations} records); full active branch`,
154
+ "Estimates, not billing. Old unmeasured gains/deliveries excluded.");
155
+ return lines.join("\n");
156
+ }
@@ -19,8 +19,10 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
19
19
  "notify": true
20
20
  },
21
21
  // Context Gateway is off by default. observe is passive telemetry; enforce
22
- // selectively compacts only recognised complete simple test/build output.
23
- // Reads and repo results remain producer-owned passthrough/native-compact.
22
+ // compacts recognised complete simple test/build output and over-budget
23
+ // structured web_search/web_fetch results whose raw details remain recoverable
24
+ // from the append-only session. Reads/repo and unsupported result shapes stay
25
+ // producer-owned passthrough/native-compact.
24
26
  "contextGateway": {
25
27
  "mode": "off",
26
28
  "budgets": {
@@ -57,6 +59,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
57
59
  // Vision-capable model used by the coding-discipline lookup tool for blind-model
58
60
  // screenshot/image questions. Remove or set to null to disable lookup.
59
61
  "lookupModel": "zai/glm-5.3-flash",
62
+ "lookupFallbackModels": [],
60
63
  "terminalBell": { "sound": true },
61
64
  // comment-checker: nudges the agent to remove AI-slop code comments it just
62
65
  // added via write/edit/apply_patch. Net-new comments are classified and a
@@ -94,29 +97,43 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
94
97
  }
95
98
  },
96
99
  "modelOverrides": {
100
+ // DCP policy reviewed 2026-09-14. Engineering starting points, not
101
+ // provider-certified optima. Keep candidate/message availability aligned
102
+ // with each model's routine compression threshold.
97
103
  "openai-codex/gpt-5*": {
98
104
  "compress": {
99
105
  "minContextPercent": "26%",
100
- "maxContextPercent": "46%"
106
+ "maxContextPercent": "46%",
107
+ "autoCandidates": { "minContextPercent": 0.26 },
108
+ "messageMode": { "minContextPercent": 0.26 }
101
109
  }
102
110
  },
103
111
  "openai-codex/gpt-5.4-mini": {
104
112
  "compress": {
105
113
  "minContextPercent": "20%",
106
- "maxContextPercent": "38%"
114
+ "maxContextPercent": "38%",
115
+ "autoCandidates": { "minContextPercent": 0.20 },
116
+ "messageMode": { "minContextPercent": 0.20 }
117
+ }
118
+ },
119
+ "openai-codex/gpt-6-astra": {
120
+ "compress": {
121
+ "minContextPercent": "26%",
122
+ "maxContextPercent": "46%",
123
+ "autoCandidates": { "minContextPercent": 0.26 },
124
+ "messageMode": { "minContextPercent": 0.26 }
107
125
  }
108
126
  },
109
127
  "zai/*": {
110
128
  "compress": {
111
129
  "minContextPercent": "16%",
112
- "maxContextPercent": "30%"
130
+ "maxContextPercent": "30%",
131
+ "autoCandidates": { "minContextPercent": 0.16 },
132
+ "messageMode": { "minContextPercent": 0.16 }
113
133
  }
114
134
  },
115
- // glm-5.3 reports a ~1M-token window. Even zai/* 16%/30% = 160K/300K is
116
- // above the ~15% (~150K) point where long sessions degrade, and an
117
- // observed 14h/273K-token session never crossed 16%. Lower ONLY glm-5.3
118
- // within the zai family: 8%/15% (~80K/150K) so nudging starts early and
119
- // auto-compress fires at the observed degradation point. Other zai/*
135
+ // GLM-5.3 and GLM-5.3-Flash expose ~1M-token windows. Use 8%/15%
136
+ // (~80K/~150K) as a conservative long-session policy while other zai/*
120
137
  // models keep 16%/30%.
121
138
  "zai/glm-5.3": {
122
139
  "compress": {
@@ -126,34 +143,68 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
126
143
  "messageMode": { "minContextPercent": 0.08 }
127
144
  }
128
145
  },
146
+ "zai/glm-5.3-flash": {
147
+ "compress": {
148
+ "minContextPercent": "8%",
149
+ "maxContextPercent": "15%",
150
+ "autoCandidates": { "minContextPercent": 0.08 },
151
+ "messageMode": { "minContextPercent": 0.08 }
152
+ }
153
+ },
129
154
  "antigravity/*sonnet*": {
130
155
  "compress": {
131
156
  "minContextPercent": "22%",
132
- "maxContextPercent": "40%"
157
+ "maxContextPercent": "40%",
158
+ "autoCandidates": { "minContextPercent": 0.22 },
159
+ "messageMode": { "minContextPercent": 0.22 }
133
160
  }
134
161
  },
135
162
  "antigravity/gemini-3.1-pro*": {
136
163
  "compress": {
137
164
  "minContextPercent": "24%",
138
- "maxContextPercent": "42%"
165
+ "maxContextPercent": "42%",
166
+ "autoCandidates": { "minContextPercent": 0.24 },
167
+ "messageMode": { "minContextPercent": 0.24 }
139
168
  }
140
169
  },
141
170
  "antigravity/gemini-3-flash*": {
142
171
  "compress": {
143
172
  "minContextPercent": "18%",
144
- "maxContextPercent": "34%"
173
+ "maxContextPercent": "34%",
174
+ "autoCandidates": { "minContextPercent": 0.18 },
175
+ "messageMode": { "minContextPercent": 0.18 }
145
176
  }
146
177
  },
147
178
  "antigravity/gemini-2.5-flash*": {
148
179
  "compress": {
149
180
  "minContextPercent": "18%",
150
- "maxContextPercent": "32%"
181
+ "maxContextPercent": "32%",
182
+ "autoCandidates": { "minContextPercent": 0.18 },
183
+ "messageMode": { "minContextPercent": 0.18 }
151
184
  }
152
185
  },
153
186
  "antigravity/antigravity-claude-opus-4-6-thinking": {
154
187
  "compress": {
155
188
  "minContextPercent": "26%",
156
- "maxContextPercent": "44%"
189
+ "maxContextPercent": "44%",
190
+ "autoCandidates": { "minContextPercent": 0.26 },
191
+ "messageMode": { "minContextPercent": 0.26 }
192
+ }
193
+ },
194
+ "antigravity/antigravity-gemini-3.1-pro": {
195
+ "compress": {
196
+ "minContextPercent": "24%",
197
+ "maxContextPercent": "42%",
198
+ "autoCandidates": { "minContextPercent": 0.24 },
199
+ "messageMode": { "minContextPercent": 0.24 }
200
+ }
201
+ },
202
+ "antigravity/antigravity-gemini-3.8-flash": {
203
+ "compress": {
204
+ "minContextPercent": "18%",
205
+ "maxContextPercent": "34%",
206
+ "autoCandidates": { "minContextPercent": 0.18 },
207
+ "messageMode": { "minContextPercent": 0.18 }
157
208
  }
158
209
  }
159
210
  },
@@ -168,7 +219,8 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
168
219
  "autoCompress": {
169
220
  "enabled": false,
170
221
  "patience": 2,
171
- "summarizerModel": ["zai/glm-5-turbo", "openai-codex/gpt-5.6-luna"],
222
+ "summarizerModel": ["zai/glm-5-turbo"],
223
+ "summarizerFallbackModels": ["openai-codex/gpt-5.6-luna"],
172
224
  "timeoutMs": 20000
173
225
  }
174
226
  }
@@ -1,4 +1,4 @@
1
- import { existsSync, statSync } from "node:fs";
1
+ import { accessSync, constants, existsSync, statSync } from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
4
  export function directoryExists(file: string): boolean {
@@ -40,3 +40,38 @@ export function findIndexedProjectRoot(cwd: string): string | undefined {
40
40
  export function hasIndexedProjectRoot(cwd: string = process.cwd()): boolean {
41
41
  return findIndexedProjectRoot(cwd) !== undefined;
42
42
  }
43
+
44
+ export function commandAvailable(command: string, env: NodeJS.ProcessEnv = process.env): boolean {
45
+ const value = command.trim();
46
+ if (!value || value.includes("/") || value.includes("\\")) return false;
47
+ const pathValue = env.PATH ?? "";
48
+ const candidates = process.platform === "win32"
49
+ ? [
50
+ value,
51
+ ...(env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD")
52
+ .split(";")
53
+ .map((extension) => extension.trim())
54
+ .filter(Boolean)
55
+ .map((extension) => `${value}${extension.startsWith(".") ? extension : `.${extension}`}`),
56
+ ]
57
+ : [value];
58
+ for (const directory of pathValue.split(path.delimiter)) {
59
+ if (!directory) continue;
60
+ for (const candidate of candidates) {
61
+ try {
62
+ accessSync(path.join(directory, candidate), constants.X_OK);
63
+ return true;
64
+ } catch {
65
+ // Continue through PATH without spawning a process or blocking on shell lookup.
66
+ }
67
+ }
68
+ }
69
+ return false;
70
+ }
71
+
72
+ export function hasAvailableIndexedProjectRoot(
73
+ cwd: string = process.cwd(),
74
+ env: NodeJS.ProcessEnv = process.env,
75
+ ): boolean {
76
+ return hasIndexedProjectRoot(cwd) && commandAvailable("idx", env);
77
+ }
@@ -15,8 +15,8 @@ import {
15
15
  import { realpath } from "node:fs/promises";
16
16
  import { resolve } from "node:path";
17
17
  import { Type, type TSchema } from "typebox";
18
- import { CODEX_ALIAS_TOOL_DESCRIPTIONS, REPO_DISCOVERY_TOOL_NAMES, claudeAliasToolDescriptions } from "../tool-descriptions";
19
- import { hasIndexedProjectRoot } from "../lib/project.js";
18
+ import { REPO_DISCOVERY_TOOL_NAMES, claudeAliasToolDescriptions, codexAliasToolDescriptions } from "../tool-descriptions";
19
+ import { hasAvailableIndexedProjectRoot } from "../lib/project.js";
20
20
  import { applyPatch } from "./apply-patch";
21
21
  import { isPathInside } from "./path-utils";
22
22
  import {
@@ -32,6 +32,7 @@ import {
32
32
  } from "./tool-args";
33
33
 
34
34
  const CLAUDE_ALIAS_TOOL_DESCRIPTIONS = claudeAliasToolDescriptions(false);
35
+ const CODEX_ALIAS_TOOL_DESCRIPTIONS = codexAliasToolDescriptions(false);
35
36
  const CLAUDE_ALIAS_TOOLS = Object.values(CLAUDE_ALIAS_TOOL_DESCRIPTIONS).map((tool) => tool.name);
36
37
  const CODEX_ALIAS_TOOLS = ["read", ...Object.values(CODEX_ALIAS_TOOL_DESCRIPTIONS).map((tool) => tool.name)];
37
38
  const BUILTIN_TOOLS = ["read", "bash", "edit", "write", "grep", "find", "ls"] as const;
@@ -379,7 +380,8 @@ async function runShellAlias(
379
380
  return tool.execute(id, { command, timeout: timeoutSeconds(input) }, signal, onUpdate, ctx);
380
381
  }
381
382
 
382
- function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI): void {
383
+ function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI, repoDiscovery: boolean): void {
384
+ const descriptions = codexAliasToolDescriptions(repoDiscovery);
383
385
  const shellParameters = Type.Object({
384
386
  command: Type.String({ description: "The shell script to execute in the user's default shell" }),
385
387
  workdir: Type.Optional(Type.String({ description: "Working directory" })),
@@ -390,7 +392,7 @@ function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI): voi
390
392
 
391
393
  pi.registerTool(
392
394
  defineTool({
393
- ...CODEX_ALIAS_TOOL_DESCRIPTIONS.shellCommand,
395
+ ...descriptions.shellCommand,
394
396
  parameters: shellParameters,
395
397
  renderCall: (args, theme, context) => renderShellAliasCall(runtime, args, theme, context),
396
398
  renderResult: (result, options, theme, context) => renderShellAliasResult(runtime, result, options, theme, context),
@@ -402,7 +404,7 @@ function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI): voi
402
404
 
403
405
  pi.registerTool(
404
406
  defineTool({
405
- ...CODEX_ALIAS_TOOL_DESCRIPTIONS.applyPatch,
407
+ ...descriptions.applyPatch,
406
408
  parameters: Type.Object({
407
409
  input: Type.String({ description: "Complete patch text: either a unified diff or a Begin Patch block" }),
408
410
  }),
@@ -457,8 +459,9 @@ function shouldPreserveSelection(env: NodeJS.ProcessEnv = process.env): boolean
457
459
 
458
460
  export default function modelTools(pi: ExtensionAPI, dependencies: Partial<ModelToolsDependencies> = {}): void {
459
461
  const runtime = createModelToolsRuntime(dependencies);
460
- registerClaudeAliases(runtime, pi, hasIndexedProjectRoot());
461
- registerCodexAliases(runtime, pi);
462
+ const repoDiscovery = hasAvailableIndexedProjectRoot();
463
+ registerClaudeAliases(runtime, pi, repoDiscovery);
464
+ registerCodexAliases(runtime, pi, repoDiscovery);
462
465
 
463
466
  let baseTools: string[] = [];
464
467