@code-yeongyu/senpi 2026.8.7 → 2026.8.9

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 (128) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/dist/core/agent-session.d.ts.map +1 -1
  3. package/dist/core/agent-session.js +25 -12
  4. package/dist/core/agent-session.js.map +1 -1
  5. package/dist/core/extensions/builtin/goal/cache-warm.d.ts +2 -0
  6. package/dist/core/extensions/builtin/goal/cache-warm.d.ts.map +1 -1
  7. package/dist/core/extensions/builtin/goal/cache-warm.js.map +1 -1
  8. package/dist/core/extensions/builtin/goal/monitor-continuation-types.d.ts +1 -0
  9. package/dist/core/extensions/builtin/goal/monitor-continuation-types.d.ts.map +1 -1
  10. package/dist/core/extensions/builtin/goal/monitor-continuation-types.js.map +1 -1
  11. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
  12. package/dist/core/extensions/builtin/goal/monitor-continuation.js +76 -35
  13. package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
  14. package/dist/core/extensions/builtin/goal/prompt.d.ts +1 -1
  15. package/dist/core/extensions/builtin/goal/prompt.d.ts.map +1 -1
  16. package/dist/core/extensions/builtin/goal/prompt.js +21 -7
  17. package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
  18. package/dist/core/extensions/builtin/goal/wait-progress.d.ts +3 -1
  19. package/dist/core/extensions/builtin/goal/wait-progress.d.ts.map +1 -1
  20. package/dist/core/extensions/builtin/goal/wait-progress.js +27 -3
  21. package/dist/core/extensions/builtin/goal/wait-progress.js.map +1 -1
  22. package/dist/core/extensions/builtin/goal/wait-ticker.d.ts +4 -3
  23. package/dist/core/extensions/builtin/goal/wait-ticker.d.ts.map +1 -1
  24. package/dist/core/extensions/builtin/goal/wait-ticker.js +6 -6
  25. package/dist/core/extensions/builtin/goal/wait-ticker.js.map +1 -1
  26. package/dist/core/extensions/builtin/import-repro.d.ts.map +1 -1
  27. package/dist/core/extensions/builtin/import-repro.js +9 -0
  28. package/dist/core/extensions/builtin/import-repro.js.map +1 -1
  29. package/dist/core/extensions/builtin/model-fallback/settings.d.ts.map +1 -1
  30. package/dist/core/extensions/builtin/model-fallback/settings.js +21 -1
  31. package/dist/core/extensions/builtin/model-fallback/settings.js.map +1 -1
  32. package/dist/core/extensions/builtin/resumption-channel-event.d.ts +13 -0
  33. package/dist/core/extensions/builtin/resumption-channel-event.d.ts.map +1 -0
  34. package/dist/core/extensions/builtin/resumption-channel-event.js +13 -0
  35. package/dist/core/extensions/builtin/resumption-channel-event.js.map +1 -0
  36. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/terminal/extension.js +20 -0
  38. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  39. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +5 -1
  40. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts.map +1 -1
  41. package/dist/core/extensions/builtin/terminal/session-bundle.js +19 -2
  42. package/dist/core/extensions/builtin/terminal/session-bundle.js.map +1 -1
  43. package/dist/core/extensions/builtin/terminal/tools/bash.d.ts.map +1 -1
  44. package/dist/core/extensions/builtin/terminal/tools/bash.js +2 -0
  45. package/dist/core/extensions/builtin/terminal/tools/bash.js.map +1 -1
  46. package/dist/core/extensions/builtin/terminal/tools/context.d.ts +2 -0
  47. package/dist/core/extensions/builtin/terminal/tools/context.d.ts.map +1 -1
  48. package/dist/core/extensions/builtin/terminal/tools/context.js.map +1 -1
  49. package/dist/core/retry-fallback/chains.d.ts +13 -1
  50. package/dist/core/retry-fallback/chains.d.ts.map +1 -1
  51. package/dist/core/retry-fallback/chains.js +80 -8
  52. package/dist/core/retry-fallback/chains.js.map +1 -1
  53. package/dist/core/retry-fallback/controller.d.ts +2 -0
  54. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  55. package/dist/core/retry-fallback/controller.js.map +1 -1
  56. package/dist/core/retry-fallback/expansion.d.ts +46 -0
  57. package/dist/core/retry-fallback/expansion.d.ts.map +1 -0
  58. package/dist/core/retry-fallback/expansion.js +113 -0
  59. package/dist/core/retry-fallback/expansion.js.map +1 -0
  60. package/dist/core/retry-fallback/settings.d.ts +6 -0
  61. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  62. package/dist/core/retry-fallback/settings.js +12 -10
  63. package/dist/core/retry-fallback/settings.js.map +1 -1
  64. package/dist/core/retry-fallback/validate.d.ts.map +1 -1
  65. package/dist/core/retry-fallback/validate.js +14 -1
  66. package/dist/core/retry-fallback/validate.js.map +1 -1
  67. package/dist/main.d.ts.map +1 -1
  68. package/dist/main.js +18 -3
  69. package/dist/main.js.map +1 -1
  70. package/dist/modes/interactive/components/favorite-models-selector.d.ts +4 -0
  71. package/dist/modes/interactive/components/favorite-models-selector.d.ts.map +1 -1
  72. package/dist/modes/interactive/components/favorite-models-selector.js +23 -7
  73. package/dist/modes/interactive/components/favorite-models-selector.js.map +1 -1
  74. package/dist/modes/interactive/components/model-selector.d.ts +1 -0
  75. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  76. package/dist/modes/interactive/components/model-selector.js +11 -7
  77. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  78. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  79. package/dist/modes/interactive/interactive-mode.js +25 -6
  80. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  81. package/dist/modes/interactive/model-search-rank.d.ts +13 -0
  82. package/dist/modes/interactive/model-search-rank.d.ts.map +1 -0
  83. package/dist/modes/interactive/model-search-rank.js +200 -0
  84. package/dist/modes/interactive/model-search-rank.js.map +1 -0
  85. package/dist/modes/interactive/model-search.d.ts +0 -5
  86. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  87. package/dist/modes/interactive/model-search.js +0 -9
  88. package/dist/modes/interactive/model-search.js.map +1 -1
  89. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  90. package/dist/modes/rpc/session-command-router.js +3 -2
  91. package/dist/modes/rpc/session-command-router.js.map +1 -1
  92. package/dist/modes/rpc/session-registry.d.ts +1 -1
  93. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  94. package/dist/modes/rpc/session-registry.js +3 -3
  95. package/dist/modes/rpc/session-registry.js.map +1 -1
  96. package/docs/settings.md +1 -1
  97. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +19 -0
  98. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  99. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/resumption-channel.ts +29 -0
  100. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +10 -0
  101. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +26 -1
  102. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.d.ts.map +1 -1
  103. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js +4 -7
  104. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js.map +1 -1
  105. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  106. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  107. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  108. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  109. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  110. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  111. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  112. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
  113. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  114. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  115. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  116. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  117. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.d.ts +4 -0
  118. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.d.ts.map +1 -0
  119. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.js +8 -0
  120. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.js.map +1 -0
  121. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  122. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts +12 -0
  123. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts.map +1 -1
  124. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js +34 -2
  125. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js.map +1 -1
  126. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  127. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  128. package/package.json +6 -6
@@ -1,11 +1,13 @@
1
+ import type { ResumptionChannelCounts } from "./monitor-continuation-types.ts";
1
2
  export type GoalWaitKind = "monitor" | "userGrace";
2
3
  export interface GoalWaitLabelInput {
3
4
  readonly kind: GoalWaitKind;
4
5
  readonly remainingMs: number;
5
6
  readonly totalMs: number;
6
- readonly activeMonitorCount: number;
7
+ readonly channelCounts: ResumptionChannelCounts;
7
8
  }
8
9
  export declare const GOAL_WAIT_BAR_CELLS = 12;
9
10
  export declare function renderGoalWaitBar(elapsedRatio: number): string;
11
+ export declare function channelsOnDuty(channelCounts: ResumptionChannelCounts): string;
10
12
  export declare function formatGoalWaitLabel(input: GoalWaitLabelInput): string;
11
13
  //# sourceMappingURL=wait-progress.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wait-progress.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-progress.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACpC;AAED,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAUtC,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG9D;AAWD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAOrE"}
1
+ {"version":3,"file":"wait-progress.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-progress.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE/E,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,EAAE,uBAAuB,CAAC;CAChD;AAED,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAWtC,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG9D;AA6BD,wBAAgB,cAAc,CAAC,aAAa,EAAE,uBAAuB,GAAG,MAAM,CAK7E;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAOrE"}
@@ -2,6 +2,7 @@ import { formatWakeDuration } from "./cache-warm.js";
2
2
  export const GOAL_WAIT_BAR_CELLS = 12;
3
3
  const FILLED_CELL = "\u25b0";
4
4
  const EMPTY_CELL = "\u25b1";
5
+ const SOURCE_ORDER = ["terminal-monitor", "senpi-task", "eval-detached", "terminal-bash"];
5
6
  function clampRatio(value) {
6
7
  if (!Number.isFinite(value))
7
8
  return 0;
@@ -16,14 +17,37 @@ function elapsedRatioOf(remainingMs, totalMs) {
16
17
  return 1;
17
18
  return clampRatio((totalMs - Math.max(0, remainingMs)) / totalMs);
18
19
  }
19
- function monitorsOnDuty(count) {
20
- return count === 1 ? "1 monitor on duty" : `${count} monitors on duty`;
20
+ function sourceSortIndex(source) {
21
+ const index = SOURCE_ORDER.indexOf(source);
22
+ return index < 0 ? SOURCE_ORDER.length : index;
23
+ }
24
+ function formatSourceCount(source, count) {
25
+ switch (source) {
26
+ case "terminal-monitor":
27
+ return count === 1 ? "1 monitor" : `${count} monitors`;
28
+ case "senpi-task":
29
+ return count === 1 ? "1 task" : `${count} tasks`;
30
+ case "eval-detached":
31
+ return count === 1 ? "1 eval" : `${count} evals`;
32
+ case "terminal-bash":
33
+ return count === 1 ? "1 bash" : `${count} bash sessions`;
34
+ default: {
35
+ const label = source.replaceAll("-", " ");
36
+ return count === 1 ? `1 ${label}` : `${count} ${label} channels`;
37
+ }
38
+ }
39
+ }
40
+ export function channelsOnDuty(channelCounts) {
41
+ const liveSources = Object.entries(channelCounts)
42
+ .filter(([, count]) => count > 0)
43
+ .sort(([left], [right]) => sourceSortIndex(left) - sourceSortIndex(right) || left.localeCompare(right));
44
+ return `${liveSources.map(([source, count]) => formatSourceCount(source, count)).join(" \u00b7 ")} on duty`;
21
45
  }
22
46
  export function formatGoalWaitLabel(input) {
23
47
  const bar = renderGoalWaitBar(elapsedRatioOf(input.remainingMs, input.totalMs));
24
48
  const remaining = formatWakeDuration(Math.max(0, input.remainingMs));
25
49
  if (input.kind === "monitor") {
26
- return `${bar} goal continues in ${remaining} \u00b7 ${monitorsOnDuty(input.activeMonitorCount)}`;
50
+ return `${bar} goal continues in ${remaining} \u00b7 ${channelsOnDuty(input.channelCounts)}`;
27
51
  }
28
52
  return `${bar} goal resumes in ${remaining}`;
29
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"wait-progress.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-progress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAWrD,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAEtC,MAAM,WAAW,GAAG,QAAQ,CAAC;AAC7B,MAAM,UAAU,GAAG,QAAQ,CAAC;AAE5B,SAAS,UAAU,CAAC,KAAa;IAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,YAAoB;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,mBAAmB,CAAC,CAAC;IAC1E,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,mBAAmB,GAAG,MAAM,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,cAAc,CAAC,WAAmB,EAAE,OAAe;IAC3D,IAAI,OAAO,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IAC3B,OAAO,UAAU,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACpC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,GAAG,KAAK,mBAAmB,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAyB;IAC5D,MAAM,GAAG,GAAG,iBAAiB,CAAC,cAAc,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IACrE,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,GAAG,GAAG,sBAAsB,SAAS,WAAW,cAAc,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;IACnG,CAAC;IACD,OAAO,GAAG,GAAG,oBAAoB,SAAS,EAAE,CAAC;AAC9C,CAAC","sourcesContent":["import { formatWakeDuration } from \"./cache-warm.ts\";\n\nexport type GoalWaitKind = \"monitor\" | \"userGrace\";\n\nexport interface GoalWaitLabelInput {\n\treadonly kind: GoalWaitKind;\n\treadonly remainingMs: number;\n\treadonly totalMs: number;\n\treadonly activeMonitorCount: number;\n}\n\nexport const GOAL_WAIT_BAR_CELLS = 12;\n\nconst FILLED_CELL = \"\\u25b0\";\nconst EMPTY_CELL = \"\\u25b1\";\n\nfunction clampRatio(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\treturn Math.min(1, Math.max(0, value));\n}\n\nexport function renderGoalWaitBar(elapsedRatio: number): string {\n\tconst filled = Math.round(clampRatio(elapsedRatio) * GOAL_WAIT_BAR_CELLS);\n\treturn FILLED_CELL.repeat(filled) + EMPTY_CELL.repeat(GOAL_WAIT_BAR_CELLS - filled);\n}\n\nfunction elapsedRatioOf(remainingMs: number, totalMs: number): number {\n\tif (totalMs <= 0) return 1;\n\treturn clampRatio((totalMs - Math.max(0, remainingMs)) / totalMs);\n}\n\nfunction monitorsOnDuty(count: number): string {\n\treturn count === 1 ? \"1 monitor on duty\" : `${count} monitors on duty`;\n}\n\nexport function formatGoalWaitLabel(input: GoalWaitLabelInput): string {\n\tconst bar = renderGoalWaitBar(elapsedRatioOf(input.remainingMs, input.totalMs));\n\tconst remaining = formatWakeDuration(Math.max(0, input.remainingMs));\n\tif (input.kind === \"monitor\") {\n\t\treturn `${bar} goal continues in ${remaining} \\u00b7 ${monitorsOnDuty(input.activeMonitorCount)}`;\n\t}\n\treturn `${bar} goal resumes in ${remaining}`;\n}\n"]}
1
+ {"version":3,"file":"wait-progress.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-progress.ts"],"names":[],"mappings":"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","sourcesContent":["import { formatWakeDuration } from \"./cache-warm.ts\";\nimport type { ResumptionChannelCounts } from \"./monitor-continuation-types.ts\";\n\nexport type GoalWaitKind = \"monitor\" | \"userGrace\";\n\nexport interface GoalWaitLabelInput {\n\treadonly kind: GoalWaitKind;\n\treadonly remainingMs: number;\n\treadonly totalMs: number;\n\treadonly channelCounts: ResumptionChannelCounts;\n}\n\nexport const GOAL_WAIT_BAR_CELLS = 12;\n\nconst FILLED_CELL = \"\\u25b0\";\nconst EMPTY_CELL = \"\\u25b1\";\nconst SOURCE_ORDER = [\"terminal-monitor\", \"senpi-task\", \"eval-detached\", \"terminal-bash\"] as const;\n\nfunction clampRatio(value: number): number {\n\tif (!Number.isFinite(value)) return 0;\n\treturn Math.min(1, Math.max(0, value));\n}\n\nexport function renderGoalWaitBar(elapsedRatio: number): string {\n\tconst filled = Math.round(clampRatio(elapsedRatio) * GOAL_WAIT_BAR_CELLS);\n\treturn FILLED_CELL.repeat(filled) + EMPTY_CELL.repeat(GOAL_WAIT_BAR_CELLS - filled);\n}\n\nfunction elapsedRatioOf(remainingMs: number, totalMs: number): number {\n\tif (totalMs <= 0) return 1;\n\treturn clampRatio((totalMs - Math.max(0, remainingMs)) / totalMs);\n}\n\nfunction sourceSortIndex(source: string): number {\n\tconst index = SOURCE_ORDER.indexOf(source as (typeof SOURCE_ORDER)[number]);\n\treturn index < 0 ? SOURCE_ORDER.length : index;\n}\n\nfunction formatSourceCount(source: string, count: number): string {\n\tswitch (source) {\n\t\tcase \"terminal-monitor\":\n\t\t\treturn count === 1 ? \"1 monitor\" : `${count} monitors`;\n\t\tcase \"senpi-task\":\n\t\t\treturn count === 1 ? \"1 task\" : `${count} tasks`;\n\t\tcase \"eval-detached\":\n\t\t\treturn count === 1 ? \"1 eval\" : `${count} evals`;\n\t\tcase \"terminal-bash\":\n\t\t\treturn count === 1 ? \"1 bash\" : `${count} bash sessions`;\n\t\tdefault: {\n\t\t\tconst label = source.replaceAll(\"-\", \" \");\n\t\t\treturn count === 1 ? `1 ${label}` : `${count} ${label} channels`;\n\t\t}\n\t}\n}\n\nexport function channelsOnDuty(channelCounts: ResumptionChannelCounts): string {\n\tconst liveSources = Object.entries(channelCounts)\n\t\t.filter(([, count]) => count > 0)\n\t\t.sort(([left], [right]) => sourceSortIndex(left) - sourceSortIndex(right) || left.localeCompare(right));\n\treturn `${liveSources.map(([source, count]) => formatSourceCount(source, count)).join(\" \\u00b7 \")} on duty`;\n}\n\nexport function formatGoalWaitLabel(input: GoalWaitLabelInput): string {\n\tconst bar = renderGoalWaitBar(elapsedRatioOf(input.remainingMs, input.totalMs));\n\tconst remaining = formatWakeDuration(Math.max(0, input.remainingMs));\n\tif (input.kind === \"monitor\") {\n\t\treturn `${bar} goal continues in ${remaining} \\u00b7 ${channelsOnDuty(input.channelCounts)}`;\n\t}\n\treturn `${bar} goal resumes in ${remaining}`;\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { ExtensionContext } from "../../types.ts";
2
+ import type { ResumptionChannelCounts } from "./monitor-continuation-types.ts";
2
3
  import { type GoalWaitLabelInput } from "./wait-progress.ts";
3
4
  /** Footer countdown refresh cadence while a Goal continuation is delayed. */
4
5
  export declare const GOAL_WAIT_TICK_INTERVAL_MS = 1000;
@@ -23,14 +24,14 @@ export declare class GoalWaitTicker {
23
24
  private kind;
24
25
  private dueAtMs;
25
26
  private totalMs;
26
- private activeMonitorCount;
27
+ private channelCounts;
27
28
  private lastRenderedStatus;
28
29
  constructor(options: GoalWaitTickerOptions);
29
30
  get running(): boolean;
30
31
  /** Render the current wait immediately and keep it live until stopped. */
31
32
  sync(ctx: ExtensionContext, input: GoalWaitLabelInput): void;
32
- /** Refresh monitor wording without changing the countdown deadline. */
33
- setActiveMonitorCount(activeMonitorCount: number): void;
33
+ /** Refresh channel wording without changing the countdown deadline. */
34
+ setChannelCounts(channelCounts: ResumptionChannelCounts): void;
34
35
  /** Stop ticking, clear the footer segment, and drop the retained context. */
35
36
  stop(): void;
36
37
  private tick;
@@ -1 +1 @@
1
- {"version":3,"file":"wait-ticker.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-ticker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAA0C,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAErG,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAC/C,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAEhD,uFAAuF;AACvF,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;AAEzF,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,wDAAwD;IACxD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,GAAG,CAA+B;IAC1C,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,kBAAkB,CAAqB;IAE/C,YAAY,OAAO,EAAE,qBAAqB,EAGzC;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,0EAA0E;IAC1E,IAAI,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAY3D;IAED,uEAAuE;IACvE,qBAAqB,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAItD;IAED,6EAA6E;IAC7E,IAAI,IAAI,IAAI,CAUX;IAED,OAAO,CAAC,IAAI;CAYZ"}
1
+ {"version":3,"file":"wait-ticker.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-ticker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,EAA0C,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAErG,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,OAAO,CAAC;AAC/C,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAEhD,uFAAuF;AACvF,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;AAEzF,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,wDAAwD;IACxD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,GAAG,CAA+B;IAC1C,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAAqB;IAE/C,YAAY,OAAO,EAAE,qBAAqB,EAGzC;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,0EAA0E;IAC1E,IAAI,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAY3D;IAED,uEAAuE;IACvE,gBAAgB,CAAC,aAAa,EAAE,uBAAuB,GAAG,IAAI,CAI7D;IAED,6EAA6E;IAC7E,IAAI,IAAI,IAAI,CAUX;IAED,OAAO,CAAC,IAAI;CAYZ"}
@@ -11,7 +11,7 @@ export class GoalWaitTicker {
11
11
  constructor(options) {
12
12
  this.dueAtMs = 0;
13
13
  this.totalMs = 0;
14
- this.activeMonitorCount = 0;
14
+ this.channelCounts = {};
15
15
  this.render = options.render;
16
16
  this.now = options.now ?? Date.now;
17
17
  }
@@ -24,7 +24,7 @@ export class GoalWaitTicker {
24
24
  this.kind = input.kind;
25
25
  this.dueAtMs = this.now() + Math.max(0, input.remainingMs);
26
26
  this.totalMs = input.totalMs;
27
- this.activeMonitorCount = input.activeMonitorCount;
27
+ this.channelCounts = { ...input.channelCounts };
28
28
  this.lastRenderedStatus = undefined;
29
29
  this.tick();
30
30
  if (this.intervalId !== undefined)
@@ -33,11 +33,11 @@ export class GoalWaitTicker {
33
33
  handle.unref();
34
34
  this.intervalId = handle;
35
35
  }
36
- /** Refresh monitor wording without changing the countdown deadline. */
37
- setActiveMonitorCount(activeMonitorCount) {
36
+ /** Refresh channel wording without changing the countdown deadline. */
37
+ setChannelCounts(channelCounts) {
38
38
  if (this.ctx === undefined || this.kind !== "monitor")
39
39
  return;
40
- this.activeMonitorCount = activeMonitorCount;
40
+ this.channelCounts = { ...channelCounts };
41
41
  this.tick();
42
42
  }
43
43
  /** Stop ticking, clear the footer segment, and drop the retained context. */
@@ -60,7 +60,7 @@ export class GoalWaitTicker {
60
60
  kind: this.kind,
61
61
  remainingMs: Math.max(0, this.dueAtMs - this.now()),
62
62
  totalMs: this.totalMs,
63
- activeMonitorCount: this.activeMonitorCount,
63
+ channelCounts: this.channelCounts,
64
64
  });
65
65
  if (status === this.lastRenderedStatus)
66
66
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"wait-ticker.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-ticker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionContext } from \"../../types.ts\";\nimport { formatGoalWaitLabel, type GoalWaitKind, type GoalWaitLabelInput } from \"./wait-progress.ts\";\n\n/** Footer countdown refresh cadence while a Goal continuation is delayed. */\nexport const GOAL_WAIT_TICK_INTERVAL_MS = 1000;\nexport const GOAL_WAIT_STATUS_KEY = \"goal-wait\";\n\n/** Receives the freshly formatted footer status text (undefined clears the status). */\nexport type GoalWaitRender = (ctx: ExtensionContext, status: string | undefined) => void;\n\nexport interface GoalWaitTickerOptions {\n\treadonly render: GoalWaitRender;\n\t/** Injectable clock for tests; defaults to Date.now. */\n\treadonly now?: () => number;\n}\n\n/**\n * Drives a once-per-second footer countdown while a Goal continuation timer is\n * armed. Mirrors the existing GoalElapsedTicker and MonitorStatusTicker: the\n * interval is unref'd and unchanged visible labels are not rendered again.\n */\nexport class GoalWaitTicker {\n\tprivate readonly render: GoalWaitRender;\n\tprivate readonly now: () => number;\n\tprivate intervalId: NodeJS.Timeout | undefined;\n\tprivate ctx: ExtensionContext | undefined;\n\tprivate kind: GoalWaitKind | undefined;\n\tprivate dueAtMs = 0;\n\tprivate totalMs = 0;\n\tprivate activeMonitorCount = 0;\n\tprivate lastRenderedStatus: string | undefined;\n\n\tconstructor(options: GoalWaitTickerOptions) {\n\t\tthis.render = options.render;\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\tget running(): boolean {\n\t\treturn this.intervalId !== undefined;\n\t}\n\n\t/** Render the current wait immediately and keep it live until stopped. */\n\tsync(ctx: ExtensionContext, input: GoalWaitLabelInput): void {\n\t\tthis.ctx = ctx;\n\t\tthis.kind = input.kind;\n\t\tthis.dueAtMs = this.now() + Math.max(0, input.remainingMs);\n\t\tthis.totalMs = input.totalMs;\n\t\tthis.activeMonitorCount = input.activeMonitorCount;\n\t\tthis.lastRenderedStatus = undefined;\n\t\tthis.tick();\n\t\tif (this.intervalId !== undefined) return;\n\t\tconst handle = setInterval(() => this.tick(), GOAL_WAIT_TICK_INTERVAL_MS);\n\t\thandle.unref();\n\t\tthis.intervalId = handle;\n\t}\n\n\t/** Refresh monitor wording without changing the countdown deadline. */\n\tsetActiveMonitorCount(activeMonitorCount: number): void {\n\t\tif (this.ctx === undefined || this.kind !== \"monitor\") return;\n\t\tthis.activeMonitorCount = activeMonitorCount;\n\t\tthis.tick();\n\t}\n\n\t/** Stop ticking, clear the footer segment, and drop the retained context. */\n\tstop(): void {\n\t\tif (this.intervalId !== undefined) {\n\t\t\tclearInterval(this.intervalId);\n\t\t\tthis.intervalId = undefined;\n\t\t}\n\t\tconst ctx = this.ctx;\n\t\tthis.ctx = undefined;\n\t\tthis.kind = undefined;\n\t\tthis.lastRenderedStatus = undefined;\n\t\tif (ctx !== undefined) this.render(ctx, undefined);\n\t}\n\n\tprivate tick(): void {\n\t\tif (this.ctx === undefined || this.kind === undefined) return;\n\t\tconst status = formatGoalWaitLabel({\n\t\t\tkind: this.kind,\n\t\t\tremainingMs: Math.max(0, this.dueAtMs - this.now()),\n\t\t\ttotalMs: this.totalMs,\n\t\t\tactiveMonitorCount: this.activeMonitorCount,\n\t\t});\n\t\tif (status === this.lastRenderedStatus) return;\n\t\tthis.lastRenderedStatus = status;\n\t\tthis.render(this.ctx, status);\n\t}\n}\n"]}
1
+ {"version":3,"file":"wait-ticker.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/goal/wait-ticker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionContext } from \"../../types.ts\";\nimport type { ResumptionChannelCounts } from \"./monitor-continuation-types.ts\";\nimport { formatGoalWaitLabel, type GoalWaitKind, type GoalWaitLabelInput } from \"./wait-progress.ts\";\n\n/** Footer countdown refresh cadence while a Goal continuation is delayed. */\nexport const GOAL_WAIT_TICK_INTERVAL_MS = 1000;\nexport const GOAL_WAIT_STATUS_KEY = \"goal-wait\";\n\n/** Receives the freshly formatted footer status text (undefined clears the status). */\nexport type GoalWaitRender = (ctx: ExtensionContext, status: string | undefined) => void;\n\nexport interface GoalWaitTickerOptions {\n\treadonly render: GoalWaitRender;\n\t/** Injectable clock for tests; defaults to Date.now. */\n\treadonly now?: () => number;\n}\n\n/**\n * Drives a once-per-second footer countdown while a Goal continuation timer is\n * armed. Mirrors the existing GoalElapsedTicker and MonitorStatusTicker: the\n * interval is unref'd and unchanged visible labels are not rendered again.\n */\nexport class GoalWaitTicker {\n\tprivate readonly render: GoalWaitRender;\n\tprivate readonly now: () => number;\n\tprivate intervalId: NodeJS.Timeout | undefined;\n\tprivate ctx: ExtensionContext | undefined;\n\tprivate kind: GoalWaitKind | undefined;\n\tprivate dueAtMs = 0;\n\tprivate totalMs = 0;\n\tprivate channelCounts: ResumptionChannelCounts = {};\n\tprivate lastRenderedStatus: string | undefined;\n\n\tconstructor(options: GoalWaitTickerOptions) {\n\t\tthis.render = options.render;\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\tget running(): boolean {\n\t\treturn this.intervalId !== undefined;\n\t}\n\n\t/** Render the current wait immediately and keep it live until stopped. */\n\tsync(ctx: ExtensionContext, input: GoalWaitLabelInput): void {\n\t\tthis.ctx = ctx;\n\t\tthis.kind = input.kind;\n\t\tthis.dueAtMs = this.now() + Math.max(0, input.remainingMs);\n\t\tthis.totalMs = input.totalMs;\n\t\tthis.channelCounts = { ...input.channelCounts };\n\t\tthis.lastRenderedStatus = undefined;\n\t\tthis.tick();\n\t\tif (this.intervalId !== undefined) return;\n\t\tconst handle = setInterval(() => this.tick(), GOAL_WAIT_TICK_INTERVAL_MS);\n\t\thandle.unref();\n\t\tthis.intervalId = handle;\n\t}\n\n\t/** Refresh channel wording without changing the countdown deadline. */\n\tsetChannelCounts(channelCounts: ResumptionChannelCounts): void {\n\t\tif (this.ctx === undefined || this.kind !== \"monitor\") return;\n\t\tthis.channelCounts = { ...channelCounts };\n\t\tthis.tick();\n\t}\n\n\t/** Stop ticking, clear the footer segment, and drop the retained context. */\n\tstop(): void {\n\t\tif (this.intervalId !== undefined) {\n\t\t\tclearInterval(this.intervalId);\n\t\t\tthis.intervalId = undefined;\n\t\t}\n\t\tconst ctx = this.ctx;\n\t\tthis.ctx = undefined;\n\t\tthis.kind = undefined;\n\t\tthis.lastRenderedStatus = undefined;\n\t\tif (ctx !== undefined) this.render(ctx, undefined);\n\t}\n\n\tprivate tick(): void {\n\t\tif (this.ctx === undefined || this.kind === undefined) return;\n\t\tconst status = formatGoalWaitLabel({\n\t\t\tkind: this.kind,\n\t\t\tremainingMs: Math.max(0, this.dueAtMs - this.now()),\n\t\t\ttotalMs: this.totalMs,\n\t\t\tchannelCounts: this.channelCounts,\n\t\t});\n\t\tif (status === this.lastRenderedStatus) return;\n\t\tthis.lastRenderedStatus = status;\n\t\tthis.render(this.ctx, status);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"import-repro.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/import-repro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,aAAa,CAAC;AAgRzE,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,QAoExC"}
1
+ {"version":3,"file":"import-repro.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/import-repro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,aAAa,CAAC;AAgRzE,MAAM,CAAC,OAAO,WAAW,EAAE,EAAE,YAAY,QA6ExC"}
@@ -231,6 +231,15 @@ export default function (pi) {
231
231
  pi.registerCommand("ir", {
232
232
  description: "Import a CI issue-analysis session from a gist ID, share URL, or issue URL and switch to it",
233
233
  handler: async (args, ctx) => {
234
+ // Session replacement aborts and disposes the live session; never start
235
+ // that while a run or compaction is active. Commands dispatch immediately
236
+ // now (see extensions/builtin/changes.md), so this handler can be entered
237
+ // mid-turn. isCompacting is checked separately because isIdle() is true
238
+ // during compaction without streaming.
239
+ if (!ctx.isIdle() || ctx.isCompacting?.() === true) {
240
+ ctx.ui.notify("/ir is unavailable while the agent is working", "warning");
241
+ return;
242
+ }
234
243
  const ref = args.trim();
235
244
  if (!ref) {
236
245
  ctx.ui.notify("Usage: /ir <gist-id | gist-url | pi.dev/session URL | issue URL>", "error");
@@ -1 +1 @@
1
- {"version":3,"file":"import-repro.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/import-repro.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Import a pi session shared as a gist by the issue-analysis CI workflow\n * (.github/workflows/issue-analysis.yml) and switch to it.\n *\n * The CI job runs in a high-entropy checkout directory; this command rewrites\n * the recorded cwd to the local checkout, installs the session file into the\n * current session directory, and switches to it.\n *\n * Usage:\n * /ir b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://gist.github.com/mitsuhiko/b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://pi.dev/session/#b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://github.com/earendil-works/pi/issues/123\n *\n * pi \"/ir <gist-id>\"\n */\n\nimport { Buffer } from \"node:buffer\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, isAbsolute, join, resolve } from \"node:path\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"../types.ts\";\n\nconst GIST_ID_RE = /^[0-9a-fA-F]{20,}$/;\nconst GIST_URL_RE = /^https:\\/\\/gist\\.github\\.com\\/(?:[^/]+\\/)?([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst SHARE_URL_RE = /^https:\\/\\/pi\\.dev\\/session\\/#([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst ISSUE_URL_RE = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/issues\\/(\\d+)(?:[/#?].*)?$/;\nconst GIST_URL_IN_TEXT_RE = /https:\\/\\/gist\\.github\\.com\\/(?:[^/\\s]+\\/)?([0-9a-fA-F]{20,})\\b/g;\nconst SESSION_DATA_RE = /<script id=\"session-data\" type=\"application\\/json\">([^<]+)<\\/script>/;\n\ninterface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\tcwd: string;\n\t[key: string]: unknown;\n}\n\ninterface ExportedSessionData {\n\theader: SessionHeader | null;\n\tentries: Array<Record<string, unknown>>;\n}\n\ninterface GistFile {\n\tfilename?: string;\n\traw_url?: string;\n\tcontent?: string;\n\ttruncated?: boolean;\n}\n\ninterface GistResponse {\n\tfiles?: Record<string, GistFile>;\n}\n\ninterface IssueComment {\n\tbody?: string | null;\n\tuser?: { login?: string } | null;\n}\n\nfunction parseRef(\n\tref: string,\n\tcwd: string,\n):\n\t| { type: \"gist\"; id: string }\n\t| { type: \"file\"; path: string }\n\t| { type: \"issue\"; owner: string; repo: string; issue: string } {\n\tif (ref.endsWith(\".html\") || ref.endsWith(\".jsonl\")) {\n\t\treturn { type: \"file\", path: isAbsolute(ref) ? ref : resolve(cwd, ref) };\n\t}\n\n\tconst shareMatch = ref.match(SHARE_URL_RE);\n\tif (shareMatch) return { type: \"gist\", id: shareMatch[1] };\n\n\tconst gistMatch = ref.match(GIST_URL_RE);\n\tif (gistMatch) return { type: \"gist\", id: gistMatch[1] };\n\n\tconst issueMatch = ref.match(ISSUE_URL_RE);\n\tif (issueMatch) return { type: \"issue\", owner: issueMatch[1], repo: issueMatch[2], issue: issueMatch[3] };\n\n\tif (GIST_ID_RE.test(ref)) return { type: \"gist\", id: ref };\n\n\tthrow new Error(`expected a gist ID, gist URL, pi.dev share URL, issue URL, .html file, or .jsonl file: ${ref}`);\n}\n\nfunction parseSessionJsonl(raw: string): { header: SessionHeader; jsonl: string } {\n\tconst newlineIndex = raw.indexOf(\"\\n\");\n\tconst firstLine = newlineIndex === -1 ? raw : raw.slice(0, newlineIndex);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(firstLine);\n\t} catch {\n\t\tthrow new Error(\"first line of session file is not valid JSON\");\n\t}\n\tconst header = parsed as Partial<SessionHeader>;\n\tif (\n\t\theader.type !== \"session\" ||\n\t\ttypeof header.id !== \"string\" ||\n\t\ttypeof header.cwd !== \"string\" ||\n\t\theader.cwd === \"\"\n\t) {\n\t\tthrow new Error(\"session file has no valid session header with a cwd\");\n\t}\n\treturn { header: header as SessionHeader, jsonl: raw };\n}\n\nfunction decodeExportedHtml(html: string): { header: SessionHeader; jsonl: string } {\n\tconst match = html.match(SESSION_DATA_RE);\n\tif (!match) throw new Error(\"HTML does not contain embedded pi session data\");\n\n\tlet data: unknown;\n\ttry {\n\t\tdata = JSON.parse(Buffer.from(match[1], \"base64\").toString(\"utf8\"));\n\t} catch {\n\t\tthrow new Error(\"embedded pi session data is not valid JSON\");\n\t}\n\n\tconst sessionData = data as Partial<ExportedSessionData>;\n\tconst header = sessionData.header;\n\tif (header?.type !== \"session\" || typeof header.id !== \"string\" || typeof header.cwd !== \"string\") {\n\t\tthrow new Error(\"embedded pi session data has no valid session header\");\n\t}\n\tif (!Array.isArray(sessionData.entries)) {\n\t\tthrow new Error(\"embedded pi session data has no entries array\");\n\t}\n\n\tconst lines = [header, ...sessionData.entries].map((entry) => JSON.stringify(entry));\n\treturn { header, jsonl: `${lines.join(\"\\n\")}\\n` };\n}\n\ntype SessionPlatform = \"windows\" | \"unix\" | \"unknown\";\n\nfunction escapeJsonString(value: string): string {\n\treturn JSON.stringify(value).slice(1, -1);\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction trimTrailingPathSeparators(value: string): string {\n\treturn value.replace(/[\\\\/]+$/, \"\");\n}\n\nfunction getPathTailName(value: string): string {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\treturn trimmed.split(/[\\\\/]/).filter(Boolean).at(-1) ?? \"\";\n}\n\nfunction getWindowsDrivePathParts(value: string): { drive: string; rest: string } | undefined {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\tconst driveMatch = trimmed.match(/^([A-Za-z]):[\\\\/](.*)$/);\n\tif (driveMatch) {\n\t\treturn { drive: driveMatch[1].toUpperCase(), rest: driveMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\tconst msysMatch = trimmed.match(/^\\/([A-Za-z])\\/(.*)$/);\n\tif (msysMatch) {\n\t\treturn { drive: msysMatch[1].toUpperCase(), rest: msysMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\treturn undefined;\n}\n\nfunction getCwdRewriteVariants(sourceCwd: string): string[] {\n\tconst trimmed = trimTrailingPathSeparators(sourceCwd);\n\tconst variants = new Set<string>();\n\tif (trimmed) variants.add(trimmed);\n\n\tconst driveParts = getWindowsDrivePathParts(trimmed);\n\tif (driveParts) {\n\t\tconst rest = driveParts.rest.replace(/^\\/+|\\/+$/g, \"\");\n\t\tconst backslashRest = rest.replace(/\\//g, \"\\\\\");\n\t\tvariants.add(`${driveParts.drive}:\\\\${backslashRest}`);\n\t\tvariants.add(`${driveParts.drive}:/${rest}`);\n\t\tvariants.add(`/${driveParts.drive.toLowerCase()}/${rest}`);\n\t\tvariants.add(`/${driveParts.drive}/${rest}`);\n\t}\n\n\treturn Array.from(variants)\n\t\t.filter(Boolean)\n\t\t.sort((a, b) => b.length - a.length);\n}\n\nfunction getCiWorkdirName(sourceCwd: string): string | undefined {\n\tconst name = getPathTailName(sourceCwd);\n\treturn /^pi-ci-[0-9a-f]{32}$/i.test(name) ? name : undefined;\n}\n\nfunction detectSessionPlatform(cwd: string): SessionPlatform {\n\tif (/^[A-Za-z]:[\\\\/]/.test(cwd) || /^\\/[A-Za-z]\\//.test(cwd)) return \"windows\";\n\tif (cwd.startsWith(\"/\")) return \"unix\";\n\treturn \"unknown\";\n}\n\nfunction getLocalPlatform(): Exclude<SessionPlatform, \"unknown\"> {\n\treturn process.platform === \"win32\" ? \"windows\" : \"unix\";\n}\n\nfunction getPlatformContinuationNotice(sourceCwd: string): string | undefined {\n\tconst sourcePlatform = detectSessionPlatform(sourceCwd);\n\tconst localPlatform = getLocalPlatform();\n\tif (sourcePlatform === \"unknown\" || sourcePlatform === localPlatform) return undefined;\n\tif (localPlatform === \"unix\") {\n\t\treturn \"This session was continued on a non-Windows machine; paths are now Unix style.\";\n\t}\n\treturn \"This session was continued on a Windows machine; paths are now Windows style.\";\n}\n\n/** Rewrite occurrences of the recorded CI cwd (JSON-escaped) to the target cwd. */\nfunction rewriteSessionCwd(raw: string, sourceCwd: string, targetCwd: string): string {\n\tconst target = escapeJsonString(targetCwd);\n\tlet rewritten = raw;\n\n\tfor (const sourceVariant of getCwdRewriteVariants(sourceCwd)) {\n\t\tif (sourceVariant === targetCwd) continue;\n\t\trewritten = rewritten.split(escapeJsonString(sourceVariant)).join(target);\n\t}\n\n\tconst ciWorkdirName = getCiWorkdirName(sourceCwd);\n\tif (ciWorkdirName) {\n\t\tconst escapedName = escapeRegExp(ciWorkdirName);\n\t\tconst windowsPathPatterns = [\n\t\t\tnew RegExp(`[A-Za-z]:(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t\tnew RegExp(`/[A-Za-z]/(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t];\n\t\tfor (const pattern of windowsPathPatterns) {\n\t\t\trewritten = rewritten.replace(pattern, target);\n\t\t}\n\t}\n\n\treturn rewritten;\n}\n\nasync function fetchText(url: string): Promise<string> {\n\tconst response = await fetch(url, { headers: { Accept: \"application/vnd.github+json\" } });\n\tif (!response.ok) {\n\t\tthrow new Error(`failed to fetch ${url}: HTTP ${response.status}`);\n\t}\n\treturn await response.text();\n}\n\nasync function readGistFile(file: GistFile): Promise<string> {\n\tif (file.content && !file.truncated) return file.content;\n\tif (!file.raw_url) throw new Error(`gist file ${file.filename ?? \"<unknown>\"} has no raw URL`);\n\treturn await fetchText(file.raw_url);\n}\n\nasync function findIssueGistId(owner: string, repo: string, issue: string): Promise<string> {\n\tconst gistIds: string[] = [];\n\tlet page = 1;\n\twhile (true) {\n\t\tconst response = await fetch(\n\t\t\t`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${encodeURIComponent(issue)}/comments?per_page=100&page=${page}`,\n\t\t\t{ headers: { Accept: \"application/vnd.github+json\", \"X-GitHub-Api-Version\": \"2022-11-28\" } },\n\t\t);\n\t\tif (!response.ok) throw new Error(`failed to fetch issue comments: HTTP ${response.status}`);\n\n\t\tconst comments = (await response.json()) as IssueComment[];\n\t\tfor (const comment of comments) {\n\t\t\tif (comment.user?.login !== \"github-actions[bot]\") continue;\n\t\t\tfor (const match of (comment.body ?? \"\").matchAll(GIST_URL_IN_TEXT_RE)) {\n\t\t\t\tgistIds.push(match[1]);\n\t\t\t}\n\t\t}\n\n\t\tif (comments.length < 100) break;\n\t\tpage++;\n\t}\n\n\tconst gistId = gistIds.at(-1);\n\tif (!gistId) throw new Error(`no github-actions gist link found in comments on ${owner}/${repo}#${issue}`);\n\treturn gistId;\n}\n\nasync function fetchGistSession(gistId: string): Promise<{ header: SessionHeader; jsonl: string }> {\n\tconst response = await fetch(`https://api.github.com/gists/${gistId}`, {\n\t\theaders: {\n\t\t\tAccept: \"application/vnd.github+json\",\n\t\t\t\"X-GitHub-Api-Version\": \"2022-11-28\",\n\t\t},\n\t});\n\tif (!response.ok) throw new Error(`failed to fetch gist ${gistId}: HTTP ${response.status}`);\n\n\tconst gist = (await response.json()) as GistResponse;\n\tconst files = Object.values(gist.files ?? {});\n\tconst jsonlFile = files.find((file) => file.filename?.endsWith(\".jsonl\"));\n\tif (jsonlFile) return parseSessionJsonl(await readGistFile(jsonlFile));\n\n\tconst htmlFile = files.find((file) => file.filename?.endsWith(\".html\"));\n\tif (htmlFile) return decodeExportedHtml(await readGistFile(htmlFile));\n\n\tthrow new Error(`gist ${gistId} has no .jsonl or .html session file`);\n}\n\nexport default function (pi: ExtensionAPI) {\n\tpi.registerCommand(\"ir\", {\n\t\tdescription: \"Import a CI issue-analysis session from a gist ID, share URL, or issue URL and switch to it\",\n\t\thandler: async (args: string, ctx: ExtensionCommandContext) => {\n\t\t\tconst ref = args.trim();\n\t\t\tif (!ref) {\n\t\t\t\tctx.ui.notify(\"Usage: /ir <gist-id | gist-url | pi.dev/session URL | issue URL>\", \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst targetCwd = ctx.sessionManager.getCwd();\n\t\t\t\tconst sessionDir = ctx.sessionManager.getSessionDir();\n\t\t\t\tconst parsedRef = parseRef(ref, targetCwd);\n\n\t\t\t\tctx.ui.notify(`Importing repro session from ${ref}...`, \"info\");\n\n\t\t\t\tlet sourceName: string;\n\t\t\t\tlet decoded: { header: SessionHeader; jsonl: string };\n\t\t\t\tif (parsedRef.type === \"gist\") {\n\t\t\t\t\tdecoded = await fetchGistSession(parsedRef.id);\n\t\t\t\t\tsourceName = `${parsedRef.id}.jsonl`;\n\t\t\t\t} else if (parsedRef.type === \"issue\") {\n\t\t\t\t\tconst gistId = await findIssueGistId(parsedRef.owner, parsedRef.repo, parsedRef.issue);\n\t\t\t\t\tdecoded = await fetchGistSession(gistId);\n\t\t\t\t\tsourceName = `${gistId}.jsonl`;\n\t\t\t\t} else {\n\t\t\t\t\tif (!existsSync(parsedRef.path)) throw new Error(`session file not found: ${parsedRef.path}`);\n\t\t\t\t\tconst raw = readFileSync(parsedRef.path, \"utf8\");\n\t\t\t\t\tdecoded = parsedRef.path.endsWith(\".html\") ? decodeExportedHtml(raw) : parseSessionJsonl(raw);\n\t\t\t\t\tsourceName = basename(parsedRef.path).replace(/\\.html$/, \".jsonl\");\n\t\t\t\t}\n\n\t\t\t\tconst platformNotice = getPlatformContinuationNotice(decoded.header.cwd);\n\t\t\t\tconst rewritten = rewriteSessionCwd(decoded.jsonl, decoded.header.cwd, targetCwd);\n\t\t\t\tconst destination = join(sessionDir, sourceName);\n\t\t\t\tif (existsSync(destination)) {\n\t\t\t\t\tconst overwrite = await ctx.ui.confirm(\n\t\t\t\t\t\t\"Session already imported\",\n\t\t\t\t\t\t`Overwrite ${destination}? Local changes to that session will be lost.`,\n\t\t\t\t\t);\n\t\t\t\t\tif (!overwrite) {\n\t\t\t\t\t\tctx.ui.notify(\"Import cancelled\", \"warning\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twriteFileSync(destination, rewritten);\n\n\t\t\t\tctx.ui.notify(`Imported session ${decoded.header.id} (cwd ${decoded.header.cwd} -> ${targetCwd})`, \"info\");\n\t\t\t\tawait ctx.switchSession(destination, {\n\t\t\t\t\twithSession: async (nextCtx) => {\n\t\t\t\t\t\tif (!platformNotice) return;\n\t\t\t\t\t\tawait nextCtx.sendMessage(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcustomType: \"import-repro\",\n\t\t\t\t\t\t\t\tcontent: platformNotice,\n\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\tdetails: { sourceCwd: decoded.header.cwd, targetCwd },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ triggerTurn: false },\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tctx.ui.notify(`ir: ${error instanceof Error ? error.message : String(error)}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"import-repro.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/import-repro.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Import a pi session shared as a gist by the issue-analysis CI workflow\n * (.github/workflows/issue-analysis.yml) and switch to it.\n *\n * The CI job runs in a high-entropy checkout directory; this command rewrites\n * the recorded cwd to the local checkout, installs the session file into the\n * current session directory, and switches to it.\n *\n * Usage:\n * /ir b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://gist.github.com/mitsuhiko/b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://pi.dev/session/#b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://github.com/earendil-works/pi/issues/123\n *\n * pi \"/ir <gist-id>\"\n */\n\nimport { Buffer } from \"node:buffer\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, isAbsolute, join, resolve } from \"node:path\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"../types.ts\";\n\nconst GIST_ID_RE = /^[0-9a-fA-F]{20,}$/;\nconst GIST_URL_RE = /^https:\\/\\/gist\\.github\\.com\\/(?:[^/]+\\/)?([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst SHARE_URL_RE = /^https:\\/\\/pi\\.dev\\/session\\/#([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst ISSUE_URL_RE = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/issues\\/(\\d+)(?:[/#?].*)?$/;\nconst GIST_URL_IN_TEXT_RE = /https:\\/\\/gist\\.github\\.com\\/(?:[^/\\s]+\\/)?([0-9a-fA-F]{20,})\\b/g;\nconst SESSION_DATA_RE = /<script id=\"session-data\" type=\"application\\/json\">([^<]+)<\\/script>/;\n\ninterface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\tcwd: string;\n\t[key: string]: unknown;\n}\n\ninterface ExportedSessionData {\n\theader: SessionHeader | null;\n\tentries: Array<Record<string, unknown>>;\n}\n\ninterface GistFile {\n\tfilename?: string;\n\traw_url?: string;\n\tcontent?: string;\n\ttruncated?: boolean;\n}\n\ninterface GistResponse {\n\tfiles?: Record<string, GistFile>;\n}\n\ninterface IssueComment {\n\tbody?: string | null;\n\tuser?: { login?: string } | null;\n}\n\nfunction parseRef(\n\tref: string,\n\tcwd: string,\n):\n\t| { type: \"gist\"; id: string }\n\t| { type: \"file\"; path: string }\n\t| { type: \"issue\"; owner: string; repo: string; issue: string } {\n\tif (ref.endsWith(\".html\") || ref.endsWith(\".jsonl\")) {\n\t\treturn { type: \"file\", path: isAbsolute(ref) ? ref : resolve(cwd, ref) };\n\t}\n\n\tconst shareMatch = ref.match(SHARE_URL_RE);\n\tif (shareMatch) return { type: \"gist\", id: shareMatch[1] };\n\n\tconst gistMatch = ref.match(GIST_URL_RE);\n\tif (gistMatch) return { type: \"gist\", id: gistMatch[1] };\n\n\tconst issueMatch = ref.match(ISSUE_URL_RE);\n\tif (issueMatch) return { type: \"issue\", owner: issueMatch[1], repo: issueMatch[2], issue: issueMatch[3] };\n\n\tif (GIST_ID_RE.test(ref)) return { type: \"gist\", id: ref };\n\n\tthrow new Error(`expected a gist ID, gist URL, pi.dev share URL, issue URL, .html file, or .jsonl file: ${ref}`);\n}\n\nfunction parseSessionJsonl(raw: string): { header: SessionHeader; jsonl: string } {\n\tconst newlineIndex = raw.indexOf(\"\\n\");\n\tconst firstLine = newlineIndex === -1 ? raw : raw.slice(0, newlineIndex);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(firstLine);\n\t} catch {\n\t\tthrow new Error(\"first line of session file is not valid JSON\");\n\t}\n\tconst header = parsed as Partial<SessionHeader>;\n\tif (\n\t\theader.type !== \"session\" ||\n\t\ttypeof header.id !== \"string\" ||\n\t\ttypeof header.cwd !== \"string\" ||\n\t\theader.cwd === \"\"\n\t) {\n\t\tthrow new Error(\"session file has no valid session header with a cwd\");\n\t}\n\treturn { header: header as SessionHeader, jsonl: raw };\n}\n\nfunction decodeExportedHtml(html: string): { header: SessionHeader; jsonl: string } {\n\tconst match = html.match(SESSION_DATA_RE);\n\tif (!match) throw new Error(\"HTML does not contain embedded pi session data\");\n\n\tlet data: unknown;\n\ttry {\n\t\tdata = JSON.parse(Buffer.from(match[1], \"base64\").toString(\"utf8\"));\n\t} catch {\n\t\tthrow new Error(\"embedded pi session data is not valid JSON\");\n\t}\n\n\tconst sessionData = data as Partial<ExportedSessionData>;\n\tconst header = sessionData.header;\n\tif (header?.type !== \"session\" || typeof header.id !== \"string\" || typeof header.cwd !== \"string\") {\n\t\tthrow new Error(\"embedded pi session data has no valid session header\");\n\t}\n\tif (!Array.isArray(sessionData.entries)) {\n\t\tthrow new Error(\"embedded pi session data has no entries array\");\n\t}\n\n\tconst lines = [header, ...sessionData.entries].map((entry) => JSON.stringify(entry));\n\treturn { header, jsonl: `${lines.join(\"\\n\")}\\n` };\n}\n\ntype SessionPlatform = \"windows\" | \"unix\" | \"unknown\";\n\nfunction escapeJsonString(value: string): string {\n\treturn JSON.stringify(value).slice(1, -1);\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction trimTrailingPathSeparators(value: string): string {\n\treturn value.replace(/[\\\\/]+$/, \"\");\n}\n\nfunction getPathTailName(value: string): string {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\treturn trimmed.split(/[\\\\/]/).filter(Boolean).at(-1) ?? \"\";\n}\n\nfunction getWindowsDrivePathParts(value: string): { drive: string; rest: string } | undefined {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\tconst driveMatch = trimmed.match(/^([A-Za-z]):[\\\\/](.*)$/);\n\tif (driveMatch) {\n\t\treturn { drive: driveMatch[1].toUpperCase(), rest: driveMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\tconst msysMatch = trimmed.match(/^\\/([A-Za-z])\\/(.*)$/);\n\tif (msysMatch) {\n\t\treturn { drive: msysMatch[1].toUpperCase(), rest: msysMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\treturn undefined;\n}\n\nfunction getCwdRewriteVariants(sourceCwd: string): string[] {\n\tconst trimmed = trimTrailingPathSeparators(sourceCwd);\n\tconst variants = new Set<string>();\n\tif (trimmed) variants.add(trimmed);\n\n\tconst driveParts = getWindowsDrivePathParts(trimmed);\n\tif (driveParts) {\n\t\tconst rest = driveParts.rest.replace(/^\\/+|\\/+$/g, \"\");\n\t\tconst backslashRest = rest.replace(/\\//g, \"\\\\\");\n\t\tvariants.add(`${driveParts.drive}:\\\\${backslashRest}`);\n\t\tvariants.add(`${driveParts.drive}:/${rest}`);\n\t\tvariants.add(`/${driveParts.drive.toLowerCase()}/${rest}`);\n\t\tvariants.add(`/${driveParts.drive}/${rest}`);\n\t}\n\n\treturn Array.from(variants)\n\t\t.filter(Boolean)\n\t\t.sort((a, b) => b.length - a.length);\n}\n\nfunction getCiWorkdirName(sourceCwd: string): string | undefined {\n\tconst name = getPathTailName(sourceCwd);\n\treturn /^pi-ci-[0-9a-f]{32}$/i.test(name) ? name : undefined;\n}\n\nfunction detectSessionPlatform(cwd: string): SessionPlatform {\n\tif (/^[A-Za-z]:[\\\\/]/.test(cwd) || /^\\/[A-Za-z]\\//.test(cwd)) return \"windows\";\n\tif (cwd.startsWith(\"/\")) return \"unix\";\n\treturn \"unknown\";\n}\n\nfunction getLocalPlatform(): Exclude<SessionPlatform, \"unknown\"> {\n\treturn process.platform === \"win32\" ? \"windows\" : \"unix\";\n}\n\nfunction getPlatformContinuationNotice(sourceCwd: string): string | undefined {\n\tconst sourcePlatform = detectSessionPlatform(sourceCwd);\n\tconst localPlatform = getLocalPlatform();\n\tif (sourcePlatform === \"unknown\" || sourcePlatform === localPlatform) return undefined;\n\tif (localPlatform === \"unix\") {\n\t\treturn \"This session was continued on a non-Windows machine; paths are now Unix style.\";\n\t}\n\treturn \"This session was continued on a Windows machine; paths are now Windows style.\";\n}\n\n/** Rewrite occurrences of the recorded CI cwd (JSON-escaped) to the target cwd. */\nfunction rewriteSessionCwd(raw: string, sourceCwd: string, targetCwd: string): string {\n\tconst target = escapeJsonString(targetCwd);\n\tlet rewritten = raw;\n\n\tfor (const sourceVariant of getCwdRewriteVariants(sourceCwd)) {\n\t\tif (sourceVariant === targetCwd) continue;\n\t\trewritten = rewritten.split(escapeJsonString(sourceVariant)).join(target);\n\t}\n\n\tconst ciWorkdirName = getCiWorkdirName(sourceCwd);\n\tif (ciWorkdirName) {\n\t\tconst escapedName = escapeRegExp(ciWorkdirName);\n\t\tconst windowsPathPatterns = [\n\t\t\tnew RegExp(`[A-Za-z]:(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t\tnew RegExp(`/[A-Za-z]/(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t];\n\t\tfor (const pattern of windowsPathPatterns) {\n\t\t\trewritten = rewritten.replace(pattern, target);\n\t\t}\n\t}\n\n\treturn rewritten;\n}\n\nasync function fetchText(url: string): Promise<string> {\n\tconst response = await fetch(url, { headers: { Accept: \"application/vnd.github+json\" } });\n\tif (!response.ok) {\n\t\tthrow new Error(`failed to fetch ${url}: HTTP ${response.status}`);\n\t}\n\treturn await response.text();\n}\n\nasync function readGistFile(file: GistFile): Promise<string> {\n\tif (file.content && !file.truncated) return file.content;\n\tif (!file.raw_url) throw new Error(`gist file ${file.filename ?? \"<unknown>\"} has no raw URL`);\n\treturn await fetchText(file.raw_url);\n}\n\nasync function findIssueGistId(owner: string, repo: string, issue: string): Promise<string> {\n\tconst gistIds: string[] = [];\n\tlet page = 1;\n\twhile (true) {\n\t\tconst response = await fetch(\n\t\t\t`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${encodeURIComponent(issue)}/comments?per_page=100&page=${page}`,\n\t\t\t{ headers: { Accept: \"application/vnd.github+json\", \"X-GitHub-Api-Version\": \"2022-11-28\" } },\n\t\t);\n\t\tif (!response.ok) throw new Error(`failed to fetch issue comments: HTTP ${response.status}`);\n\n\t\tconst comments = (await response.json()) as IssueComment[];\n\t\tfor (const comment of comments) {\n\t\t\tif (comment.user?.login !== \"github-actions[bot]\") continue;\n\t\t\tfor (const match of (comment.body ?? \"\").matchAll(GIST_URL_IN_TEXT_RE)) {\n\t\t\t\tgistIds.push(match[1]);\n\t\t\t}\n\t\t}\n\n\t\tif (comments.length < 100) break;\n\t\tpage++;\n\t}\n\n\tconst gistId = gistIds.at(-1);\n\tif (!gistId) throw new Error(`no github-actions gist link found in comments on ${owner}/${repo}#${issue}`);\n\treturn gistId;\n}\n\nasync function fetchGistSession(gistId: string): Promise<{ header: SessionHeader; jsonl: string }> {\n\tconst response = await fetch(`https://api.github.com/gists/${gistId}`, {\n\t\theaders: {\n\t\t\tAccept: \"application/vnd.github+json\",\n\t\t\t\"X-GitHub-Api-Version\": \"2022-11-28\",\n\t\t},\n\t});\n\tif (!response.ok) throw new Error(`failed to fetch gist ${gistId}: HTTP ${response.status}`);\n\n\tconst gist = (await response.json()) as GistResponse;\n\tconst files = Object.values(gist.files ?? {});\n\tconst jsonlFile = files.find((file) => file.filename?.endsWith(\".jsonl\"));\n\tif (jsonlFile) return parseSessionJsonl(await readGistFile(jsonlFile));\n\n\tconst htmlFile = files.find((file) => file.filename?.endsWith(\".html\"));\n\tif (htmlFile) return decodeExportedHtml(await readGistFile(htmlFile));\n\n\tthrow new Error(`gist ${gistId} has no .jsonl or .html session file`);\n}\n\nexport default function (pi: ExtensionAPI) {\n\tpi.registerCommand(\"ir\", {\n\t\tdescription: \"Import a CI issue-analysis session from a gist ID, share URL, or issue URL and switch to it\",\n\t\thandler: async (args: string, ctx: ExtensionCommandContext) => {\n\t\t\t// Session replacement aborts and disposes the live session; never start\n\t\t\t// that while a run or compaction is active. Commands dispatch immediately\n\t\t\t// now (see extensions/builtin/changes.md), so this handler can be entered\n\t\t\t// mid-turn. isCompacting is checked separately because isIdle() is true\n\t\t\t// during compaction without streaming.\n\t\t\tif (!ctx.isIdle() || ctx.isCompacting?.() === true) {\n\t\t\t\tctx.ui.notify(\"/ir is unavailable while the agent is working\", \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst ref = args.trim();\n\t\t\tif (!ref) {\n\t\t\t\tctx.ui.notify(\"Usage: /ir <gist-id | gist-url | pi.dev/session URL | issue URL>\", \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst targetCwd = ctx.sessionManager.getCwd();\n\t\t\t\tconst sessionDir = ctx.sessionManager.getSessionDir();\n\t\t\t\tconst parsedRef = parseRef(ref, targetCwd);\n\n\t\t\t\tctx.ui.notify(`Importing repro session from ${ref}...`, \"info\");\n\n\t\t\t\tlet sourceName: string;\n\t\t\t\tlet decoded: { header: SessionHeader; jsonl: string };\n\t\t\t\tif (parsedRef.type === \"gist\") {\n\t\t\t\t\tdecoded = await fetchGistSession(parsedRef.id);\n\t\t\t\t\tsourceName = `${parsedRef.id}.jsonl`;\n\t\t\t\t} else if (parsedRef.type === \"issue\") {\n\t\t\t\t\tconst gistId = await findIssueGistId(parsedRef.owner, parsedRef.repo, parsedRef.issue);\n\t\t\t\t\tdecoded = await fetchGistSession(gistId);\n\t\t\t\t\tsourceName = `${gistId}.jsonl`;\n\t\t\t\t} else {\n\t\t\t\t\tif (!existsSync(parsedRef.path)) throw new Error(`session file not found: ${parsedRef.path}`);\n\t\t\t\t\tconst raw = readFileSync(parsedRef.path, \"utf8\");\n\t\t\t\t\tdecoded = parsedRef.path.endsWith(\".html\") ? decodeExportedHtml(raw) : parseSessionJsonl(raw);\n\t\t\t\t\tsourceName = basename(parsedRef.path).replace(/\\.html$/, \".jsonl\");\n\t\t\t\t}\n\n\t\t\t\tconst platformNotice = getPlatformContinuationNotice(decoded.header.cwd);\n\t\t\t\tconst rewritten = rewriteSessionCwd(decoded.jsonl, decoded.header.cwd, targetCwd);\n\t\t\t\tconst destination = join(sessionDir, sourceName);\n\t\t\t\tif (existsSync(destination)) {\n\t\t\t\t\tconst overwrite = await ctx.ui.confirm(\n\t\t\t\t\t\t\"Session already imported\",\n\t\t\t\t\t\t`Overwrite ${destination}? Local changes to that session will be lost.`,\n\t\t\t\t\t);\n\t\t\t\t\tif (!overwrite) {\n\t\t\t\t\t\tctx.ui.notify(\"Import cancelled\", \"warning\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twriteFileSync(destination, rewritten);\n\n\t\t\t\tctx.ui.notify(`Imported session ${decoded.header.id} (cwd ${decoded.header.cwd} -> ${targetCwd})`, \"info\");\n\t\t\t\tawait ctx.switchSession(destination, {\n\t\t\t\t\twithSession: async (nextCtx) => {\n\t\t\t\t\t\tif (!platformNotice) return;\n\t\t\t\t\t\tawait nextCtx.sendMessage(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcustomType: \"import-repro\",\n\t\t\t\t\t\t\t\tcontent: platformNotice,\n\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\tdetails: { sourceCwd: decoded.header.cwd, targetCwd },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ triggerTurn: false },\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tctx.ui.notify(`ir: ${error instanceof Error ? error.message : String(error)}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACzG,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AASrD,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,GACzB,gBAAgB,CAElB;AAED,wBAAsB,sBAAsB,CAC3C,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,CAAC,QAAQ,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3D,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,EAAE,WAAW,oBAAc,GAAG,OAAO,CAE9G"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACzG,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAiCrD,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,GACzB,gBAAgB,CAElB;AAED,wBAAsB,sBAAsB,CAC3C,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,CAAC,QAAQ,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3D,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,EAAE,WAAW,oBAAc,GAAG,OAAO,CAE9G"}
@@ -1,8 +1,28 @@
1
1
  import { canonicalizeFallbackChains } from "../../../retry-fallback/chains.js";
2
+ /**
3
+ * `/fallback` shows what the user can act on. A bare default expands across every
4
+ * provider in the builtin catalog that publishes the model, so canonicalizing
5
+ * against the full registry listed chains for providers the user cannot select
6
+ * (no credentials). Scope the display to selectable models; the runtime keeps
7
+ * using the full registry so a chain still resolves for the active model.
8
+ */
9
+ function displayLookup(models) {
10
+ if (Array.isArray(models))
11
+ return models;
12
+ const registry = models;
13
+ if (typeof registry.getAvailable !== "function")
14
+ return models;
15
+ const available = registry.getAvailable();
16
+ return {
17
+ getAll: () => (available.length > 0 ? available : registry.getAll()),
18
+ isUsingOAuth: (model) => registry.isUsingOAuth?.(model) === true,
19
+ hasConfiguredAuth: (model) => registry.hasConfiguredAuth?.(model) === true,
20
+ };
21
+ }
2
22
  function withAvailableChains(settings, models) {
3
23
  return {
4
24
  ...settings,
5
- chains: canonicalizeFallbackChains(settings.chains, models),
25
+ chains: canonicalizeFallbackChains(settings.chains, displayLookup(models)),
6
26
  };
7
27
  }
8
28
  export function loadFallbackSettings(settings, models) {
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAA4B,MAAM,mCAAmC,CAAC;AAKzG,SAAS,mBAAmB,CAAC,QAA0B,EAAE,MAA2B;IACnF,OAAO;QACN,GAAG,QAAQ;QACX,MAAM,EAAE,0BAA0B,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,QAAkC,EAClC,MAA2B;IAE3B,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,QAAkC,EAClC,MAA2B,EAC3B,MAA6D;IAE7D,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAkC,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG;IACpG,OAAO,IAAI,KAAK,IAAI,IAAI,WAAW,CAAC,iBAAiB,KAAK,GAAG,CAAC;AAC/D,CAAC","sourcesContent":["import { canonicalizeFallbackChains, type FallbackModelLookup } from \"../../../retry-fallback/chains.ts\";\nimport type { ExtensionSessionSettings, RetryFallbackSettings } from \"../../types.ts\";\n\nexport type FallbackSettings = RetryFallbackSettings;\n\nfunction withAvailableChains(settings: FallbackSettings, models: FallbackModelLookup): FallbackSettings {\n\treturn {\n\t\t...settings,\n\t\tchains: canonicalizeFallbackChains(settings.chains, models),\n\t};\n}\n\nexport function loadFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n): FallbackSettings {\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport async function updateFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n\tupdate: (settings: ExtensionSessionSettings) => Promise<void>,\n): Promise<FallbackSettings> {\n\tawait update(settings);\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport function isModelFallbackDisabled(flag: boolean | string | undefined, environment = process.env): boolean {\n\treturn flag === true || environment.SENPI_NO_FALLBACK === \"1\";\n}\n"]}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAA4B,MAAM,mCAAmC,CAAC;AAKzG;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,MAA2B;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACzC,MAAM,QAAQ,GAAG,MAKhB,CAAC;IACF,IAAI,OAAO,QAAQ,CAAC,YAAY,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC;IAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;IAC1C,OAAO;QACN,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpE,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI;QAChE,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI;KAC1E,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,QAA0B,EAAE,MAA2B;IACnF,OAAO;QACN,GAAG,QAAQ;QACX,MAAM,EAAE,0BAA0B,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;KAC1E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,QAAkC,EAClC,MAA2B;IAE3B,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,QAAkC,EAClC,MAA2B,EAC3B,MAA6D;IAE7D,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAkC,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG;IACpG,OAAO,IAAI,KAAK,IAAI,IAAI,WAAW,CAAC,iBAAiB,KAAK,GAAG,CAAC;AAC/D,CAAC","sourcesContent":["import type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { canonicalizeFallbackChains, type FallbackModelLookup } from \"../../../retry-fallback/chains.ts\";\nimport type { ExtensionSessionSettings, RetryFallbackSettings } from \"../../types.ts\";\n\nexport type FallbackSettings = RetryFallbackSettings;\n\n/**\n * `/fallback` shows what the user can act on. A bare default expands across every\n * provider in the builtin catalog that publishes the model, so canonicalizing\n * against the full registry listed chains for providers the user cannot select\n * (no credentials). Scope the display to selectable models; the runtime keeps\n * using the full registry so a chain still resolves for the active model.\n */\nfunction displayLookup(models: FallbackModelLookup): FallbackModelLookup {\n\tif (Array.isArray(models)) return models;\n\tconst registry = models as {\n\t\tgetAll(): Model<Api>[];\n\t\tgetAvailable?(): Model<Api>[];\n\t\tisUsingOAuth?(model: Model<Api>): boolean;\n\t\thasConfiguredAuth?(model: Model<Api>): boolean;\n\t};\n\tif (typeof registry.getAvailable !== \"function\") return models;\n\tconst available = registry.getAvailable();\n\treturn {\n\t\tgetAll: () => (available.length > 0 ? available : registry.getAll()),\n\t\tisUsingOAuth: (model) => registry.isUsingOAuth?.(model) === true,\n\t\thasConfiguredAuth: (model) => registry.hasConfiguredAuth?.(model) === true,\n\t};\n}\n\nfunction withAvailableChains(settings: FallbackSettings, models: FallbackModelLookup): FallbackSettings {\n\treturn {\n\t\t...settings,\n\t\tchains: canonicalizeFallbackChains(settings.chains, displayLookup(models)),\n\t};\n}\n\nexport function loadFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n): FallbackSettings {\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport async function updateFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n\tupdate: (settings: ExtensionSessionSettings) => Promise<void>,\n): Promise<FallbackSettings> {\n\tawait update(settings);\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport function isModelFallbackDisabled(flag: boolean | string | undefined, environment = process.env): boolean {\n\treturn flag === true || environment.SENPI_NO_FALLBACK === \"1\";\n}\n"]}
@@ -0,0 +1,13 @@
1
+ export declare const RESUMPTION_CHANNEL_STATE_EVENT = "resumption_channel_state";
2
+ export interface ResumptionChannelEntry {
3
+ readonly id: string;
4
+ readonly description: string;
5
+ readonly startedAtMs: number;
6
+ }
7
+ export interface ResumptionChannelStateEvent {
8
+ readonly source: string;
9
+ readonly activeCount: number;
10
+ readonly channels?: readonly ResumptionChannelEntry[];
11
+ }
12
+ export declare function isResumptionChannelStateEvent(data: unknown): data is ResumptionChannelStateEvent;
13
+ //# sourceMappingURL=resumption-channel-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resumption-channel-event.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/resumption-channel-event.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,8BAA8B,6BAA6B,CAAC;AAEzE,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACtD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,2BAA2B,CAYhG"}
@@ -0,0 +1,13 @@
1
+ export const RESUMPTION_CHANNEL_STATE_EVENT = "resumption_channel_state";
2
+ export function isResumptionChannelStateEvent(data) {
3
+ return (typeof data === "object" &&
4
+ data !== null &&
5
+ "source" in data &&
6
+ typeof data.source === "string" &&
7
+ data.source.length > 0 &&
8
+ "activeCount" in data &&
9
+ typeof data.activeCount === "number" &&
10
+ Number.isInteger(data.activeCount) &&
11
+ data.activeCount >= 0);
12
+ }
13
+ //# sourceMappingURL=resumption-channel-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resumption-channel-event.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/resumption-channel-event.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,8BAA8B,GAAG,0BAA0B,CAAC;AAczE,MAAM,UAAU,6BAA6B,CAAC,IAAa;IAC1D,OAAO,CACN,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,QAAQ,IAAI,IAAI;QAChB,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;QAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QACtB,aAAa,IAAI,IAAI;QACrB,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;QACpC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC;QAClC,IAAI,CAAC,WAAW,IAAI,CAAC,CACrB,CAAC;AACH,CAAC","sourcesContent":["export const RESUMPTION_CHANNEL_STATE_EVENT = \"resumption_channel_state\";\n\nexport interface ResumptionChannelEntry {\n\treadonly id: string;\n\treadonly description: string;\n\treadonly startedAtMs: number;\n}\n\nexport interface ResumptionChannelStateEvent {\n\treadonly source: string;\n\treadonly activeCount: number;\n\treadonly channels?: readonly ResumptionChannelEntry[];\n}\n\nexport function isResumptionChannelStateEvent(data: unknown): data is ResumptionChannelStateEvent {\n\treturn (\n\t\ttypeof data === \"object\" &&\n\t\tdata !== null &&\n\t\t\"source\" in data &&\n\t\ttypeof data.source === \"string\" &&\n\t\tdata.source.length > 0 &&\n\t\t\"activeCount\" in data &&\n\t\ttypeof data.activeCount === \"number\" &&\n\t\tNumber.isInteger(data.activeCount) &&\n\t\tdata.activeCount >= 0\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AA+IrE,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAsGhE;eAEc,yBAAyB"}
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAmKrE,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAsGhE;eAEc,yBAAyB"}
@@ -2,6 +2,7 @@ import { getShellEnv } from "../../../../utils/shell.js";
2
2
  import { SettingsManager } from "../../../settings-manager.js";
3
3
  import { isAnthropicBashEnabled } from "../anthropic-bash/index.js";
4
4
  import { TERMINAL_MONITOR_STATE_EVENT } from "../monitor-state-event.js";
5
+ import { RESUMPTION_CHANNEL_STATE_EVENT } from "../resumption-channel-event.js";
5
6
  import { MonitorNotifier } from "./monitor-notify.js";
6
7
  import { MONITOR_STATUS_KEY } from "./monitor-status.js";
7
8
  import { MonitorStatusTicker } from "./monitor-status-ticker.js";
@@ -41,6 +42,22 @@ function bundleSinks(pi, state) {
41
42
  startedAtMs: entry.startedAtMs,
42
43
  })),
43
44
  });
45
+ pi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {
46
+ source: "terminal-monitor",
47
+ activeCount: snapshot.length,
48
+ channels: snapshot.map((entry) => ({
49
+ id: entry.id,
50
+ description: entry.description,
51
+ startedAtMs: entry.startedAtMs,
52
+ })),
53
+ });
54
+ },
55
+ onBackgroundState: (snapshot) => {
56
+ pi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {
57
+ source: "terminal-bash",
58
+ activeCount: snapshot.length,
59
+ channels: snapshot,
60
+ });
44
61
  },
45
62
  onBackgroundExit: (id, runtime) => state.notifier?.notifyCompletion(id, runtime),
46
63
  };
@@ -82,6 +99,9 @@ function buildToolContext(pi, state) {
82
99
  getSessionContext: () => state.ctx,
83
100
  // Exit listeners registered before a reload reach the post-reload owner through the
84
101
  // shared bundle, so this must dispatch via the bundle, never the instance notifier.
102
+ onBackgroundStart: (id, description, startedAtMs) => {
103
+ state.bundle?.notifyBackgroundStart(id, description, startedAtMs);
104
+ },
85
105
  onBackgroundExit: (id, runtime) => {
86
106
  state.bundle?.notifyBackgroundExit(id, runtime);
87
107
  },
@@ -1 +1 @@
1
- {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"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","sourcesContent":["import { getShellEnv } from \"../../../../utils/shell.ts\";\nimport { SettingsManager } from \"../../../settings-manager.ts\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { isAnthropicBashEnabled } from \"../anthropic-bash/index.ts\";\nimport { TERMINAL_MONITOR_STATE_EVENT } from \"../monitor-state-event.ts\";\nimport { MonitorNotifier } from \"./monitor-notify.ts\";\nimport { MONITOR_STATUS_KEY } from \"./monitor-status.ts\";\nimport { MonitorStatusTicker } from \"./monitor-status-ticker.ts\";\nimport { TerminalNotifier } from \"./notify.ts\";\nimport { TERMINAL_PROMPT_SECTION } from \"./prompt.ts\";\nimport type { TerminalRuntimeSession } from \"./runtime-session.ts\";\nimport {\n\tclaimParkedBundle,\n\tparkBundle,\n\ttype TerminalEventSinks,\n\tTerminalSessionBundle,\n\tteardownParkedBundle,\n} from \"./session-bundle.ts\";\nimport { loadTerminalSettings, type ResolvedTerminalSettings, TERMINAL_SETTINGS_DEFAULTS } from \"./settings.ts\";\nimport { TERMINAL_BASH_TOOL, TERMINAL_COMPANION_TOOLS } from \"./shared.ts\";\nimport { createPtyBashTool } from \"./tools/bash.ts\";\nimport { createBashInputTool } from \"./tools/bash-input.ts\";\nimport { createBashOutputTool } from \"./tools/bash-output.ts\";\nimport { createBashResizeTool } from \"./tools/bash-resize.ts\";\nimport type { TerminalToolContext } from \"./tools/context.ts\";\nimport { createKillBashTool } from \"./tools/kill-bash.ts\";\nimport { createMonitorTool } from \"./tools/monitor.ts\";\n\ninterface TerminalExtensionState {\n\tbundle: TerminalSessionBundle | null;\n\tsettings: ResolvedTerminalSettings;\n\tnotifier: TerminalNotifier | null;\n\tmonitorNotifier: MonitorNotifier | null;\n\tstatusTicker: MonitorStatusTicker;\n\tctx: ExtensionContext | undefined;\n\tshellPath: string | undefined;\n\tsteppedAside: boolean;\n\tnoticeShown: boolean;\n}\n\n/** Tests and SDK callers may hand partial contexts without a session manager. */\nfunction sessionKeyOf(ctx: ExtensionContext | undefined): string | undefined {\n\treturn ctx?.sessionManager?.getSessionId?.();\n}\n\nfunction createBundle(state: TerminalExtensionState): TerminalSessionBundle {\n\treturn new TerminalSessionBundle({\n\t\tmaxSessions: state.settings.maxSessions,\n\t\tscrollback: state.settings.scrollback,\n\t});\n}\n\n/** Sinks read the live instance state at call time, so notifier swaps need no re-bind. */\nfunction bundleSinks(pi: ExtensionAPI, state: TerminalExtensionState): TerminalEventSinks {\n\treturn {\n\t\tonMonitorEvent: (event) => state.monitorNotifier?.notifyEvent(event),\n\t\tonMonitorState: (snapshot) => {\n\t\t\tstate.statusTicker.sync(snapshot);\n\t\t\tpi.events?.emit(TERMINAL_MONITOR_STATE_EVENT, {\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tmonitors: snapshot.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tdescription: entry.description,\n\t\t\t\t\tpaused: entry.paused,\n\t\t\t\t\tstartedAtMs: entry.startedAtMs,\n\t\t\t\t})),\n\t\t\t});\n\t\t},\n\t\tonBackgroundExit: (id, runtime) => state.notifier?.notifyCompletion(id, runtime),\n\t};\n}\n\nfunction buildToolContext(pi: ExtensionAPI, state: TerminalExtensionState): TerminalToolContext {\n\tconst requireBundle = (): TerminalSessionBundle => {\n\t\t// Lazily create a bundle so the tools work even when invoked directly (e.g. via the\n\t\t// SDK) before `session_start` initializes one. `session_start` replaces it with a\n\t\t// settings-configured bundle and tears down any earlier one.\n\t\tif (!state.bundle) {\n\t\t\tstate.bundle = createBundle(state);\n\t\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\t}\n\t\treturn state.bundle;\n\t};\n\treturn {\n\t\tget manager() {\n\t\t\treturn requireBundle().manager;\n\t\t},\n\t\tget cwd() {\n\t\t\treturn state.ctx?.cwd ?? process.cwd();\n\t\t},\n\t\tget shellPath() {\n\t\t\treturn state.shellPath;\n\t\t},\n\t\tget defaultCols() {\n\t\t\treturn state.settings.defaultCols;\n\t\t},\n\t\tget defaultRows() {\n\t\t\treturn state.settings.defaultRows;\n\t\t},\n\t\tget timeoutAction() {\n\t\t\treturn state.settings.timeoutAction;\n\t\t},\n\t\tget monitorRegistry() {\n\t\t\treturn requireBundle().monitors;\n\t\t},\n\t\tgetEnv: () => getShellEnv(),\n\t\tgetSessionContext: () => state.ctx,\n\t\t// Exit listeners registered before a reload reach the post-reload owner through the\n\t\t// shared bundle, so this must dispatch via the bundle, never the instance notifier.\n\t\tonBackgroundExit: (id: string, runtime: TerminalRuntimeSession) => {\n\t\t\tstate.bundle?.notifyBackgroundExit(id, runtime);\n\t\t},\n\t\tonMonitorRearmed: (id: string) => state.monitorNotifier?.rearm(id),\n\t};\n}\n\nfunction shouldStepAside(ctx: ExtensionContext | undefined): boolean {\n\treturn isAnthropicBashEnabled() && ctx?.model?.api === \"anthropic-messages\";\n}\n\n/**\n * Keep the tool surface consistent with anthropic-bash. When native Anthropic bash is active,\n * the provider replaces the PTY `bash` function, but the companions stay active because `monitor`\n * creates its own PTY session and bash_output/input/resize/kill operate on that shared registry.\n * Otherwise the PTY `bash` + companions are (re)activated. Re-evaluated on session_start AND\n * model_select.\n */\nfunction syncToolset(pi: ExtensionAPI, state: TerminalExtensionState): void {\n\tconst stepAside = shouldStepAside(state.ctx);\n\tconst active = new Set(pi.getActiveTools());\n\tif (stepAside) {\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tif (!state.noticeShown) {\n\t\t\tstate.ctx?.ui.notify(\"native Anthropic bash active — monitor sessions remain available\", \"info\");\n\t\t\tstate.noticeShown = true;\n\t\t}\n\t} else {\n\t\tactive.add(TERMINAL_BASH_TOOL);\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tstate.noticeShown = false;\n\t}\n\tstate.steppedAside = stepAside;\n\tpi.setActiveTools([...active]);\n}\n\nexport function registerTerminalExtension(pi: ExtensionAPI): void {\n\tconst state: TerminalExtensionState = {\n\t\tbundle: null,\n\t\tsettings: TERMINAL_SETTINGS_DEFAULTS,\n\t\tnotifier: null,\n\t\tmonitorNotifier: null,\n\t\tstatusTicker: new MonitorStatusTicker({\n\t\t\trender: (status) => {\n\t\t\t\tconst ctx = state.ctx;\n\t\t\t\tctx?.ui.setStatus(\n\t\t\t\t\tMONITOR_STATUS_KEY,\n\t\t\t\t\tstatus === undefined || ctx.mode !== \"tui\"\n\t\t\t\t\t\t? status\n\t\t\t\t\t\t: ctx.ui.theme.bg(\"selectedBg\", ctx.ui.theme.fg(\"text\", status)),\n\t\t\t\t);\n\t\t\t},\n\t\t}),\n\t\tctx: undefined,\n\t\tshellPath: undefined,\n\t\tsteppedAside: false,\n\t\tnoticeShown: false,\n\t};\n\tconst toolCtx = buildToolContext(pi, state);\n\n\tpi.registerTool(createPtyBashTool(toolCtx));\n\tpi.registerTool(createBashOutputTool(toolCtx));\n\tpi.registerTool(createBashInputTool(toolCtx));\n\tpi.registerTool(createBashResizeTool(toolCtx));\n\tpi.registerTool(createKillBashTool(toolCtx));\n\tpi.registerTool(createMonitorTool(toolCtx));\n\n\tpi.on(\"session_start\", async (event, ctx) => {\n\t\tstate.ctx = ctx;\n\t\tconst settingsManager = SettingsManager.create(ctx.cwd);\n\t\tstate.settings = loadTerminalSettings(settingsManager);\n\t\tstate.shellPath = settingsManager.getShellPath();\n\t\tstate.notifier = new TerminalNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t});\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = new MonitorNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t\tgetSettings: () => state.settings.monitor,\n\t\t\tpauseMonitors: () => state.bundle?.monitors.pauseAll() ?? [],\n\t\t});\n\t\tconst sessionKey = sessionKeyOf(ctx);\n\t\tif (event.reason === \"reload\") {\n\t\t\tconst claimed = sessionKey === undefined ? undefined : claimParkedBundle(sessionKey);\n\t\t\tif (claimed) {\n\t\t\t\tawait state.bundle?.teardown();\n\t\t\t\tstate.bundle = claimed;\n\t\t\t}\n\t\t} else {\n\t\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t\t\tawait state.bundle?.teardown();\n\t\t\tstate.bundle = createBundle(state);\n\t\t}\n\t\tstate.bundle ??= createBundle(state);\n\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"model_select\", async (event, ctx) => {\n\t\tstate.ctx = { ...ctx, model: event.model };\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"input\", (event) => {\n\t\tif (event.source !== \"extension\") state.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"tool_call\", () => {\n\t\tstate.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"before_agent_start\", async (event) => {\n\t\tif (state.steppedAside) return undefined;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n${TERMINAL_PROMPT_SECTION}` };\n\t});\n\n\tpi.on(\"session_shutdown\", async (event, ctx) => {\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = null;\n\t\tstate.notifier = null;\n\t\tstate.statusTicker.stop();\n\t\tconst sessionKey = sessionKeyOf(ctx) ?? sessionKeyOf(state.ctx);\n\t\tif (event.reason === \"reload\" && state.bundle && sessionKey !== undefined) {\n\t\t\t// Keep state.bundle referenced: exit listeners captured by this instance's tool\n\t\t\t// context still route through the shared bundle after the new owner claims it.\n\t\t\tstate.bundle.park();\n\t\t\tawait parkBundle(sessionKey, state.bundle);\n\t\t\treturn;\n\t\t}\n\t\tconst bundle = state.bundle;\n\t\tstate.bundle = null;\n\t\tawait bundle?.teardown();\n\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t});\n}\n\nexport default registerTerminalExtension;\n"]}
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"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","sourcesContent":["import { getShellEnv } from \"../../../../utils/shell.ts\";\nimport { SettingsManager } from \"../../../settings-manager.ts\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { isAnthropicBashEnabled } from \"../anthropic-bash/index.ts\";\nimport { TERMINAL_MONITOR_STATE_EVENT } from \"../monitor-state-event.ts\";\nimport { RESUMPTION_CHANNEL_STATE_EVENT } from \"../resumption-channel-event.ts\";\nimport { MonitorNotifier } from \"./monitor-notify.ts\";\nimport { MONITOR_STATUS_KEY } from \"./monitor-status.ts\";\nimport { MonitorStatusTicker } from \"./monitor-status-ticker.ts\";\nimport { TerminalNotifier } from \"./notify.ts\";\nimport { TERMINAL_PROMPT_SECTION } from \"./prompt.ts\";\nimport type { TerminalRuntimeSession } from \"./runtime-session.ts\";\nimport {\n\tclaimParkedBundle,\n\tparkBundle,\n\ttype TerminalEventSinks,\n\tTerminalSessionBundle,\n\tteardownParkedBundle,\n} from \"./session-bundle.ts\";\nimport { loadTerminalSettings, type ResolvedTerminalSettings, TERMINAL_SETTINGS_DEFAULTS } from \"./settings.ts\";\nimport { TERMINAL_BASH_TOOL, TERMINAL_COMPANION_TOOLS } from \"./shared.ts\";\nimport { createPtyBashTool } from \"./tools/bash.ts\";\nimport { createBashInputTool } from \"./tools/bash-input.ts\";\nimport { createBashOutputTool } from \"./tools/bash-output.ts\";\nimport { createBashResizeTool } from \"./tools/bash-resize.ts\";\nimport type { TerminalToolContext } from \"./tools/context.ts\";\nimport { createKillBashTool } from \"./tools/kill-bash.ts\";\nimport { createMonitorTool } from \"./tools/monitor.ts\";\n\ninterface TerminalExtensionState {\n\tbundle: TerminalSessionBundle | null;\n\tsettings: ResolvedTerminalSettings;\n\tnotifier: TerminalNotifier | null;\n\tmonitorNotifier: MonitorNotifier | null;\n\tstatusTicker: MonitorStatusTicker;\n\tctx: ExtensionContext | undefined;\n\tshellPath: string | undefined;\n\tsteppedAside: boolean;\n\tnoticeShown: boolean;\n}\n\n/** Tests and SDK callers may hand partial contexts without a session manager. */\nfunction sessionKeyOf(ctx: ExtensionContext | undefined): string | undefined {\n\treturn ctx?.sessionManager?.getSessionId?.();\n}\n\nfunction createBundle(state: TerminalExtensionState): TerminalSessionBundle {\n\treturn new TerminalSessionBundle({\n\t\tmaxSessions: state.settings.maxSessions,\n\t\tscrollback: state.settings.scrollback,\n\t});\n}\n\n/** Sinks read the live instance state at call time, so notifier swaps need no re-bind. */\nfunction bundleSinks(pi: ExtensionAPI, state: TerminalExtensionState): TerminalEventSinks {\n\treturn {\n\t\tonMonitorEvent: (event) => state.monitorNotifier?.notifyEvent(event),\n\t\tonMonitorState: (snapshot) => {\n\t\t\tstate.statusTicker.sync(snapshot);\n\t\t\tpi.events?.emit(TERMINAL_MONITOR_STATE_EVENT, {\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tmonitors: snapshot.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tdescription: entry.description,\n\t\t\t\t\tpaused: entry.paused,\n\t\t\t\t\tstartedAtMs: entry.startedAtMs,\n\t\t\t\t})),\n\t\t\t});\n\t\t\tpi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {\n\t\t\t\tsource: \"terminal-monitor\",\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tchannels: snapshot.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tdescription: entry.description,\n\t\t\t\t\tstartedAtMs: entry.startedAtMs,\n\t\t\t\t})),\n\t\t\t});\n\t\t},\n\t\tonBackgroundState: (snapshot) => {\n\t\t\tpi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {\n\t\t\t\tsource: \"terminal-bash\",\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tchannels: snapshot,\n\t\t\t});\n\t\t},\n\t\tonBackgroundExit: (id, runtime) => state.notifier?.notifyCompletion(id, runtime),\n\t};\n}\n\nfunction buildToolContext(pi: ExtensionAPI, state: TerminalExtensionState): TerminalToolContext {\n\tconst requireBundle = (): TerminalSessionBundle => {\n\t\t// Lazily create a bundle so the tools work even when invoked directly (e.g. via the\n\t\t// SDK) before `session_start` initializes one. `session_start` replaces it with a\n\t\t// settings-configured bundle and tears down any earlier one.\n\t\tif (!state.bundle) {\n\t\t\tstate.bundle = createBundle(state);\n\t\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\t}\n\t\treturn state.bundle;\n\t};\n\treturn {\n\t\tget manager() {\n\t\t\treturn requireBundle().manager;\n\t\t},\n\t\tget cwd() {\n\t\t\treturn state.ctx?.cwd ?? process.cwd();\n\t\t},\n\t\tget shellPath() {\n\t\t\treturn state.shellPath;\n\t\t},\n\t\tget defaultCols() {\n\t\t\treturn state.settings.defaultCols;\n\t\t},\n\t\tget defaultRows() {\n\t\t\treturn state.settings.defaultRows;\n\t\t},\n\t\tget timeoutAction() {\n\t\t\treturn state.settings.timeoutAction;\n\t\t},\n\t\tget monitorRegistry() {\n\t\t\treturn requireBundle().monitors;\n\t\t},\n\t\tgetEnv: () => getShellEnv(),\n\t\tgetSessionContext: () => state.ctx,\n\t\t// Exit listeners registered before a reload reach the post-reload owner through the\n\t\t// shared bundle, so this must dispatch via the bundle, never the instance notifier.\n\t\tonBackgroundStart: (id: string, description: string, startedAtMs: number) => {\n\t\t\tstate.bundle?.notifyBackgroundStart(id, description, startedAtMs);\n\t\t},\n\t\tonBackgroundExit: (id: string, runtime: TerminalRuntimeSession) => {\n\t\t\tstate.bundle?.notifyBackgroundExit(id, runtime);\n\t\t},\n\t\tonMonitorRearmed: (id: string) => state.monitorNotifier?.rearm(id),\n\t};\n}\n\nfunction shouldStepAside(ctx: ExtensionContext | undefined): boolean {\n\treturn isAnthropicBashEnabled() && ctx?.model?.api === \"anthropic-messages\";\n}\n\n/**\n * Keep the tool surface consistent with anthropic-bash. When native Anthropic bash is active,\n * the provider replaces the PTY `bash` function, but the companions stay active because `monitor`\n * creates its own PTY session and bash_output/input/resize/kill operate on that shared registry.\n * Otherwise the PTY `bash` + companions are (re)activated. Re-evaluated on session_start AND\n * model_select.\n */\nfunction syncToolset(pi: ExtensionAPI, state: TerminalExtensionState): void {\n\tconst stepAside = shouldStepAside(state.ctx);\n\tconst active = new Set(pi.getActiveTools());\n\tif (stepAside) {\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tif (!state.noticeShown) {\n\t\t\tstate.ctx?.ui.notify(\"native Anthropic bash active — monitor sessions remain available\", \"info\");\n\t\t\tstate.noticeShown = true;\n\t\t}\n\t} else {\n\t\tactive.add(TERMINAL_BASH_TOOL);\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tstate.noticeShown = false;\n\t}\n\tstate.steppedAside = stepAside;\n\tpi.setActiveTools([...active]);\n}\n\nexport function registerTerminalExtension(pi: ExtensionAPI): void {\n\tconst state: TerminalExtensionState = {\n\t\tbundle: null,\n\t\tsettings: TERMINAL_SETTINGS_DEFAULTS,\n\t\tnotifier: null,\n\t\tmonitorNotifier: null,\n\t\tstatusTicker: new MonitorStatusTicker({\n\t\t\trender: (status) => {\n\t\t\t\tconst ctx = state.ctx;\n\t\t\t\tctx?.ui.setStatus(\n\t\t\t\t\tMONITOR_STATUS_KEY,\n\t\t\t\t\tstatus === undefined || ctx.mode !== \"tui\"\n\t\t\t\t\t\t? status\n\t\t\t\t\t\t: ctx.ui.theme.bg(\"selectedBg\", ctx.ui.theme.fg(\"text\", status)),\n\t\t\t\t);\n\t\t\t},\n\t\t}),\n\t\tctx: undefined,\n\t\tshellPath: undefined,\n\t\tsteppedAside: false,\n\t\tnoticeShown: false,\n\t};\n\tconst toolCtx = buildToolContext(pi, state);\n\n\tpi.registerTool(createPtyBashTool(toolCtx));\n\tpi.registerTool(createBashOutputTool(toolCtx));\n\tpi.registerTool(createBashInputTool(toolCtx));\n\tpi.registerTool(createBashResizeTool(toolCtx));\n\tpi.registerTool(createKillBashTool(toolCtx));\n\tpi.registerTool(createMonitorTool(toolCtx));\n\n\tpi.on(\"session_start\", async (event, ctx) => {\n\t\tstate.ctx = ctx;\n\t\tconst settingsManager = SettingsManager.create(ctx.cwd);\n\t\tstate.settings = loadTerminalSettings(settingsManager);\n\t\tstate.shellPath = settingsManager.getShellPath();\n\t\tstate.notifier = new TerminalNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t});\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = new MonitorNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t\tgetSettings: () => state.settings.monitor,\n\t\t\tpauseMonitors: () => state.bundle?.monitors.pauseAll() ?? [],\n\t\t});\n\t\tconst sessionKey = sessionKeyOf(ctx);\n\t\tif (event.reason === \"reload\") {\n\t\t\tconst claimed = sessionKey === undefined ? undefined : claimParkedBundle(sessionKey);\n\t\t\tif (claimed) {\n\t\t\t\tawait state.bundle?.teardown();\n\t\t\t\tstate.bundle = claimed;\n\t\t\t}\n\t\t} else {\n\t\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t\t\tawait state.bundle?.teardown();\n\t\t\tstate.bundle = createBundle(state);\n\t\t}\n\t\tstate.bundle ??= createBundle(state);\n\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"model_select\", async (event, ctx) => {\n\t\tstate.ctx = { ...ctx, model: event.model };\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"input\", (event) => {\n\t\tif (event.source !== \"extension\") state.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"tool_call\", () => {\n\t\tstate.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"before_agent_start\", async (event) => {\n\t\tif (state.steppedAside) return undefined;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n${TERMINAL_PROMPT_SECTION}` };\n\t});\n\n\tpi.on(\"session_shutdown\", async (event, ctx) => {\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = null;\n\t\tstate.notifier = null;\n\t\tstate.statusTicker.stop();\n\t\tconst sessionKey = sessionKeyOf(ctx) ?? sessionKeyOf(state.ctx);\n\t\tif (event.reason === \"reload\" && state.bundle && sessionKey !== undefined) {\n\t\t\t// Keep state.bundle referenced: exit listeners captured by this instance's tool\n\t\t\t// context still route through the shared bundle after the new owner claims it.\n\t\t\tstate.bundle.park();\n\t\t\tawait parkBundle(sessionKey, state.bundle);\n\t\t\treturn;\n\t\t}\n\t\tconst bundle = state.bundle;\n\t\tstate.bundle = null;\n\t\tawait bundle?.teardown();\n\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t});\n}\n\nexport default registerTerminalExtension;\n"]}