pi-ui-extend 1.0.39 → 1.0.41

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 (113) hide show
  1. package/README.md +1 -1
  2. package/dist/app/commands/command-registry.js +2 -2
  3. package/dist/app/commands/command-session-actions.d.ts +0 -1
  4. package/dist/app/commands/command-session-actions.js +22 -13
  5. package/dist/app/icons.d.ts +14 -0
  6. package/dist/app/icons.js +33 -0
  7. package/dist/app/rendering/conversation-tool-renderer.js +2 -2
  8. package/dist/app/rendering/dcp-stats.d.ts +6 -1
  9. package/dist/app/rendering/dcp-stats.js +214 -46
  10. package/dist/app/rendering/editor-panels.js +8 -5
  11. package/dist/app/session/lazy-session-manager.js +12 -1
  12. package/dist/app/session/tabs-controller.d.ts +2 -5
  13. package/dist/app/session/tabs-controller.js +12 -21
  14. package/dist/app/subagents/subagents-model.d.ts +14 -1
  15. package/dist/app/subagents/subagents-model.js +34 -15
  16. package/dist/app/types.d.ts +2 -0
  17. package/dist/bundled-extensions/session-title/config.js +1 -1
  18. package/dist/markdown-format.js +27 -9
  19. package/dist/schemas/pi-tools-suite-schema.d.ts +29 -16
  20. package/dist/schemas/pi-tools-suite-schema.js +46 -31
  21. package/external/pi-tools-suite/README.md +392 -52
  22. package/external/pi-tools-suite/docs/browser-qa-subagent.md +31 -21
  23. package/external/pi-tools-suite/docs/context-gateway-p00-adr.md +216 -0
  24. package/external/pi-tools-suite/docs/context-gateway-p01n-gate-review.md +122 -0
  25. package/external/pi-tools-suite/docs/context-gateway-p01n-measurement.md +133 -0
  26. package/external/pi-tools-suite/docs/context-gateway-p01r-ra-evidence.md +111 -0
  27. package/external/pi-tools-suite/docs/context-gateway-p01r-rb-evidence.md +100 -0
  28. package/external/pi-tools-suite/docs/context-gateway-p01r-rc-evidence.md +69 -0
  29. package/external/pi-tools-suite/docs/context-gateway-p01r-rd-evidence.md +100 -0
  30. package/external/pi-tools-suite/docs/context-gateway-p01r-re-evidence.md +74 -0
  31. package/external/pi-tools-suite/docs/context-gateway-p01r-rf-evidence.md +153 -0
  32. package/external/pi-tools-suite/docs/context-gateway-p01r-rg-evidence.md +235 -0
  33. package/external/pi-tools-suite/docs/evals.md +684 -0
  34. package/external/pi-tools-suite/docs/subagent-model-pools.md +109 -0
  35. package/external/pi-tools-suite/package.json +10 -3
  36. package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/scripts/browser-qa-runner.mjs +82 -1
  37. package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/SKILL.md → agents/browser-qa.md} +261 -12
  38. package/external/pi-tools-suite/src/async-subagents/agents/implement.md +20 -0
  39. package/external/pi-tools-suite/src/async-subagents/agents/oracle.md +16 -0
  40. package/external/pi-tools-suite/src/async-subagents/agents/research.md +18 -0
  41. package/external/pi-tools-suite/src/async-subagents/agents/verify.md +18 -0
  42. package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +27 -243
  43. package/external/pi-tools-suite/src/async-subagents/commands.ts +6 -2
  44. package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +41 -0
  45. package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +13 -93
  46. package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +494 -0
  47. package/external/pi-tools-suite/src/async-subagents/core/browser-qa.ts +9 -0
  48. package/external/pi-tools-suite/src/async-subagents/core/config.ts +200 -143
  49. package/external/pi-tools-suite/src/async-subagents/core/model-fallback.ts +1 -1
  50. package/external/pi-tools-suite/src/async-subagents/core/model-selection.ts +54 -0
  51. package/external/pi-tools-suite/src/async-subagents/core/prompt.ts +7 -6
  52. package/external/pi-tools-suite/src/async-subagents/core/routing.ts +52 -45
  53. package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +12 -4
  54. package/external/pi-tools-suite/src/async-subagents/index.ts +11 -1
  55. package/external/pi-tools-suite/src/async-subagents/lib.ts +6 -2
  56. package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +46 -18
  57. package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +3 -2
  58. package/external/pi-tools-suite/src/async-subagents/types.ts +2 -0
  59. package/external/pi-tools-suite/src/coding-discipline/index.ts +41 -142
  60. package/external/pi-tools-suite/src/config.ts +1 -22
  61. package/external/pi-tools-suite/src/context-gateway/accounting.ts +151 -0
  62. package/external/pi-tools-suite/src/context-gateway/config.ts +111 -0
  63. package/external/pi-tools-suite/src/context-gateway/index.ts +160 -0
  64. package/external/pi-tools-suite/src/context-gateway/metadata-normalization.ts +88 -0
  65. package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +89 -0
  66. package/external/pi-tools-suite/src/context-gateway/telemetry.ts +429 -0
  67. package/external/pi-tools-suite/src/context-gateway/test-output-parser.ts +326 -0
  68. package/external/pi-tools-suite/src/context-gateway/types.ts +152 -0
  69. package/external/pi-tools-suite/src/dcp/auto-compress-budget.ts +106 -0
  70. package/external/pi-tools-suite/src/dcp/auto-compress.ts +810 -106
  71. package/external/pi-tools-suite/src/dcp/commands.ts +64 -139
  72. package/external/pi-tools-suite/src/dcp/compress-tool.ts +369 -35
  73. package/external/pi-tools-suite/src/dcp/compression-blocks.ts +510 -64
  74. package/external/pi-tools-suite/src/dcp/compression-preview.ts +113 -0
  75. package/external/pi-tools-suite/src/dcp/compression-progress.ts +70 -0
  76. package/external/pi-tools-suite/src/dcp/config.ts +36 -61
  77. package/external/pi-tools-suite/src/dcp/conversation-index.ts +421 -0
  78. package/external/pi-tools-suite/src/dcp/debug-log.ts +7 -5
  79. package/external/pi-tools-suite/src/dcp/index.ts +617 -203
  80. package/external/pi-tools-suite/src/dcp/journal.ts +566 -0
  81. package/external/pi-tools-suite/src/dcp/progress-controller.ts +244 -0
  82. package/external/pi-tools-suite/src/dcp/prompts.ts +10 -7
  83. package/external/pi-tools-suite/src/dcp/provider-tool-results.ts +189 -0
  84. package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +298 -78
  85. package/external/pi-tools-suite/src/dcp/pruner-compression-blocks.ts +173 -281
  86. package/external/pi-tools-suite/src/dcp/pruner-emergency.ts +2 -4
  87. package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +17 -5
  88. package/external/pi-tools-suite/src/dcp/pruner-metadata.ts +11 -1
  89. package/external/pi-tools-suite/src/dcp/pruner-nudge.ts +30 -82
  90. package/external/pi-tools-suite/src/dcp/pruner-tools.ts +22 -133
  91. package/external/pi-tools-suite/src/dcp/pruner.ts +18 -33
  92. package/external/pi-tools-suite/src/dcp/recovery.ts +129 -0
  93. package/external/pi-tools-suite/src/dcp/shadow-plan.ts +127 -0
  94. package/external/pi-tools-suite/src/dcp/state-transaction.ts +102 -0
  95. package/external/pi-tools-suite/src/dcp/state.ts +158 -580
  96. package/external/pi-tools-suite/src/dcp/ui.ts +1 -0
  97. package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +55 -220
  98. package/external/pi-tools-suite/src/index.ts +9 -0
  99. package/external/pi-tools-suite/src/model-tools/index.ts +76 -42
  100. package/external/pi-tools-suite/src/repo-discovery/index.ts +84 -18
  101. package/external/pi-tools-suite/src/repo-discovery/native-compact.ts +458 -0
  102. package/external/pi-tools-suite/src/session-recovery/index.ts +189 -43
  103. package/external/pi-tools-suite/src/tool-descriptions.ts +43 -38
  104. package/external/pi-tools-suite/src/truncation-metadata-normalizer/index.ts +17 -0
  105. package/package.json +6 -6
  106. package/schemas/pi-tools-suite.json +159 -78
  107. package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/auth-scaffold-spec.md +0 -78
  108. package/external/pi-tools-suite/src/async-subagents/private-skills/browser-qa/references/qa-design.md +0 -223
  109. package/external/pi-tools-suite/src/dcp/state-persistence.ts +0 -195
  110. /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-auth.example.jsonc +0 -0
  111. /package/external/pi-tools-suite/src/async-subagents/{private-skills/browser-qa/references → agents/browser-qa/examples}/qa-flow.example.jsonc +0 -0
  112. /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.LICENSE +0 -0
  113. /package/external/pi-tools-suite/src/async-subagents/{private-skills → agents}/browser-qa/vendor/fflate.mjs +0 -0
@@ -14,6 +14,7 @@ export interface DcpCompressionVisualDetails {
14
14
  contextPercent?: number | null
15
15
  skippedMessages?: number
16
16
  skippedMessageIssues?: string[]
17
+ idempotentReplay?: boolean
17
18
  }
18
19
 
19
20
  export interface DcpContextUsage {
@@ -1,3 +1,8 @@
1
+ import { readFileSync } from "node:fs";
2
+
3
+ // Reuse the shipped sample instead of copying role descriptions/model defaults.
4
+ const subagentDefaults = readFileSync(new URL("./async-subagents/async-subagents.sample.jsonc", import.meta.url), "utf8").trim();
5
+
1
6
  // Default user config written when pi-tools-suite.jsonc is missing.
2
7
  export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
3
8
  "$schema": "https://unpkg.com/pi-ui-extend/schemas/pi-tools-suite.json",
@@ -7,11 +12,34 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
7
12
  ],
8
13
  // Secret firewall is deliberately opt-in for now. Flip this to true to enable
9
14
  // high-confidence outbound redaction plus session-history hygiene.
10
- "modules": { "credential-firewall": false },
15
+ "modules": {
16
+ "credential-firewall": false,
17
+ // Optional non-store cleanup: removes only SDK truncation metadata text
18
+ // proven to duplicate the already-visible result. Context Gateway observe
19
+ // remains passive because this module is separate and disabled by default.
20
+ "truncation-metadata-normalizer": false
21
+ },
11
22
  "secretFirewall": {
12
23
  "sessionHygiene": true,
13
24
  "notify": true
14
25
  },
26
+ // Context Gateway is passive/off by default. P01 supports off/observe only;
27
+ // enforce is explicitly refused until capture/store/reader integration lands.
28
+ "contextGateway": {
29
+ "mode": "off",
30
+ "budgets": {
31
+ "maxInlineBytes": 8192,
32
+ "maxResultBytes": 8192,
33
+ "maxExactReadBytes": 32768,
34
+ "maxSearchBytes": 8192,
35
+ "maxSearchMatches": 12
36
+ }
37
+ },
38
+ // Baseline preserves the historical repo_* argv/defaults. Native Compact is
39
+ // an explicit experimental arm with bounded native flags/cursors/output.
40
+ "repoDiscovery": {
41
+ "profile": "baseline"
42
+ },
15
43
  // When true, todo items may carry a per-task thinking level and the todo
16
44
  // module will switch/restore Pi's thinking level as in-progress tasks change.
17
45
  "todoThinking": true,
@@ -24,12 +52,6 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
24
52
  // Vision-capable model used by the coding-discipline lookup tool for blind-model
25
53
  // screenshot/image questions. Remove or set to null to disable lookup.
26
54
  "lookupModel": "zai/glm-5.3-flash",
27
- // coding-discipline working-state strictness.
28
- // "lenient" (default): batch independent read-only tool calls; brief reasoning
29
- // text is acceptable when thinking is off. Text only counts as chatter when a
30
- // thinking/reasoning block already captured the reasoning.
31
- // "strict": one tool call per turn, no assistant text at all (Opus-like).
32
- "codingDisciplineStrictness": "lenient",
33
55
  "terminalBell": { "sound": true },
34
56
  // comment-checker: nudges the agent to remove AI-slop code comments it just
35
57
  // added via write/edit/apply_patch. Net-new comments are classified and a
@@ -51,7 +73,7 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
51
73
  // dropping the oldest past debugLog.maxBackups (default 3).
52
74
  "debug": false,
53
75
  "debugLog": { "maxBytes": 5242880, "maxBackups": 3 },
54
- "manualMode": { "enabled": false, "automaticStrategies": true },
76
+ "manualMode": { "enabled": false },
55
77
  "strategies": {
56
78
  "emergencyCurrentTurnPruning": {
57
79
  // Disabling this turns off same-turn candidates and lossy pruning;
@@ -141,222 +163,12 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
141
163
  "autoCompress": {
142
164
  "enabled": false,
143
165
  "patience": 2,
144
- "summarizerModel": ["zai/glm-5.3", "zai/glm-4.5-air"],
166
+ "summarizerModel": ["zai/glm-5.3", "zai/glm-5-turbo"],
145
167
  "timeoutMs": 20000
146
168
  }
147
169
  }
148
170
  },
149
- "asyncSubagents": {
150
- "defaultType": "quick",
151
- "routing": { "enabled": true, "model": "zai/glm-4.5-air", "fallbackModels": ["openai-codex/gpt-5.6-luna"], "maxTaskChars": 1200, "maxTokens": 512, "maxRetries": 1, "timeoutMs": 12000, "debug": false },
152
- "presets": {
153
- "cheap": {
154
- "description": "Use GLM models by role, including GLM-5.3 Flash for multimodal work.",
155
- "types": {
156
- "quick": { "model": "zai/glm-4.5-air", "thinking": "off" },
157
- "scan": { "model": "zai/glm-4.5-air", "thinking": "off" },
158
- "research": { "model": "zai/glm-5-turbo", "thinking": "low" },
159
- "docs": { "model": "zai/glm-4.5-air", "thinking": "low" },
160
- "frontend": {
161
- "model": "zai/glm-5.3-flash",
162
- "thinking": "medium"
163
- },
164
- "browser-qa": { "model": "zai/glm-5.3-flash", "fallbackModels": ["openai-codex/gpt-5.6-luna"], "thinking": "low" },
165
- "tests": { "model": "zai/glm-5-turbo", "thinking": "medium" },
166
- "review": { "model": "zai/glm-5.3", "thinking": "high" },
167
- "implement": { "model": "zai/glm-5.3", "thinking": "high" },
168
- "deep": { "model": "zai/glm-5.3", "thinking": "high" }
169
- }
170
- },
171
- "gpt": {
172
- "description": "Use the GPT-5.6 family by role: luna for fast tasks, terra for balanced work, and sol for heavy reasoning; fallback cross-provider on quota.",
173
- "types": {
174
- "quick": {
175
- "model": "openai-codex/gpt-5.6-luna",
176
- "fallbackModels": ["zai/glm-4.5-air"],
177
- "thinking": "off"
178
- },
179
- "scan": {
180
- "model": "openai-codex/gpt-5.6-luna",
181
- "fallbackModels": ["zai/glm-4.5-air"],
182
- "thinking": "off"
183
- },
184
- "research": {
185
- "model": "openai-codex/gpt-5.6-terra",
186
- "fallbackModels": ["zai/glm-5-turbo"],
187
- "thinking": "low"
188
- },
189
- "docs": {
190
- "model": "openai-codex/gpt-5.6-luna",
191
- "fallbackModels": ["zai/glm-4.5-air"],
192
- "thinking": "low"
193
- },
194
- "frontend": {
195
- "model": "openai-codex/gpt-5.6-terra",
196
- "fallbackModels": ["antigravity/gemini-3-flash-preview", "zai/glm-5.3"],
197
- "thinking": "medium"
198
- },
199
- "tests": {
200
- "model": "openai-codex/gpt-5.6-terra",
201
- "fallbackModels": ["zai/glm-5-turbo"],
202
- "thinking": "medium"
203
- },
204
- "review": {
205
- "model": "openai-codex/gpt-5.6-sol",
206
- "fallbackModels": ["zai/glm-5.3"],
207
- "thinking": "high"
208
- },
209
- "implement": {
210
- "model": "openai-codex/gpt-5.6-sol",
211
- "fallbackModels": ["zai/glm-5.3"],
212
- "thinking": "high"
213
- },
214
- "deep": {
215
- "model": "openai-codex/gpt-5.6-sol",
216
- "fallbackModels": ["zai/glm-5.3"],
217
- "thinking": "high"
218
- }
219
- }
220
- },
221
- "deep": {
222
- "description": "Use only enabled strong models, mixing GPT, Claude, and Gemini by role.",
223
- "types": {
224
- "quick": {
225
- "model": "openai-codex/gpt-5.6-luna",
226
- "fallbackModels": ["zai/glm-4.5-air"],
227
- "thinking": "low"
228
- },
229
- "scan": {
230
- "model": "antigravity/gemini-3-flash-preview",
231
- "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-4.5-air"],
232
- "thinking": "off"
233
- },
234
- "research": {
235
- "model": "antigravity/gemini-3.1-pro-preview",
236
- "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5-turbo"],
237
- "thinking": "medium"
238
- },
239
- "docs": {
240
- "model": "antigravity/gemini-2.5-flash",
241
- "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-4.5-air"],
242
- "thinking": "medium"
243
- },
244
- "frontend": {
245
- "model": "antigravity/gemini-3.1-pro-preview-customtools",
246
- "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5.3"],
247
- "thinking": "low"
248
- },
249
- "tests": {
250
- "model": "antigravity/antigravity-claude-sonnet-4-6",
251
- "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5-turbo"],
252
- "thinking": "high"
253
- },
254
- "review": {
255
- "model": "antigravity/antigravity-claude-sonnet-4-6",
256
- "fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.3"],
257
- "thinking": "high"
258
- },
259
- "implement": {
260
- "model": "openai-codex/gpt-5.6-sol",
261
- "fallbackModels": ["zai/glm-5.3"],
262
- "thinking": "high"
263
- },
264
- "deep": {
265
- "model": "antigravity/antigravity-claude-opus-4-6-thinking",
266
- "fallbackModels": ["openai-codex/gpt-5.6-sol", "zai/glm-5.3"],
267
- "thinking": "high"
268
- }
269
- }
270
- }
271
- },
272
- "types": {
273
- "quick": {
274
- "description": "Use for tiny cheap tasks: answer a simple question, inspect one known file, or verify one fact. Not for broad repo search.",
275
- "model": "openai-codex/gpt-5.6-luna",
276
- "fallbackModels": ["zai/glm-4.5-air"],
277
- "thinking": "off"
278
- },
279
- "scan": {
280
- "description": "Use for finding files, symbols, text, or inventory across a repo. Return paths/facts; do not judge code quality.",
281
- "model": "openai-codex/gpt-5.6-luna",
282
- "fallbackModels": ["zai/glm-4.5-air"],
283
- "thinking": "off",
284
- "tools": ["read", "grep"]
285
- },
286
- "research": {
287
- "description": "Use for multi-file codebase research: read several files and explain how something works. No edits.",
288
- "model": "openai-codex/gpt-5.6-terra",
289
- "fallbackModels": ["zai/glm-5-turbo"],
290
- "thinking": "low",
291
- "tools": ["read", "grep"]
292
- },
293
- "docs": { "description": "Use for documentation work: README/API docs review, docs gaps, changelog, migration notes, examples.", "model": "openai-codex/gpt-5.6-luna", "fallbackModels": ["zai/glm-4.5-air"], "thinking": "low" },
294
- "frontend": {
295
- "description": "Use for frontend UI/UX visual work: styling, layout, typography, animation, responsive states, component polish, accessibility. Avoid backend/business logic unless needed for UI behavior.",
296
- "model": "antigravity/gemini-3-flash-preview",
297
- "fallbackModels": ["openai-codex/gpt-5.6-luna", "zai/glm-5.3"],
298
- "thinking": "medium",
299
- "promptAppend": [
300
- "Act as a frontend UI/UX engineer for visual and product-facing work.",
301
- "Prioritize layout, typography, spacing, color, motion, responsive states, accessibility, and consistency with the existing design system.",
302
- "Before editing, inspect nearby components/styles and infer the project's design language. Avoid backend/business-logic changes unless required for UI behavior.",
303
- "When no mockup exists, choose a clear aesthetic direction and explain it briefly. Verify with targeted build/lint/tests or screenshot-relevant checks when possible."
304
- ]
305
- },
306
- "browser-qa": {
307
- "description": "Use for browser-based visual QA: reproduce UI bugs and verify fixes with deterministic assertions, screenshots, video, and traces.",
308
- "model": "zai/glm-5.3-flash",
309
- "fallbackModels": ["openai-codex/gpt-5.6-luna"],
310
- "thinking": "low",
311
- "timeoutMs": 120000,
312
- "tools": ["read", "grep", "bash"]
313
- },
314
- "tests": {
315
- "description": "Use for tests: locate coverage, find gaps, run/check targeted test commands, diagnose failing tests.",
316
- "model": "openai-codex/gpt-5.6-terra",
317
- "fallbackModels": ["zai/glm-5-turbo"],
318
- "thinking": "medium",
319
- "tools": ["read", "grep", "bash"]
320
- },
321
- "review": {
322
- "description": "Use for review/audit of existing code or changes: correctness, security, performance, maintainability, API risks, quality. Do not implement new code.",
323
- "model": "openai-codex/gpt-5.6-sol",
324
- "fallbackModels": ["zai/glm-5.3"],
325
- "thinking": "high",
326
- "tools": ["read", "grep"]
327
- },
328
- "implement": {
329
- "description": "Use when the sub-agent should make or plan code changes for a feature, bug fix, or refactor.",
330
- "model": "openai-codex/gpt-5.6-sol",
331
- "fallbackModels": ["zai/glm-5.3"],
332
- "modelByParent": {
333
- "openai-codex/gpt-5.6-luna*": { "model": "openai-codex/gpt-5.6-terra", "fallbackModels": ["zai/glm-5.3"] },
334
- "openai-codex/gpt-5.6-sol*": { "model": "openai-codex/gpt-5.6-terra", "fallbackModels": ["zai/glm-5.3"] }
335
- },
336
- "thinking": "high"
337
- },
338
- "deep": {
339
- "description": "Use for broad hard reasoning: architecture, system design, cross-module impact, complex tradeoffs.",
340
- "model": "openai-codex/gpt-5.6-sol",
341
- "fallbackModels": ["zai/glm-5.3"],
342
- "thinking": "high"
343
- },
344
- "oracle": {
345
- "description": "Oracle: cross-provider flagship second opinion for hard or high-stakes uncertainty. Use sparingly to pressure-test architecture, plans, root-cause hypotheses, risk/security calls, or final recommendations when independent disagreement is valuable. Read-only; advise, do not edit.",
346
- "model": "openai-codex/gpt-5.6-sol",
347
- "fallbackModels": ["zai/glm-5.3"],
348
- "thinking": "max",
349
- "tools": ["read", "grep", "bash"],
350
- "modelByParent": {
351
- "zai/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.3"] },
352
- "openai-codex/*": { "model": "zai/glm-5.3", "fallbackModels": ["openai-codex/gpt-5.6-sol"] },
353
- "antigravity/*": { "model": "zai/glm-5.3", "fallbackModels": ["openai-codex/gpt-5.6-sol"] },
354
- "anthropic/*": { "model": "openai-codex/gpt-5.6-sol", "fallbackModels": ["zai/glm-5.3"] }
355
- },
356
- "promptAppend": "You are an oracle: a flagship model from a different provider giving a second opinion to the parent agent. Give a concise, decisive recommendation with key tradeoffs and risks. Disagree when warranted; do not rubber-stamp. Do not edit unless explicitly asked."
357
- }
358
- }
359
- },
171
+ "asyncSubagents": ${subagentDefaults},
360
172
  "toolRenderer": {},
361
173
  "promptCommands": {
362
174
  "commands": {
@@ -398,6 +210,29 @@ export const DEFAULT_PI_TOOLS_SUITE_CONFIG_JSONC = String.raw`{
398
210
  }
399
211
  // ,
400
212
  // {
213
+ // "id": "svelte",
214
+ // "include": [
215
+ // "**/*.svelte"
216
+ // ],
217
+ // "exclude": [
218
+ // "**/node_modules/**"
219
+ // ],
220
+ // "rootMarkers": [
221
+ // "svelte.config.js",
222
+ // "package.json"
223
+ // ],
224
+ // "bin": "svelteserver",
225
+ // "args": [
226
+ // "--stdio"
227
+ // ],
228
+ // "startupTimeoutMs": 30000,
229
+ // "diagnosticsWaitMs": 8000,
230
+ // "languageIdByExtension": {
231
+ // ".svelte": "svelte"
232
+ // }
233
+ // }
234
+ // ,
235
+ // {
401
236
  // "id": "python",
402
237
  // "include": [
403
238
  // "**/*.py",
@@ -24,6 +24,15 @@ export const MODULES: Array<{ name: string; load: () => Promise<ExtensionModule>
24
24
  { name: "model-tools", load: () => import("./model-tools/index") },
25
25
  { name: "usage", load: () => import("./usage/index") },
26
26
  { name: "web-search", load: () => import("./web-search/index") },
27
+ // Observe-only Context Gateway currently runs after result enrichers. P01-R
28
+ // keeps this independent result chain; a coordinator is conditional future
29
+ // enforce work only if a concrete ordering conflict is proven.
30
+ { name: "context-gateway", load: () => import("./context-gateway/index") },
31
+ // Explicit opt-in, non-store cleanup. Keep after Gateway observe so passive
32
+ // telemetry measures the original boundary, and before downstream result
33
+ // observers. This ordering does not depend on any particular DCP persistence
34
+ // design; DCP is scheduled for a separate redesign.
35
+ { name: "truncation-metadata-normalizer", load: () => import("./truncation-metadata-normalizer/index") },
27
36
  { name: "dcp", load: () => import("./dcp/index") },
28
37
  { name: "prompt-commands", load: () => import("./prompt-commands/index") },
29
38
  { name: "skill-installer", load: () => import("./skill-installer/index") },
@@ -61,6 +61,19 @@ type ShellAliasInput = {
61
61
  type BashToolDefinition = ReturnType<typeof createBashToolDefinition>;
62
62
  type AnyToolDefinition = ToolDefinition<any, any, any>;
63
63
  type BuiltinToolName = (typeof BUILTIN_TOOLS)[number];
64
+ export interface ModelToolsDependencies {
65
+ createReadToolDefinition: (cwd: string, options?: any) => AnyToolDefinition;
66
+ createEditToolDefinition: (cwd: string, options?: any) => AnyToolDefinition;
67
+ createWriteToolDefinition: (cwd: string, options?: any) => AnyToolDefinition;
68
+ createBashToolDefinition: (cwd: string, options?: any) => AnyToolDefinition;
69
+ createGrepToolDefinition: (cwd: string, options?: any) => AnyToolDefinition;
70
+ createFindToolDefinition: (cwd: string, options?: any) => AnyToolDefinition;
71
+ createLsToolDefinition: (cwd: string, options?: any) => AnyToolDefinition;
72
+ }
73
+ type ModelToolsRuntime = {
74
+ dependencies: ModelToolsDependencies;
75
+ builtinDefinitions: Map<string, AnyToolDefinition>;
76
+ };
64
77
  type RenderContext = {
65
78
  args: any;
66
79
  cwd: string;
@@ -68,7 +81,22 @@ type RenderContext = {
68
81
  };
69
82
  type RenderTheme = Parameters<NonNullable<BashToolDefinition["renderCall"]>>[1];
70
83
 
71
- const builtinDefinitions = new Map<string, AnyToolDefinition>();
84
+ const DEFAULT_MODEL_TOOLS_DEPENDENCIES: ModelToolsDependencies = {
85
+ createReadToolDefinition,
86
+ createEditToolDefinition,
87
+ createWriteToolDefinition,
88
+ createBashToolDefinition,
89
+ createGrepToolDefinition,
90
+ createFindToolDefinition,
91
+ createLsToolDefinition,
92
+ };
93
+
94
+ function createModelToolsRuntime(overrides: Partial<ModelToolsDependencies> = {}): ModelToolsRuntime {
95
+ return {
96
+ dependencies: { ...DEFAULT_MODEL_TOOLS_DEPENDENCIES, ...overrides },
97
+ builtinDefinitions: new Map(),
98
+ };
99
+ }
72
100
 
73
101
  function timeoutSeconds(input: { timeout?: number; timeout_ms?: number }): number | undefined {
74
102
  if (typeof input.timeout === "number") return input.timeout;
@@ -76,39 +104,40 @@ function timeoutSeconds(input: { timeout?: number; timeout_ms?: number }): numbe
76
104
  return undefined;
77
105
  }
78
106
 
79
- function createBuiltinDefinition(name: BuiltinToolName, cwd: string): AnyToolDefinition {
107
+ function createBuiltinDefinition(runtime: ModelToolsRuntime, name: BuiltinToolName, cwd: string): AnyToolDefinition {
108
+ const dependencies = runtime.dependencies;
80
109
  switch (name) {
81
110
  case "read":
82
- return createReadToolDefinition(cwd);
111
+ return dependencies.createReadToolDefinition(cwd);
83
112
  case "edit":
84
- return createEditToolDefinition(cwd);
113
+ return dependencies.createEditToolDefinition(cwd);
85
114
  case "write":
86
- return createWriteToolDefinition(cwd);
115
+ return dependencies.createWriteToolDefinition(cwd);
87
116
  case "bash":
88
- return createBashToolDefinition(cwd);
117
+ return dependencies.createBashToolDefinition(cwd);
89
118
  case "grep":
90
- return createGrepToolDefinition(cwd);
119
+ return dependencies.createGrepToolDefinition(cwd);
91
120
  case "find":
92
- return createFindToolDefinition(cwd);
121
+ return dependencies.createFindToolDefinition(cwd);
93
122
  case "ls":
94
- return createLsToolDefinition(cwd);
123
+ return dependencies.createLsToolDefinition(cwd);
95
124
  }
96
125
  }
97
126
 
98
- function getRenderDefinition(name: BuiltinToolName, cwd: string): AnyToolDefinition {
127
+ function getRenderDefinition(runtime: ModelToolsRuntime, name: BuiltinToolName, cwd: string): AnyToolDefinition {
99
128
  const key = `${name}:${cwd}`;
100
- const existing = builtinDefinitions.get(key);
129
+ const existing = runtime.builtinDefinitions.get(key);
101
130
  if (existing) {
102
- builtinDefinitions.delete(key);
103
- builtinDefinitions.set(key, existing);
131
+ runtime.builtinDefinitions.delete(key);
132
+ runtime.builtinDefinitions.set(key, existing);
104
133
  return existing;
105
134
  }
106
- const definition = createBuiltinDefinition(name, cwd);
107
- if (builtinDefinitions.size >= MAX_BUILTIN_DEFINITIONS) {
108
- const oldestKey = builtinDefinitions.keys().next().value;
109
- if (oldestKey) builtinDefinitions.delete(oldestKey);
135
+ const definition = createBuiltinDefinition(runtime, name, cwd);
136
+ if (runtime.builtinDefinitions.size >= MAX_BUILTIN_DEFINITIONS) {
137
+ const oldestKey = runtime.builtinDefinitions.keys().next().value;
138
+ if (oldestKey) runtime.builtinDefinitions.delete(oldestKey);
110
139
  }
111
- builtinDefinitions.set(key, definition);
140
+ runtime.builtinDefinitions.set(key, definition);
112
141
  return definition;
113
142
  }
114
143
 
@@ -143,6 +172,7 @@ function applyAliasToolTitle(component: unknown, builtinName: BuiltinToolName, a
143
172
  }
144
173
 
145
174
  function renderAliasCall(
175
+ runtime: ModelToolsRuntime,
146
176
  name: BuiltinToolName,
147
177
  args: unknown,
148
178
  theme: RenderTheme,
@@ -150,7 +180,7 @@ function renderAliasCall(
150
180
  aliasLabel: string = name,
151
181
  ) {
152
182
  const renderContext = context as RenderContext;
153
- const renderCall = getRenderDefinition(name, renderContext.cwd).renderCall;
183
+ const renderCall = getRenderDefinition(runtime, name, renderContext.cwd).renderCall;
154
184
  if (!renderCall) throw new Error(`${name} renderer is unavailable`);
155
185
  const component = renderCall(args, theme, withRenderArgs(renderContext, args) as any);
156
186
  applyAliasToolTitle(component, name, aliasLabel);
@@ -158,6 +188,7 @@ function renderAliasCall(
158
188
  }
159
189
 
160
190
  function renderAliasResult(
191
+ runtime: ModelToolsRuntime,
161
192
  name: BuiltinToolName,
162
193
  args: unknown,
163
194
  result: unknown,
@@ -167,7 +198,7 @@ function renderAliasResult(
167
198
  aliasLabel: string = name,
168
199
  ) {
169
200
  const renderContext = context as RenderContext;
170
- const renderResult = getRenderDefinition(name, renderContext.cwd).renderResult;
201
+ const renderResult = getRenderDefinition(runtime, name, renderContext.cwd).renderResult;
171
202
  if (!renderResult) throw new Error(`${name} renderer is unavailable`);
172
203
  const component = renderResult(
173
204
  result as Parameters<NonNullable<AnyToolDefinition["renderResult"]>>[0],
@@ -180,13 +211,13 @@ function renderAliasResult(
180
211
  return component;
181
212
  }
182
213
 
183
- function renderShellAliasCall(args: ShellAliasInput, theme: RenderTheme, context: unknown) {
184
- return renderAliasCall("bash", toBashRenderArgs(args), theme, context, "shell");
214
+ function renderShellAliasCall(runtime: ModelToolsRuntime, args: ShellAliasInput, theme: RenderTheme, context: unknown) {
215
+ return renderAliasCall(runtime, "bash", toBashRenderArgs(args), theme, context, "shell");
185
216
  }
186
217
 
187
- function renderShellAliasResult(result: unknown, options: ToolRenderResultOptions, theme: RenderTheme, context: unknown) {
218
+ function renderShellAliasResult(runtime: ModelToolsRuntime, result: unknown, options: ToolRenderResultOptions, theme: RenderTheme, context: unknown) {
188
219
  const args = toBashRenderArgs((context as RenderContext).args as ShellAliasInput);
189
- return renderAliasResult("bash", args, result, options, theme, context, "shell");
220
+ return renderAliasResult(runtime, "bash", args, result, options, theme, context, "shell");
190
221
  }
191
222
 
192
223
  async function resolveWorkdir(ctx: ExtensionContext, workdir: string | undefined): Promise<string | undefined> {
@@ -209,7 +240,7 @@ type BuiltinAliasOptions<Input> = {
209
240
  validate?: (params: Input) => void;
210
241
  };
211
242
 
212
- function registerBuiltinAlias<Input>(pi: ExtensionAPI, options: BuiltinAliasOptions<Input>): void {
243
+ function registerBuiltinAlias<Input>(runtime: ModelToolsRuntime, pi: ExtensionAPI, options: BuiltinAliasOptions<Input>): void {
213
244
  pi.registerTool(
214
245
  defineTool({
215
246
  name: options.name,
@@ -218,9 +249,10 @@ function registerBuiltinAlias<Input>(pi: ExtensionAPI, options: BuiltinAliasOpti
218
249
  parameters: options.parameters,
219
250
  renderShell: options.renderShell,
220
251
  renderCall: (params, theme, context) =>
221
- renderAliasCall(options.builtinName, options.toArgs(params as Input), theme, context, options.label),
252
+ renderAliasCall(runtime, options.builtinName, options.toArgs(params as Input), theme, context, options.label),
222
253
  renderResult: (result, renderOptions, theme, context) =>
223
254
  renderAliasResult(
255
+ runtime,
224
256
  options.builtinName,
225
257
  options.toArgs((context as RenderContext).args as Input),
226
258
  result,
@@ -232,7 +264,7 @@ function registerBuiltinAlias<Input>(pi: ExtensionAPI, options: BuiltinAliasOpti
232
264
  async execute(id, params, signal, onUpdate, ctx) {
233
265
  const input = params as Input;
234
266
  options.validate?.(input);
235
- return createBuiltinDefinition(options.builtinName, ctx.cwd).execute(
267
+ return createBuiltinDefinition(runtime, options.builtinName, ctx.cwd).execute(
236
268
  id,
237
269
  options.toArgs(input),
238
270
  signal,
@@ -244,10 +276,10 @@ function registerBuiltinAlias<Input>(pi: ExtensionAPI, options: BuiltinAliasOpti
244
276
  );
245
277
  }
246
278
 
247
- function registerClaudeAliases(pi: ExtensionAPI, repoDiscovery: boolean): void {
279
+ function registerClaudeAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI, repoDiscovery: boolean): void {
248
280
  const descriptions = claudeAliasToolDescriptions(repoDiscovery);
249
281
 
250
- registerBuiltinAlias(pi, {
282
+ registerBuiltinAlias(runtime, pi, {
251
283
  ...descriptions.Read,
252
284
  builtinName: "read",
253
285
  parameters: Type.Object({
@@ -258,7 +290,7 @@ function registerClaudeAliases(pi: ExtensionAPI, repoDiscovery: boolean): void {
258
290
  toArgs: toReadArgs,
259
291
  });
260
292
 
261
- registerBuiltinAlias(pi, {
293
+ registerBuiltinAlias(runtime, pi, {
262
294
  ...descriptions.Edit,
263
295
  builtinName: "edit",
264
296
  parameters: Type.Object({
@@ -274,7 +306,7 @@ function registerClaudeAliases(pi: ExtensionAPI, repoDiscovery: boolean): void {
274
306
  },
275
307
  });
276
308
 
277
- registerBuiltinAlias(pi, {
309
+ registerBuiltinAlias(runtime, pi, {
278
310
  ...descriptions.Write,
279
311
  builtinName: "write",
280
312
  parameters: Type.Object({
@@ -284,7 +316,7 @@ function registerClaudeAliases(pi: ExtensionAPI, repoDiscovery: boolean): void {
284
316
  toArgs: toWriteArgs,
285
317
  });
286
318
 
287
- registerBuiltinAlias(pi, {
319
+ registerBuiltinAlias(runtime, pi, {
288
320
  ...descriptions.Bash,
289
321
  builtinName: "bash",
290
322
  parameters: Type.Object({
@@ -299,7 +331,7 @@ function registerClaudeAliases(pi: ExtensionAPI, repoDiscovery: boolean): void {
299
331
  },
300
332
  });
301
333
 
302
- registerBuiltinAlias(pi, {
334
+ registerBuiltinAlias(runtime, pi, {
303
335
  ...descriptions.Grep,
304
336
  builtinName: "grep",
305
337
  parameters: Type.Object({
@@ -317,7 +349,7 @@ function registerClaudeAliases(pi: ExtensionAPI, repoDiscovery: boolean): void {
317
349
  toArgs: toGrepArgs,
318
350
  });
319
351
 
320
- registerBuiltinAlias(pi, {
352
+ registerBuiltinAlias(runtime, pi, {
321
353
  ...descriptions.Glob,
322
354
  builtinName: "find",
323
355
  parameters: Type.Object({
@@ -330,6 +362,7 @@ function registerClaudeAliases(pi: ExtensionAPI, repoDiscovery: boolean): void {
330
362
  }
331
363
 
332
364
  async function runShellAlias(
365
+ runtime: ModelToolsRuntime,
333
366
  id: string,
334
367
  input: ShellAliasInput,
335
368
  signal: AbortSignal | undefined,
@@ -339,14 +372,14 @@ async function runShellAlias(
339
372
  const command = toShellCommand(input);
340
373
  if (!command) throw new Error("Missing shell command");
341
374
  const workdir = await resolveWorkdir(ctx, input.cwd ?? input.workdir);
342
- const tool = createBashToolDefinition(
375
+ const tool = runtime.dependencies.createBashToolDefinition(
343
376
  ctx.cwd,
344
377
  workdir ? { spawnHook: (spawnContext) => ({ ...spawnContext, cwd: workdir }) } : undefined,
345
378
  );
346
379
  return tool.execute(id, { command, timeout: timeoutSeconds(input) }, signal, onUpdate, ctx);
347
380
  }
348
381
 
349
- function registerCodexAliases(pi: ExtensionAPI): void {
382
+ function registerCodexAliases(runtime: ModelToolsRuntime, pi: ExtensionAPI): void {
350
383
  const shellParameters = Type.Object({
351
384
  command: Type.String({ description: "The shell script to execute in the user's default shell" }),
352
385
  workdir: Type.Optional(Type.String({ description: "Working directory" })),
@@ -359,10 +392,10 @@ function registerCodexAliases(pi: ExtensionAPI): void {
359
392
  defineTool({
360
393
  ...CODEX_ALIAS_TOOL_DESCRIPTIONS.shellCommand,
361
394
  parameters: shellParameters,
362
- renderCall: renderShellAliasCall,
363
- renderResult: renderShellAliasResult,
395
+ renderCall: (args, theme, context) => renderShellAliasCall(runtime, args, theme, context),
396
+ renderResult: (result, options, theme, context) => renderShellAliasResult(runtime, result, options, theme, context),
364
397
  async execute(id, params, signal, onUpdate, ctx) {
365
- return runShellAlias(id, params, signal, onUpdate, ctx);
398
+ return runShellAlias(runtime, id, params, signal, onUpdate, ctx);
366
399
  },
367
400
  }),
368
401
  );
@@ -422,9 +455,10 @@ function shouldPreserveSelection(env: NodeJS.ProcessEnv = process.env): boolean
422
455
  .some((value) => typeof value === "string" && /^(1|true|yes|on)$/i.test(value.trim()));
423
456
  }
424
457
 
425
- export default function modelTools(pi: ExtensionAPI): void {
426
- registerClaudeAliases(pi, hasIndexedProjectRoot());
427
- registerCodexAliases(pi);
458
+ export default function modelTools(pi: ExtensionAPI, dependencies: Partial<ModelToolsDependencies> = {}): void {
459
+ const runtime = createModelToolsRuntime(dependencies);
460
+ registerClaudeAliases(runtime, pi, hasIndexedProjectRoot());
461
+ registerCodexAliases(runtime, pi);
428
462
 
429
463
  let baseTools: string[] = [];
430
464