@diegopetrucci/pi-extensions 0.1.57 → 0.1.59

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 (102) hide show
  1. package/.pi-fleet-tested-version +1 -1
  2. package/extensions/agent-workflow-audit/.pi-fleet-tested-version +1 -1
  3. package/extensions/agent-workflow-audit/index.ts +8 -1
  4. package/extensions/agent-workflow-audit/package.json +5 -1
  5. package/extensions/annotate-git-diff/.pi-fleet-tested-version +1 -1
  6. package/extensions/annotate-git-diff/package.json +5 -2
  7. package/extensions/annotate-last-message/.pi-fleet-tested-version +1 -1
  8. package/extensions/annotate-last-message/package.json +5 -2
  9. package/extensions/brrr/.pi-fleet-tested-version +1 -1
  10. package/extensions/brrr/README.md +2 -2
  11. package/extensions/brrr/package.json +5 -1
  12. package/extensions/claude-fast/.pi-fleet-tested-version +1 -1
  13. package/extensions/claude-fast/package.json +5 -1
  14. package/extensions/code-reviewer/.pi-fleet-tested-version +1 -1
  15. package/extensions/code-reviewer/index.ts +129 -39
  16. package/extensions/code-reviewer/package.json +5 -1
  17. package/extensions/confirm-destructive/.pi-fleet-tested-version +1 -1
  18. package/extensions/confirm-destructive/README.md +1 -1
  19. package/extensions/confirm-destructive/index.ts +20 -5
  20. package/extensions/confirm-destructive/package.json +5 -1
  21. package/extensions/context-cap/.pi-fleet-tested-version +1 -1
  22. package/extensions/context-cap/package.json +5 -1
  23. package/extensions/context-inspector/.pi-fleet-tested-version +1 -1
  24. package/extensions/context-inspector/package.json +5 -1
  25. package/extensions/contrarian/.pi-fleet-tested-version +1 -1
  26. package/extensions/contrarian/README.md +1 -1
  27. package/extensions/contrarian/index.ts +199 -40
  28. package/extensions/contrarian/package.json +5 -1
  29. package/extensions/dirty-repo-guard/.pi-fleet-tested-version +1 -1
  30. package/extensions/dirty-repo-guard/README.md +1 -1
  31. package/extensions/dirty-repo-guard/package.json +5 -1
  32. package/extensions/dynamic-context-pruning/.pi-fleet-tested-version +1 -1
  33. package/extensions/dynamic-context-pruning/package.json +4 -1
  34. package/extensions/git-footer/.pi-fleet-tested-version +1 -1
  35. package/extensions/git-footer/package.json +5 -1
  36. package/extensions/gnosis/.pi-fleet-tested-version +1 -1
  37. package/extensions/gnosis/package.json +5 -1
  38. package/extensions/illustrations-to-explain-things/.pi-fleet-tested-version +1 -1
  39. package/extensions/illustrations-to-explain-things/package.json +4 -1
  40. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/01-two-breakpoints.webp +0 -0
  41. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/02-minimum-loop.webp +0 -0
  42. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/03-sort-by-purpose.webp +0 -0
  43. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/04-one-fish-many-uses.webp +0 -0
  44. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/05-handoff-path.webp +0 -0
  45. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/06-three-sources.webp +0 -0
  46. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/07-three-content-jobs.webp +0 -0
  47. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/08-handoff-copy-toolbox.webp +0 -0
  48. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/09-common-pits-no-title.webp +0 -0
  49. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/10-information-well.webp +0 -0
  50. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/11-idea-press.webp +0 -0
  51. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/12-content-fermentation.webp +0 -0
  52. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/13-system-bearing.webp +0 -0
  53. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/14-trust-bridge.webp +0 -0
  54. package/extensions/inline-bash/.pi-fleet-tested-version +1 -1
  55. package/extensions/inline-bash/README.md +1 -1
  56. package/extensions/inline-bash/package.json +5 -1
  57. package/extensions/librarian/.pi-fleet-tested-version +1 -1
  58. package/extensions/librarian/index.ts +393 -107
  59. package/extensions/librarian/package.json +5 -1
  60. package/extensions/minimal-footer/.pi-fleet-tested-version +1 -1
  61. package/extensions/minimal-footer/index.ts +2 -5
  62. package/extensions/minimal-footer/openai-usage.ts +58 -11
  63. package/extensions/minimal-footer/package.json +5 -1
  64. package/extensions/notify/.pi-fleet-tested-version +1 -1
  65. package/extensions/notify/README.md +3 -3
  66. package/extensions/notify/package.json +5 -1
  67. package/extensions/openai-fast/.pi-fleet-tested-version +1 -1
  68. package/extensions/openai-fast/package.json +5 -1
  69. package/extensions/oracle/.pi-fleet-tested-version +1 -1
  70. package/extensions/oracle/README.md +1 -1
  71. package/extensions/oracle/index.ts +200 -41
  72. package/extensions/oracle/package.json +5 -1
  73. package/extensions/permission-gate/.pi-fleet-tested-version +1 -1
  74. package/extensions/permission-gate/README.md +1 -1
  75. package/extensions/permission-gate/index.ts +453 -2
  76. package/extensions/permission-gate/package.json +5 -1
  77. package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
  78. package/extensions/quiet-tools/package.json +5 -1
  79. package/extensions/review/.pi-fleet-tested-version +1 -1
  80. package/extensions/review/index.ts +53 -19
  81. package/extensions/review/package.json +5 -1
  82. package/extensions/todo/.pi-fleet-tested-version +1 -1
  83. package/extensions/todo/README.md +1 -1
  84. package/extensions/todo/package.json +5 -1
  85. package/extensions/triage-comments/.pi-fleet-tested-version +1 -1
  86. package/extensions/triage-comments/index.ts +115 -34
  87. package/extensions/triage-comments/package.json +5 -1
  88. package/package.json +10 -6
  89. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/01-two-breakpoints.png +0 -0
  90. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/02-minimum-loop.png +0 -0
  91. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/03-sort-by-purpose.png +0 -0
  92. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/04-one-fish-many-uses.png +0 -0
  93. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/05-handoff-path.png +0 -0
  94. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/06-three-sources.png +0 -0
  95. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/07-three-content-jobs.png +0 -0
  96. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/08-handoff-copy-toolbox.png +0 -0
  97. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/09-common-pits-no-title.png +0 -0
  98. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/10-information-well.png +0 -0
  99. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/11-idea-press.png +0 -0
  100. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/12-content-fermentation.png +0 -0
  101. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/13-system-bearing.png +0 -0
  102. package/extensions/illustrations-to-explain-things/skills/illustrations-to-explain-things/assets/examples/14-trust-bridge.png +0 -0
@@ -2,6 +2,7 @@ import * as fs from "node:fs/promises";
2
2
  import * as path from "node:path";
3
3
 
4
4
  import type { AgentSession, ExecResult, ExtensionAPI, ExtensionCommandContext, ExtensionFactory } from "@earendil-works/pi-coding-agent";
5
+ import type { Usage } from "@earendil-works/pi-ai";
5
6
  import {
6
7
  DefaultResourceLoader,
7
8
  SessionManager,
@@ -91,6 +92,13 @@ const MUTATING_GH_API_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
91
92
 
92
93
  type TriageStatus = "running" | "done" | "error" | "aborted";
93
94
 
95
+ type CreateAgentSessionOptions = NonNullable<Parameters<typeof createAgentSession>[0]>;
96
+
97
+ function getModelRuntimeOption(ctx: { modelRegistry?: unknown }): Pick<CreateAgentSessionOptions, "modelRuntime"> {
98
+ const modelRuntime = (ctx.modelRegistry as { runtime?: CreateAgentSessionOptions["modelRuntime"] } | undefined)?.runtime;
99
+ return modelRuntime ? { modelRuntime } : {};
100
+ }
101
+
94
102
  type ToolCall = {
95
103
  id: string;
96
104
  name: string;
@@ -322,26 +330,72 @@ function ensureImplementationNote(text: string): string {
322
330
  return `${trimmed}\n\n---\n${IMPLEMENTATION_NOTE}`;
323
331
  }
324
332
 
325
- function extractLastAssistantText(messages: unknown[]): string {
326
- for (let i = messages.length - 1; i >= 0; i--) {
327
- const message = messages[i] as { role?: string; content?: unknown };
328
- if (message?.role !== "assistant" || !Array.isArray(message.content)) continue;
329
- const parts: string[] = [];
330
- for (const part of message.content) {
331
- if (part && typeof part === "object" && (part as { type?: string }).type === "text") {
332
- const text = (part as { text?: unknown }).text;
333
- if (typeof text === "string") parts.push(text);
334
- }
335
- }
336
- if (parts.length) return parts.join("").trim();
333
+ function createEmptyUsage(): Usage {
334
+ return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } };
335
+ }
336
+
337
+ function addUsage(total: Usage, usage: Usage): void {
338
+ total.input += usage.input || 0;
339
+ total.output += usage.output || 0;
340
+ total.cacheRead += usage.cacheRead || 0;
341
+ total.cacheWrite += usage.cacheWrite || 0;
342
+ if (usage.cacheWrite1h !== undefined) total.cacheWrite1h = (total.cacheWrite1h ?? 0) + usage.cacheWrite1h;
343
+ if (usage.reasoning !== undefined) total.reasoning = (total.reasoning ?? 0) + usage.reasoning;
344
+ total.totalTokens += usage.totalTokens || 0;
345
+ total.cost.input += usage.cost?.input || 0;
346
+ total.cost.output += usage.cost?.output || 0;
347
+ total.cost.cacheRead += usage.cost?.cacheRead || 0;
348
+ total.cost.cacheWrite += usage.cost?.cacheWrite || 0;
349
+ total.cost.total += usage.cost?.total || 0;
350
+ }
351
+
352
+ type AssistantLikeMessage = { role?: string; content?: unknown; stopReason?: unknown; errorMessage?: unknown; usage?: unknown };
353
+
354
+ function addAssistantMessageUsage(total: Usage, message: unknown): void {
355
+ const assistant = message as AssistantLikeMessage;
356
+ if (assistant?.role !== "assistant" || !assistant.usage || typeof assistant.usage !== "object") return;
357
+ addUsage(total, assistant.usage as Usage);
358
+ }
359
+
360
+ function aggregateAssistantUsage(messages: unknown[]): Usage {
361
+ const total = createEmptyUsage();
362
+ for (const message of messages) addAssistantMessageUsage(total, message);
363
+ return total;
364
+ }
365
+
366
+ function addSessionEventUsage(total: Usage, event: unknown): void {
367
+ const sessionEvent = event as { type?: string; message?: unknown; result?: { usage?: Usage } };
368
+ if (sessionEvent?.type === "message_end") return void addAssistantMessageUsage(total, sessionEvent.message);
369
+ if (sessionEvent?.type === "compaction_end" && sessionEvent.result?.usage) addUsage(total, sessionEvent.result.usage);
370
+ }
371
+
372
+ function inspectFinalAssistant(messages: unknown[]):
373
+ | { ok: true; answer: string; stopReason?: string }
374
+ | { ok: false; reason: string; stopReason?: string; errorMessage?: string } {
375
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
376
+ const message = messages[i] as AssistantLikeMessage;
377
+ if (message?.role !== "assistant") continue;
378
+ const stopReason = typeof message.stopReason === "string" ? message.stopReason.trim() : "";
379
+ const errorMessage = typeof message.errorMessage === "string" ? message.errorMessage.trim() : "";
380
+ const answer = Array.isArray(message.content)
381
+ ? message.content
382
+ .map((part) => (part && typeof part === "object" && (part as { type?: string }).type === "text" && typeof (part as { text?: unknown }).text === "string"
383
+ ? (part as { text: string }).text
384
+ : ""))
385
+ .join("")
386
+ .trim()
387
+ : "";
388
+ if (stopReason === "error") return { ok: false, reason: `triage_comments subagent error: ${errorMessage || "provider/model error"}`, stopReason, errorMessage };
389
+ if (stopReason === "aborted") return { ok: false, reason: "triage_comments subagent aborted before producing a usable answer", stopReason };
390
+ if (answer) return { ok: true, answer, stopReason: stopReason || undefined };
391
+ return { ok: false, reason: stopReason ? `triage_comments subagent produced no final assistant text (stopReason: ${stopReason})` : "triage_comments subagent produced no final assistant text", stopReason: stopReason || undefined, errorMessage: errorMessage || undefined };
337
392
  }
338
- return "";
393
+ return { ok: false, reason: "triage_comments subagent produced no assistant message" };
339
394
  }
340
395
 
341
- function isAbortLikeError(error: unknown): boolean {
342
- if (error && typeof error === "object" && (error as { name?: unknown }).name === "AbortError") return true;
343
- const message = error instanceof Error ? error.message : String(error);
344
- return /aborted|cancelled|canceled/i.test(message);
396
+ function classifyRunFailure(error: unknown, aborted: boolean): { status: "aborted" | "error"; message: string; error?: string } {
397
+ const message = aborted ? "Aborted" : error instanceof Error ? error.message : String(error);
398
+ return { status: aborted ? "aborted" : "error", message, error: aborted ? undefined : message };
345
399
  }
346
400
 
347
401
  function isInside(parent: string, child: string): boolean {
@@ -1897,9 +1951,21 @@ export const __test__ = {
1897
1951
  parseSelectionList,
1898
1952
  parseTriageCommandArgs,
1899
1953
  prepareArguments,
1954
+ aggregateAssistantUsage,
1955
+ addAssistantMessageUsage,
1956
+ addSessionEventUsage,
1957
+ inspectFinalAssistant,
1958
+ classifyRunFailure,
1900
1959
  };
1901
1960
 
1902
1961
  export default function triageCommentsExtension(pi: ExtensionAPI) {
1962
+ pi.on("tool_result", async (event) => {
1963
+ if (event.toolName !== "triage_comments") return undefined;
1964
+ const details = event.details as { status?: unknown } | undefined;
1965
+ if (details?.status !== "error") return undefined;
1966
+ return { isError: true };
1967
+ });
1968
+
1903
1969
  pi.registerCommand("triage-comments", {
1904
1970
  description: "Collect pasted feedback or PR comments, then start a triage_comments investigation",
1905
1971
  getArgumentCompletions: (prefix) => {
@@ -1981,24 +2047,29 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
1981
2047
  let unsubscribe: (() => void) | undefined;
1982
2048
  let runTimeout: NodeJS.Timeout | undefined;
1983
2049
  let abortListenerAdded = false;
1984
- let aborted = Boolean(signal?.aborted);
2050
+ let callerAborted = Boolean(signal?.aborted);
2051
+ const usage = createEmptyUsage();
1985
2052
 
1986
2053
  const emit = () => {
1987
2054
  onUpdate?.({ content: [{ type: "text", text: lastContent }], details });
1988
2055
  };
1989
2056
 
1990
- const abort = () => {
1991
- aborted = true;
2057
+ const abortForCleanup = () => {
2058
+ void session?.abort();
2059
+ };
2060
+
2061
+ const abortFromCaller = () => {
2062
+ callerAborted = true;
1992
2063
  details.status = "aborted";
1993
2064
  details.endedAt = Date.now();
1994
2065
  lastContent = "Aborted";
1995
2066
  emit();
1996
- void session?.abort();
2067
+ abortForCleanup();
1997
2068
  };
1998
2069
 
1999
- if (signal?.aborted) abort();
2070
+ if (signal?.aborted) abortFromCaller();
2000
2071
  if (signal && !signal.aborted) {
2001
- signal.addEventListener("abort", abort);
2072
+ signal.addEventListener("abort", abortFromCaller);
2002
2073
  abortListenerAdded = true;
2003
2074
  }
2004
2075
 
@@ -2035,7 +2106,7 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
2035
2106
 
2036
2107
  const created = await createAgentSession({
2037
2108
  cwd,
2038
- modelRegistry: ctx.modelRegistry,
2109
+ ...getModelRuntimeOption(ctx),
2039
2110
  resourceLoader,
2040
2111
  settingsManager: isolatedSettingsManager,
2041
2112
  sessionManager: SessionManager.inMemory(cwd),
@@ -2046,6 +2117,7 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
2046
2117
 
2047
2118
  session = created.session;
2048
2119
  unsubscribe = session.subscribe((event) => {
2120
+ addSessionEventUsage(usage, event);
2049
2121
  switch (event.type) {
2050
2122
  case "turn_end":
2051
2123
  details.turns += 1;
@@ -2075,32 +2147,40 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
2075
2147
  }
2076
2148
  });
2077
2149
 
2078
- if (!aborted) {
2150
+ if (!callerAborted) {
2079
2151
  const promptPromise = session.prompt(buildUserPrompt(input, cwd), { expandPromptTemplates: false });
2080
2152
  const timeoutPromise = new Promise<never>((_resolve, reject) => {
2081
2153
  runTimeout = setTimeout(() => {
2082
- abort();
2154
+ abortForCleanup();
2083
2155
  reject(new Error(`triage_comments timed out after ${Math.round(MAX_RUN_MS / 1000)} seconds.`));
2084
2156
  }, MAX_RUN_MS);
2085
2157
  });
2086
2158
  await Promise.race([promptPromise, timeoutPromise]);
2087
2159
  }
2088
2160
 
2089
- const answer = session ? extractLastAssistantText(session.state.messages) : "";
2090
- lastContent = answer ? ensureImplementationNote(answer) : aborted ? "Aborted" : "(no output)";
2091
- details.status = aborted ? "aborted" : "done";
2161
+ const outcome = session ? inspectFinalAssistant(session.state.messages) : { ok: false as const, reason: "the isolated triage_comments session produced no assistant message" };
2162
+ if (outcome.ok) {
2163
+ lastContent = ensureImplementationNote(outcome.answer);
2164
+ details.status = "done";
2165
+ } else if (callerAborted) {
2166
+ lastContent = "Aborted";
2167
+ details.status = "aborted";
2168
+ } else {
2169
+ throw new Error(outcome.reason);
2170
+ }
2092
2171
  details.endedAt = Date.now();
2093
2172
  emit();
2094
2173
 
2095
2174
  return {
2096
2175
  content: [{ type: "text", text: lastContent }],
2097
2176
  details,
2177
+ usage,
2098
2178
  };
2099
2179
  } catch (error) {
2100
- const wasAbort = aborted || isAbortLikeError(error);
2101
- const message = wasAbort ? "Aborted" : error instanceof Error ? error.message : String(error);
2102
- details.status = wasAbort ? "aborted" : "error";
2103
- details.error = wasAbort ? undefined : message;
2180
+ const failure = classifyRunFailure(error, callerAborted);
2181
+ const { message } = failure;
2182
+ details.status = failure.status;
2183
+ details.error = failure.error;
2104
2184
  details.endedAt = Date.now();
2105
2185
  lastContent = message;
2106
2186
  emit();
@@ -2108,10 +2188,11 @@ export default function triageCommentsExtension(pi: ExtensionAPI) {
2108
2188
  return {
2109
2189
  content: [{ type: "text", text: message }],
2110
2190
  details,
2191
+ usage,
2111
2192
  };
2112
2193
  } finally {
2113
2194
  if (runTimeout) clearTimeout(runTimeout);
2114
- if (signal && abortListenerAdded) signal.removeEventListener("abort", abort);
2195
+ if (signal && abortListenerAdded) signal.removeEventListener("abort", abortFromCaller);
2115
2196
  unsubscribe?.();
2116
2197
  session?.dispose();
2117
2198
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-triage-comments",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "A pi extension that adds /triage-comments and a read-only triage_comments subagent tool for review-comment triage.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -33,5 +33,9 @@
33
33
  "@earendil-works/pi-coding-agent": "*",
34
34
  "@earendil-works/pi-tui": "*",
35
35
  "typebox": "*"
36
+ },
37
+ "type": "module",
38
+ "engines": {
39
+ "node": ">=22.19.0"
36
40
  }
37
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diegopetrucci/pi-extensions",
3
- "version": "0.1.57",
3
+ "version": "0.1.59",
4
4
  "description": "A collection of pi extensions and skills for annotation UIs, context management, workflow audits, contrarian review, review-comment triage, notifications, brrr push alerts, safety guards, GitHub research, repo-local knowledge, todos, tool rendering, model/provider helpers, and Xiaohei-style article illustrations.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -17,7 +17,8 @@
17
17
  "ci": "npm run preflight:install-state && npm run typecheck && npm test",
18
18
  "preflight:install-state": "node scripts/check-install-state.mjs",
19
19
  "test": "node --test test/*.test.mjs",
20
- "typecheck": "npx tsc --noEmit --module NodeNext --moduleResolution NodeNext --target ES2022 --skipLibCheck $(git ls-files '*.ts')"
20
+ "typecheck": "tsc -p tsconfig.json",
21
+ "prepare-release": "node scripts/prepare-release.mjs"
21
22
  },
22
23
  "files": [
23
24
  "extensions",
@@ -71,9 +72,9 @@
71
72
  ]
72
73
  },
73
74
  "devDependencies": {
74
- "@earendil-works/pi-ai": "^0.80.6",
75
- "@earendil-works/pi-coding-agent": "^0.80.6",
76
- "@earendil-works/pi-tui": "^0.80.6",
75
+ "@earendil-works/pi-ai": "^0.81.1",
76
+ "@earendil-works/pi-coding-agent": "^0.81.1",
77
+ "@earendil-works/pi-tui": "^0.81.1",
77
78
  "@types/node": "^25.9.1",
78
79
  "husky": "^9.1.7",
79
80
  "typebox": "^1.3.6",
@@ -85,6 +86,9 @@
85
86
  "monaco-editor": "0.52.2"
86
87
  },
87
88
  "overrides": {
88
- "protobufjs": "^7.6.4"
89
+ "protobufjs": "^7.6.5"
90
+ },
91
+ "engines": {
92
+ "node": ">=22.19.0"
89
93
  }
90
94
  }