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
@@ -1953,7 +1953,12 @@ export class AppTabsController {
1953
1953
  for (const session of sessions) {
1954
1954
  if (keep.has(session.path))
1955
1955
  continue;
1956
- await this.unlinkSessionAndDcpSidecar(session.path);
1956
+ // Lifecycle state can change while retention is scanning. Re-check the
1957
+ // current runtime/open tabs immediately before destructive work so a
1958
+ // session that became live after the initial snapshot is not removed.
1959
+ if (this.preservedSessionPaths().has(resolve(session.path)))
1960
+ continue;
1961
+ await this.unlinkSessionFile(session.path);
1957
1962
  }
1958
1963
  }
1959
1964
  catch {
@@ -1964,31 +1969,17 @@ export class AppTabsController {
1964
1969
  }
1965
1970
  }
1966
1971
  /**
1967
- * Unlink a project session file and, best-effort, its DCP sidecar state.
1968
- * The sidecar path is derived from the session id in the first line of the
1969
- * `.jsonl` (mirrors the DCP module's `safeSessionFileName`), so retention
1970
- * never leaves orphan sidecars behind. Everything here is best-effort:
1972
+ * Unlink a project session file. Everything here is best-effort:
1971
1973
  * session retention must never interrupt the terminal UI.
1972
1974
  */
1973
- async unlinkSessionAndDcpSidecar(sessionPath) {
1974
- let sidecarPath;
1975
- const header = await readSessionHeader(sessionPath);
1976
- if (header?.type === "session" && typeof header.id === "string" && header.id) {
1977
- sidecarPath = join(dirname(sessionPath), "dcp-state", header.id.replace(/[^a-zA-Z0-9._-]/g, "_") + ".json");
1978
- }
1975
+ async unlinkSessionFile(sessionPath, unlinkFile = unlink) {
1976
+ if (this.preservedSessionPaths().has(resolve(sessionPath)))
1977
+ return;
1979
1978
  try {
1980
- await unlink(sessionPath);
1979
+ await unlinkFile(sessionPath);
1981
1980
  }
1982
1981
  catch {
1983
- // Session retention must never interrupt the terminal UI.
1984
- }
1985
- if (sidecarPath) {
1986
- try {
1987
- await unlink(sidecarPath);
1988
- }
1989
- catch {
1990
- // Sidecar removal is best-effort; never interrupt the terminal UI.
1991
- }
1982
+ return;
1992
1983
  }
1993
1984
  }
1994
1985
  preservedSessionPaths() {
@@ -11,7 +11,20 @@ export declare function isSubagentsLiveStateEvent(value: unknown): value is Suba
11
11
  export declare function isSubagentRegistryRun(runId: string, value: unknown): value is SubagentRegistryRun;
12
12
  export declare function isSubagentRegistryAgent(agentId: string, value: unknown): value is SubagentRegistryAgent;
13
13
  export declare function isSubagentRegistry(value: unknown): value is SubagentRegistry;
14
- export declare function subagentStatusIcon(status: SubagentStatus): string;
14
+ /**
15
+ * Agent icon names accepted in sub-agent `icon:` frontmatter (both bundled
16
+ * agents and `.pi/agents/*.md`). Keys mirror APP_ICONS entries and the Pix
17
+ * Desktop lucide mapping (desktop/src/lib/agent-icons.ts); status is conveyed
18
+ * by color, not by the glyph.
19
+ */
20
+ export declare const SUBAGENT_ICON_NAMES: readonly ["agent", "search", "code", "flask", "globe", "sparkles", "brain", "wrench", "terminal", "bug", "book", "eye", "zap", "rocket"];
21
+ export type SubagentIconName = (typeof SUBAGENT_ICON_NAMES)[number];
22
+ export declare function isSubagentIconName(value: string): value is SubagentIconName;
23
+ /**
24
+ * Resolve the per-agent icon glyph from the task preview. Unknown or missing
25
+ * icon names fall back to the neutral agent glyph.
26
+ */
27
+ export declare function subagentIcon(preview: SubagentTaskPreview | undefined): string;
15
28
  export declare function formatSubagentsPanelStats(agents: readonly SubagentAgentState[]): string;
16
29
  export declare function subagentModelThinkingLabel(preview: SubagentTaskPreview | undefined): string;
17
30
  export declare function activeSubagentStates(agents: readonly SubagentAgentState[]): SubagentAgentState[];
@@ -60,6 +60,8 @@ export function isSubagentTaskPreview(value) {
60
60
  return false;
61
61
  if (value.thinkingLevel !== undefined && typeof value.thinkingLevel !== "string")
62
62
  return false;
63
+ if (value.icon !== undefined && typeof value.icon !== "string")
64
+ return false;
63
65
  return true;
64
66
  }
65
67
  export function isSubagentRunRenderDetails(value) {
@@ -148,21 +150,38 @@ export function isSubagentRegistry(value) {
148
150
  return Object.entries(value.runs).every(([runId, run]) => isSubagentRegistryRun(runId, run))
149
151
  && Object.entries(value.agents).every(([agentId, agent]) => isSubagentRegistryAgent(agentId, agent));
150
152
  }
151
- export function subagentStatusIcon(status) {
152
- switch (status) {
153
- case "planned":
154
- return APP_ICONS.circleOutline;
155
- case "running":
156
- return APP_ICONS.timerSand;
157
- case "retrying":
158
- return APP_ICONS.refresh;
159
- case "done":
160
- return APP_ICONS.checkCircle;
161
- case "failed":
162
- return APP_ICONS.closeCircle;
163
- case "stopped":
164
- return APP_ICONS.stopCircle;
165
- }
153
+ /**
154
+ * Agent icon names accepted in sub-agent `icon:` frontmatter (both bundled
155
+ * agents and `.pi/agents/*.md`). Keys mirror APP_ICONS entries and the Pix
156
+ * Desktop lucide mapping (desktop/src/lib/agent-icons.ts); status is conveyed
157
+ * by color, not by the glyph.
158
+ */
159
+ export const SUBAGENT_ICON_NAMES = [
160
+ "agent",
161
+ "search",
162
+ "code",
163
+ "flask",
164
+ "globe",
165
+ "sparkles",
166
+ "brain",
167
+ "wrench",
168
+ "terminal",
169
+ "bug",
170
+ "book",
171
+ "eye",
172
+ "zap",
173
+ "rocket",
174
+ ];
175
+ export function isSubagentIconName(value) {
176
+ return SUBAGENT_ICON_NAMES.includes(value);
177
+ }
178
+ /**
179
+ * Resolve the per-agent icon glyph from the task preview. Unknown or missing
180
+ * icon names fall back to the neutral agent glyph.
181
+ */
182
+ export function subagentIcon(preview) {
183
+ const name = preview?.icon?.trim();
184
+ return name && isSubagentIconName(name) ? APP_ICONS[name] : APP_ICONS.agent;
166
185
  }
167
186
  export function formatSubagentsPanelStats(agents) {
168
187
  const stats = [
@@ -159,6 +159,8 @@ export type SubagentTaskPreview = {
159
159
  model?: string;
160
160
  thinking?: string;
161
161
  thinkingLevel?: string;
162
+ /** Agent icon name from the subagentType profile; resolved via APP_ICONS. */
163
+ icon?: string;
162
164
  };
163
165
  export type SubagentRunRenderDetails = {
164
166
  runDir: string;
@@ -4,7 +4,7 @@ import { dirname, join, parse, resolve } from "node:path";
4
4
  import { parse as parseJsonc } from "jsonc-parser";
5
5
  const DEFAULT_CONFIG = {
6
6
  enabled: true,
7
- model: "zai/glm-4.5-air",
7
+ model: "zai/glm-5-turbo",
8
8
  fallbackModels: [],
9
9
  maxInputChars: 2000,
10
10
  maxTitleChars: 80,
@@ -944,23 +944,41 @@ export function stripDcpControlMetadata(text) {
944
944
  return text;
945
945
  const lines = text.split("\n");
946
946
  const kept = [];
947
- let inMessageIds = false;
947
+ let candidate;
948
+ let inFence;
948
949
  let touched = false;
949
950
  for (const line of lines) {
950
- if (inMessageIds) {
951
- touched = true;
952
- if (/<\/dcp-message-ids>\s*$/i.test(line))
953
- inMessageIds = false;
951
+ if (candidate) {
952
+ candidate.push(line);
953
+ if (/<\/dcp-message-ids>\s*$/i.test(line)) {
954
+ candidate = undefined;
955
+ touched = true;
956
+ }
954
957
  continue;
955
958
  }
956
- if (/^\s*<dcp-message-ids>/i.test(line)) {
957
- touched = true;
958
- if (!/<\/dcp-message-ids>\s*$/i.test(line))
959
- inMessageIds = true;
959
+ const quoteLine = /^\s{0,3}>/.test(line);
960
+ if (!quoteLine) {
961
+ const fence = markdownFence(line);
962
+ if (fence) {
963
+ if (!inFence)
964
+ inFence = { marker: fence.marker, length: fence.length };
965
+ else if (fence.marker === inFence.marker && fence.length >= inFence.length)
966
+ inFence = undefined;
967
+ }
968
+ }
969
+ if (!inFence && !quoteLine && /^\s*<dcp-message-ids>/i.test(line)) {
970
+ if (/<\/dcp-message-ids>\s*$/i.test(line)) {
971
+ touched = true;
972
+ }
973
+ else {
974
+ candidate = [line];
975
+ }
960
976
  continue;
961
977
  }
962
978
  kept.push(line);
963
979
  }
980
+ if (candidate)
981
+ kept.push(...candidate);
964
982
  return touched ? kept.join("\n").trimEnd() : text;
965
983
  }
966
984
  function isHiddenMarkdownMetadataLine(line) {
@@ -30,7 +30,6 @@ export declare const PiToolsSuiteConfigSchema: Type.TObject<{
30
30
  }>>;
31
31
  manualMode: Type.TOptional<Type.TObject<{
32
32
  enabled: Type.TOptional<Type.TBoolean>;
33
- automaticStrategies: Type.TOptional<Type.TBoolean>;
34
33
  }>>;
35
34
  compress: Type.TOptional<Type.TObject<{
36
35
  maxContextPercent: Type.TOptional<Type.TUnion<[Type.TNumber, Type.TString]>>;
@@ -63,28 +62,26 @@ export declare const PiToolsSuiteConfigSchema: Type.TObject<{
63
62
  highTokens: Type.TOptional<Type.TNumber>;
64
63
  maxSuggestions: Type.TOptional<Type.TNumber>;
65
64
  }>>;
66
- }>>;
67
- strategies: Type.TOptional<Type.TObject<{
68
- deduplication: Type.TOptional<Type.TObject<{
65
+ autoCompress: Type.TOptional<Type.TObject<{
69
66
  enabled: Type.TOptional<Type.TBoolean>;
70
- protectedTools: Type.TOptional<Type.TArray<Type.TString>>;
71
- }>>;
72
- purgeErrors: Type.TOptional<Type.TObject<{
73
- enabled: Type.TOptional<Type.TBoolean>;
74
- turns: Type.TOptional<Type.TNumber>;
75
- protectedTools: Type.TOptional<Type.TArray<Type.TString>>;
67
+ patience: Type.TOptional<Type.TNumber>;
68
+ summarizerModel: Type.TOptional<Type.TArray<Type.TString>>;
69
+ timeoutMs: Type.TOptional<Type.TNumber>;
76
70
  }>>;
77
- autoToolPruning: Type.TOptional<Type.TObject<{
71
+ }>>;
72
+ strategies: Type.TOptional<Type.TObject<{
73
+ emergencyCurrentTurnPruning: Type.TOptional<Type.TObject<{
78
74
  enabled: Type.TOptional<Type.TBoolean>;
79
- maxOutputTokens: Type.TOptional<Type.TNumber>;
80
- keepRecentTurns: Type.TOptional<Type.TNumber>;
81
- readLikeTools: Type.TOptional<Type.TArray<Type.TString>>;
82
- readLikeTurns: Type.TOptional<Type.TNumber>;
75
+ hardContextPercent: Type.TOptional<Type.TNumber>;
76
+ targetContextPercent: Type.TOptional<Type.TNumber>;
77
+ patience: Type.TOptional<Type.TNumber>;
78
+ keepRecentToolPairs: Type.TOptional<Type.TNumber>;
79
+ minOutputTokens: Type.TOptional<Type.TNumber>;
80
+ maxSuggestions: Type.TOptional<Type.TNumber>;
83
81
  protectedTools: Type.TOptional<Type.TArray<Type.TString>>;
84
82
  }>>;
85
83
  }>>;
86
84
  protectedFilePatterns: Type.TOptional<Type.TArray<Type.TString>>;
87
- pruneNotification: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"detailed">]>>;
88
85
  }>>;
89
86
  asyncSubagents: Type.TOptional<Type.TObject<{
90
87
  defaultType: Type.TOptional<Type.TString>;
@@ -103,6 +100,7 @@ export declare const PiToolsSuiteConfigSchema: Type.TObject<{
103
100
  }>>;
104
101
  presets: Type.TOptional<Type.TRecord<"^.*$", Type.TObject<{
105
102
  description: Type.TOptional<Type.TString>;
103
+ models: Type.TOptional<Type.TArray<Type.TString>>;
106
104
  model: Type.TOptional<Type.TString>;
107
105
  fallbackModels: Type.TOptional<Type.TArray<Type.TString>>;
108
106
  thinking: Type.TOptional<Type.TString>;
@@ -118,6 +116,8 @@ export declare const PiToolsSuiteConfigSchema: Type.TObject<{
118
116
  }>>>;
119
117
  types: Type.TOptional<Type.TRecord<"^.*$", Type.TObject<{
120
118
  description: Type.TOptional<Type.TString>;
119
+ icon: Type.TOptional<Type.TString>;
120
+ models: Type.TOptional<Type.TArray<Type.TString>>;
121
121
  model: Type.TOptional<Type.TString>;
122
122
  fallbackModels: Type.TOptional<Type.TArray<Type.TString>>;
123
123
  thinking: Type.TOptional<Type.TString>;
@@ -171,6 +171,19 @@ export declare const PiToolsSuiteConfigSchema: Type.TObject<{
171
171
  sessionHygiene: Type.TOptional<Type.TBoolean>;
172
172
  notify: Type.TOptional<Type.TBoolean>;
173
173
  }>>;
174
+ contextGateway: Type.TOptional<Type.TObject<{
175
+ mode: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"observe">, Type.TLiteral<"enforce">]>>;
176
+ budgets: Type.TOptional<Type.TObject<{
177
+ maxInlineBytes: Type.TOptional<Type.TInteger>;
178
+ maxResultBytes: Type.TOptional<Type.TInteger>;
179
+ maxExactReadBytes: Type.TOptional<Type.TInteger>;
180
+ maxSearchBytes: Type.TOptional<Type.TInteger>;
181
+ maxSearchMatches: Type.TOptional<Type.TInteger>;
182
+ }>>;
183
+ }>>;
184
+ repoDiscovery: Type.TOptional<Type.TObject<{
185
+ profile: Type.TOptional<Type.TUnion<[Type.TLiteral<"baseline">, Type.TLiteral<"native-compact">]>>;
186
+ }>>;
174
187
  lsp: Type.TOptional<Type.TObject<{
175
188
  servers: Type.TOptional<Type.TArray<Type.TObject<{
176
189
  id: Type.TString;
@@ -39,7 +39,6 @@ const TerminalBellConfig = Type.Object({
39
39
  // ---------------------------------------------------------------------------
40
40
  const DcpManualModeConfig = Type.Object({
41
41
  enabled: Type.Optional(Type.Boolean({ description: "Enable manual DCP mode." })),
42
- automaticStrategies: Type.Optional(Type.Boolean({ description: "Run dedup/purge even in manual mode." })),
43
42
  }, { description: "Manual mode configuration." });
44
43
  const DcpAutoCandidatesConfig = Type.Object({
45
44
  enabled: Type.Optional(Type.Boolean({ description: "Enable auto candidate selection for compression." })),
@@ -56,6 +55,12 @@ const DcpMessageModeConfig = Type.Object({
56
55
  highTokens: Type.Optional(Type.Number({ description: "Token threshold for high-quality summary.", minimum: 0 })),
57
56
  maxSuggestions: Type.Optional(Type.Number({ description: "Maximum compression suggestions.", minimum: 0 })),
58
57
  }, { description: "Message-mode compression configuration." });
58
+ const DcpAutoCompressConfig = Type.Object({
59
+ enabled: Type.Optional(Type.Boolean({ description: "Allow bounded automatic summary creation after pressure/opportunity gates." })),
60
+ patience: Type.Optional(Type.Number({ description: "Completed actionable opportunities allowed before automatic compression.", minimum: 0 })),
61
+ summarizerModel: Type.Optional(Type.Array(Type.String(), { description: "Ordered summarizer model refs; empty uses the deterministic extractive summary." })),
62
+ timeoutMs: Type.Optional(Type.Number({ description: "Per-summarizer deadline in milliseconds.", minimum: 1 })),
63
+ }, { description: "Bounded automatic compression fallback." });
59
64
  const DcpCompressConfig = Type.Object({
60
65
  maxContextPercent: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: "Maximum context percent (0–1 or '80%') before compression triggers." })),
61
66
  minContextPercent: Type.Optional(Type.Union([Type.Number(), Type.String()], { description: "Target context percent after compression." })),
@@ -74,29 +79,21 @@ const DcpCompressConfig = Type.Object({
74
79
  protectUserMessages: Type.Optional(Type.Boolean({ description: "Protect user messages from pruning." })),
75
80
  autoCandidates: Type.Optional(DcpAutoCandidatesConfig),
76
81
  messageMode: Type.Optional(DcpMessageModeConfig),
82
+ autoCompress: Type.Optional(DcpAutoCompressConfig),
77
83
  }, { description: "Compression trigger and behavior configuration." });
78
- const DcpDeduplicationConfig = Type.Object({
79
- enabled: Type.Optional(Type.Boolean({ description: "Enable duplicate content deduplication." })),
80
- protectedTools: Type.Optional(Type.Array(Type.String(), { description: "Tool outputs protected from dedup." })),
81
- }, { description: "Deduplication strategy configuration." });
82
- const DcpPurgeErrorsConfig = Type.Object({
83
- enabled: Type.Optional(Type.Boolean({ description: "Enable error input purging." })),
84
- turns: Type.Optional(Type.Number({ description: "Prune error inputs after N user turns.", minimum: 1 })),
85
- protectedTools: Type.Optional(Type.Array(Type.String(), { description: "Tool outputs protected from error purge." })),
86
- }, { description: "Error purging strategy configuration." });
87
- const DcpAutoToolPruningConfig = Type.Object({
88
- enabled: Type.Optional(Type.Boolean({ description: "Enable automatic tool output pruning." })),
89
- maxOutputTokens: Type.Optional(Type.Number({ description: "Maximum output tokens before truncation.", minimum: 0 })),
90
- keepRecentTurns: Type.Optional(Type.Number({ description: "Recent turns to keep.", minimum: 0 })),
91
- readLikeTools: Type.Optional(Type.Array(Type.String(), { description: "Tools treated as read-like (aggressively pruned)." })),
92
- readLikeTurns: Type.Optional(Type.Number({ description: "Turns threshold for read-like tool pruning.", minimum: 0 })),
93
- protectedTools: Type.Optional(Type.Array(Type.String(), { description: "Tool outputs protected from auto-pruning." })),
94
- }, { description: "Auto tool pruning strategy configuration." });
84
+ const DcpEmergencyCurrentTurnPruningConfig = Type.Object({
85
+ enabled: Type.Optional(Type.Boolean({ description: "Enable bounded same-turn emergency planning and last-resort output pruning." })),
86
+ hardContextPercent: Type.Optional(Type.Number({ description: "Context fraction that activates hard emergency pressure.", minimum: 0, maximum: 1 })),
87
+ targetContextPercent: Type.Optional(Type.Number({ description: "Context fraction the emergency path attempts to recover toward.", minimum: 0, maximum: 1 })),
88
+ patience: Type.Optional(Type.Number({ description: "Completed emergency opportunities allowed before last-resort pruning.", minimum: 0 })),
89
+ keepRecentToolPairs: Type.Optional(Type.Number({ description: "Newest complete tool-call/result pairs never selected by emergency cleanup.", minimum: 0 })),
90
+ minOutputTokens: Type.Optional(Type.Number({ description: "Minimum tool-result size eligible for emergency pruning.", minimum: 0 })),
91
+ maxSuggestions: Type.Optional(Type.Number({ description: "Maximum emergency message candidates shown in a reminder.", minimum: 0 })),
92
+ protectedTools: Type.Optional(Type.Array(Type.String(), { description: "Additional tools protected from emergency pruning and manual sweep." })),
93
+ }, { description: "Single bounded emergency cleanup strategy." });
95
94
  const DcpStrategiesConfig = Type.Object({
96
- deduplication: Type.Optional(DcpDeduplicationConfig),
97
- purgeErrors: Type.Optional(DcpPurgeErrorsConfig),
98
- autoToolPruning: Type.Optional(DcpAutoToolPruningConfig),
99
- }, { description: "DCP pruning strategies." });
95
+ emergencyCurrentTurnPruning: Type.Optional(DcpEmergencyCurrentTurnPruningConfig),
96
+ }, { description: "Bounded DCP emergency strategy." });
100
97
  const DcpConfig = Type.Object({
101
98
  enabled: Type.Optional(Type.Boolean({ description: "Enable DCP (Dynamic Context Pruning)." })),
102
99
  debug: Type.Optional(Type.Boolean({ description: "Enable DCP debug logging." })),
@@ -108,7 +105,6 @@ const DcpConfig = Type.Object({
108
105
  compress: Type.Optional(DcpCompressConfig),
109
106
  strategies: Type.Optional(DcpStrategiesConfig),
110
107
  protectedFilePatterns: Type.Optional(Type.Array(Type.String(), { description: "File path glob patterns whose content is protected from pruning." })),
111
- pruneNotification: Type.Optional(Type.Union([Type.Literal("off"), Type.Literal("minimal"), Type.Literal("detailed")], { description: "Notification level when pruning occurs." })),
112
108
  }, { description: "DCP (Dynamic Context Pruning) configuration." });
113
109
  // ---------------------------------------------------------------------------
114
110
  // Async subagents
@@ -119,7 +115,7 @@ const RetryConfig = Type.Object({
119
115
  retryableExitCodes: Type.Optional(Type.Array(Type.Number(), { description: "Exit codes eligible for retry. Empty array disables retry." })),
120
116
  }, { description: "Retry configuration for sub-agents." });
121
117
  const SubagentRoutingConfig = Type.Object({
122
- enabled: Type.Optional(Type.Boolean({ description: "Enable LLM-based automatic role routing." })),
118
+ enabled: Type.Optional(Type.Boolean({ description: "Enable fallback LLM selection for omitted subagentType values. Explicit valid types bypass the router; when disabled, every spawn task must specify a valid type." })),
123
119
  model: Type.Optional(Type.String({ description: "Router model in provider/model form." })),
124
120
  fallbackModels: Type.Optional(Type.Array(Type.String(), { uniqueItems: true, description: "Ordered router model fallbacks tried when the primary routing model is unavailable or fails. The current parent model is always tried last." })),
125
121
  maxTaskChars: Type.Optional(Type.Number({ description: "Max task/scope characters sent to router.", minimum: 100 })),
@@ -127,7 +123,7 @@ const SubagentRoutingConfig = Type.Object({
127
123
  maxRetries: Type.Optional(Type.Number({ description: "Router request retries.", minimum: 0 })),
128
124
  timeoutMs: Type.Optional(Type.Number({ description: "Router request timeout in ms.", minimum: 1000 })),
129
125
  debug: Type.Optional(Type.Boolean({ description: "Show routing debug warnings." })),
130
- }, { description: "LLM-based role routing configuration." });
126
+ }, { description: "Fallback role routing for omitted types. Unknown explicit types or failed/incomplete routing reject the entire batch before any agents launch." });
131
127
  const SubagentVisionConfig = Type.Object({
132
128
  blindModelPatterns: Type.Optional(Type.Array(Type.String(), { description: "Glob-like model refs treated as unable to inspect images." })),
133
129
  }, { description: "Vision capability overrides." });
@@ -140,17 +136,20 @@ const SubagentPresetTypeOverride = Type.Object({
140
136
  }, { description: "Per-type override within a preset." });
141
137
  const SubagentPreset = Type.Object({
142
138
  description: Type.Optional(Type.String({ description: "Preset description." })),
143
- model: Type.Optional(Type.String({ description: "Default model for this preset." })),
144
- fallbackModels: Type.Optional(Type.Array(Type.String(), { description: "Global fallback models for this preset." })),
139
+ models: Type.Optional(Type.Array(Type.String({ pattern: "^[^\\s/*]+/[^\\s*]+$" }), { uniqueItems: true, description: "Available model pool. Filter the agent's ordered models by membership; pool order is ignored. Empty intersection rejects spawn. Oracle also respects this pool." })),
140
+ model: Type.Optional(Type.String({ description: "Legacy default model. Ignored when models is set.", deprecated: true })),
141
+ fallbackModels: Type.Optional(Type.Array(Type.String(), { description: "Legacy fallback list. Ignored when models is set.", deprecated: true })),
145
142
  thinking: Type.Optional(Type.String({ description: "Default thinking level." })),
146
143
  extraArgs: Type.Optional(Type.Array(Type.String(), { description: "Extra CLI arguments." })),
147
144
  timeoutMs: Type.Optional(Type.Number({ description: "Per-agent wall-clock timeout in ms.", minimum: 1 })),
148
145
  types: Type.Optional(Type.Record(Type.String(), SubagentPresetTypeOverride, { description: "Per-type overrides." })),
149
- }, { description: "Named spawn preset." });
146
+ }, { description: "Named available-model pool. Legacy model/types overrides remain supported; prefer models for new presets." });
150
147
  const SubagentTypeConfig = Type.Object({
151
148
  description: Type.Optional(Type.String({ description: "Role description for routing." })),
152
- model: Type.Optional(Type.String({ description: "Model for this sub-agent type." })),
153
- fallbackModels: Type.Optional(Type.Array(Type.String(), { description: "Ordered model fallbacks." })),
149
+ icon: Type.Optional(Type.String({ description: "Agent icon name rendered by UIs (pix TUI icon themes and Pix Desktop lucide icons): agent, search, code, flask, globe, sparkles, brain, wrench, terminal, bug, book, eye, zap, rocket. Unknown names render as the neutral agent icon." })),
150
+ models: Type.Optional(Type.Array(Type.String({ pattern: "^[^\\s/*]+/[^\\s*]+$" }), { uniqueItems: true, description: "Ordered model candidates. First usable member of the preset pool runs; only remaining compatible members can be used on quota failure. Replaces legacy model/fallbackModels/modelByParent selection." })),
151
+ model: Type.Optional(Type.String({ description: "Legacy primary model; use models for new profiles.", deprecated: true })),
152
+ fallbackModels: Type.Optional(Type.Array(Type.String(), { description: "Legacy candidates after model; use models for a complete ranked list.", deprecated: true })),
154
153
  thinking: Type.Optional(Type.String({ description: "Thinking level." })),
155
154
  tools: Type.Optional(Type.Array(Type.String(), { description: "Enabled tools for this type." })),
156
155
  isolatedSkills: Type.Optional(Type.Array(Type.String(), { description: "Explicit skill files loaded after disabling normal skill discovery for this type." })),
@@ -162,7 +161,7 @@ const SubagentTypeConfig = Type.Object({
162
161
  timeoutMs: Type.Optional(Type.Number({ description: "Per-agent wall-clock timeout in ms.", minimum: 1 })),
163
162
  }, { description: "Configuration for a sub-agent type/role." });
164
163
  const AsyncSubagentsConfig = Type.Object({
165
- defaultType: Type.Optional(Type.String({ description: "Default sub-agent type when not specified." })),
164
+ defaultType: Type.Optional(Type.String({ description: "Preferred role for genuinely ambiguous router tasks and legacy resolver default. Not used as a spawn fallback for missing/invalid routes." })),
166
165
  routing: Type.Optional(SubagentRoutingConfig),
167
166
  vision: Type.Optional(SubagentVisionConfig),
168
167
  presets: Type.Optional(Type.Record(Type.String(), SubagentPreset, { description: "Named spawn presets." })),
@@ -186,6 +185,20 @@ const SecretFirewallConfig = Type.Object({
186
185
  sessionHygiene: Type.Optional(Type.Boolean({ description: "Redact detected secret material from tool results and completed messages before it remains in session history." })),
187
186
  notify: Type.Optional(Type.Boolean({ description: "Show a warning when one or more secrets are redacted. Secret values are never included in notifications." })),
188
187
  }, { description: "Settings for the opt-in credential-firewall module." });
188
+ const ContextGatewayBudgetsConfig = Type.Object({
189
+ maxInlineBytes: Type.Optional(Type.Integer({ minimum: 1, maximum: 67108864, description: "Initial inline byte budget used by Context Gateway policy experiments. Default 8192." })),
190
+ maxResultBytes: Type.Optional(Type.Integer({ minimum: 1, maximum: 67108864, description: "Experimental delivered-result byte budget. P01 observe measures the available tool-result content boundary; later shaping must account for the final provider-visible serialization. Default 8192." })),
191
+ maxExactReadBytes: Type.Optional(Type.Integer({ minimum: 1, maximum: 67108864, description: "Future exact-read byte budget. Default 32768." })),
192
+ maxSearchBytes: Type.Optional(Type.Integer({ minimum: 1, maximum: 67108864, description: "Future search-delivery byte budget. Default 8192." })),
193
+ maxSearchMatches: Type.Optional(Type.Integer({ minimum: 1, maximum: 1000, description: "Future search match budget. Default 12." })),
194
+ }, { description: "Context Gateway delivery budgets. In P01 only maxResultBytes is used for passive observe accounting." });
195
+ const ContextGatewayConfig = Type.Object({
196
+ mode: Type.Optional(Type.Union([Type.Literal("off"), Type.Literal("observe"), Type.Literal("enforce")], { description: "Context Gateway mode. P01 implements off/observe; enforce is parsed but explicitly refused until later integration gates." })),
197
+ budgets: Type.Optional(ContextGatewayBudgetsConfig),
198
+ }, { description: "Context Gateway configuration. Default mode is off." });
199
+ const RepoDiscoveryConfig = Type.Object({
200
+ profile: Type.Optional(Type.Union([Type.Literal("baseline"), Type.Literal("native-compact")], { description: "repo_* runtime profile. baseline preserves historical argv/defaults; native-compact enables bounded native flags, cursors, validation, and an explicit per-call full override." })),
201
+ }, { description: "Repository discovery runtime policy. Default profile is baseline." });
189
202
  // ---------------------------------------------------------------------------
190
203
  // LSP
191
204
  // ---------------------------------------------------------------------------
@@ -239,6 +252,8 @@ export const PiToolsSuiteConfigSchema = Type.Object({
239
252
  toolRenderer: Type.Optional(ToolRendererConfig),
240
253
  promptCommands: Type.Optional(PromptCommandsConfig),
241
254
  secretFirewall: Type.Optional(SecretFirewallConfig),
255
+ contextGateway: Type.Optional(ContextGatewayConfig),
256
+ repoDiscovery: Type.Optional(RepoDiscoveryConfig),
242
257
  lsp: Type.Optional(LspConfig),
243
258
  }, {
244
259
  $id: "https://unpkg.com/pi-ui-extend/schemas/pi-tools-suite.json",