@oh-my-pi/pi-coding-agent 15.9.3 → 15.9.67

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 (142) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/dist/types/cli/classify-install-target.d.ts +5 -1
  3. package/dist/types/config/keybindings.d.ts +4 -1
  4. package/dist/types/config/settings-schema.d.ts +24 -5
  5. package/dist/types/edit/file-snapshot-store.d.ts +1 -1
  6. package/dist/types/eval/__tests__/kernel-spawn.test.d.ts +1 -0
  7. package/dist/types/eval/backend.d.ts +6 -6
  8. package/dist/types/eval/bridge-timeout.d.ts +27 -0
  9. package/dist/types/eval/idle-timeout.d.ts +16 -14
  10. package/dist/types/eval/js/executor.d.ts +3 -3
  11. package/dist/types/eval/py/executor.d.ts +2 -2
  12. package/dist/types/eval/py/spawn-options.d.ts +58 -0
  13. package/dist/types/modes/components/assistant-message.d.ts +16 -0
  14. package/dist/types/modes/components/copy-selector.d.ts +22 -0
  15. package/dist/types/modes/components/custom-editor.d.ts +3 -1
  16. package/dist/types/modes/components/error-banner.d.ts +11 -0
  17. package/dist/types/modes/components/model-selector.d.ts +1 -0
  18. package/dist/types/modes/components/tool-execution.d.ts +15 -0
  19. package/dist/types/modes/components/transcript-container.d.ts +1 -0
  20. package/dist/types/modes/components/user-message.d.ts +1 -1
  21. package/dist/types/modes/controllers/command-controller.d.ts +0 -1
  22. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  23. package/dist/types/modes/image-references.d.ts +17 -0
  24. package/dist/types/modes/interactive-mode.d.ts +8 -1
  25. package/dist/types/modes/types.d.ts +8 -1
  26. package/dist/types/modes/utils/copy-targets.d.ts +53 -0
  27. package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
  28. package/dist/types/session/blob-store.d.ts +12 -11
  29. package/dist/types/session/session-manager.d.ts +5 -3
  30. package/dist/types/system-prompt.d.ts +2 -0
  31. package/dist/types/tiny/title-client.d.ts +16 -1
  32. package/dist/types/tool-discovery/mode.d.ts +8 -0
  33. package/dist/types/tools/archive-reader.d.ts +5 -1
  34. package/dist/types/tools/eval-render.d.ts +8 -0
  35. package/dist/types/tools/render-utils.d.ts +25 -0
  36. package/dist/types/tui/code-cell.d.ts +6 -0
  37. package/dist/types/tui/hyperlink.d.ts +12 -0
  38. package/dist/types/tui/output-block.d.ts +11 -0
  39. package/dist/types/web/search/render.d.ts +1 -2
  40. package/package.json +9 -9
  41. package/src/autoresearch/dashboard.ts +11 -21
  42. package/src/cli/classify-install-target.ts +31 -5
  43. package/src/cli/claude-trace-cli.ts +13 -1
  44. package/src/cli/plugin-cli.ts +45 -0
  45. package/src/cli/web-search-cli.ts +0 -1
  46. package/src/config/keybindings.ts +58 -1
  47. package/src/config/model-registry.ts +54 -4
  48. package/src/config/settings-schema.ts +25 -5
  49. package/src/debug/raw-sse.ts +18 -4
  50. package/src/edit/file-snapshot-store.ts +1 -1
  51. package/src/edit/index.ts +1 -1
  52. package/src/edit/renderer.ts +7 -7
  53. package/src/edit/streaming.ts +1 -1
  54. package/src/eval/__tests__/agent-bridge.test.ts +100 -27
  55. package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
  56. package/src/eval/__tests__/idle-timeout.test.ts +26 -12
  57. package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
  58. package/src/eval/__tests__/llm-bridge.test.ts +10 -10
  59. package/src/eval/__tests__/shared-executors.test.ts +2 -2
  60. package/src/eval/agent-bridge.ts +4 -5
  61. package/src/eval/backend.ts +6 -6
  62. package/src/eval/bridge-timeout.ts +44 -0
  63. package/src/eval/idle-timeout.ts +33 -15
  64. package/src/eval/js/executor.ts +10 -10
  65. package/src/eval/llm-bridge.ts +4 -5
  66. package/src/eval/py/executor.ts +6 -6
  67. package/src/eval/py/kernel.ts +11 -1
  68. package/src/eval/py/spawn-options.ts +126 -0
  69. package/src/eval/py/tool-bridge.ts +43 -5
  70. package/src/export/ttsr.ts +9 -0
  71. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +31 -2
  72. package/src/extensibility/extensions/runner.ts +2 -0
  73. package/src/internal-urls/docs-index.generated.ts +9 -8
  74. package/src/lsp/client.ts +80 -2
  75. package/src/lsp/index.ts +38 -4
  76. package/src/lsp/render.ts +3 -3
  77. package/src/main.ts +8 -2
  78. package/src/modes/components/agent-dashboard.ts +13 -4
  79. package/src/modes/components/assistant-message.ts +44 -1
  80. package/src/modes/components/copy-selector.ts +249 -0
  81. package/src/modes/components/custom-editor.ts +14 -2
  82. package/src/modes/components/error-banner.ts +33 -0
  83. package/src/modes/components/extensions/extension-list.ts +17 -8
  84. package/src/modes/components/history-search.ts +19 -11
  85. package/src/modes/components/model-selector.ts +125 -29
  86. package/src/modes/components/oauth-selector.ts +28 -12
  87. package/src/modes/components/session-observer-overlay.ts +13 -15
  88. package/src/modes/components/session-selector.ts +24 -13
  89. package/src/modes/components/tool-execution.ts +71 -13
  90. package/src/modes/components/transcript-container.ts +93 -32
  91. package/src/modes/components/tree-selector.ts +19 -7
  92. package/src/modes/components/user-message-selector.ts +25 -14
  93. package/src/modes/components/user-message.ts +9 -2
  94. package/src/modes/controllers/command-controller.ts +0 -116
  95. package/src/modes/controllers/event-controller.ts +67 -12
  96. package/src/modes/controllers/input-controller.ts +33 -1
  97. package/src/modes/controllers/selector-controller.ts +38 -1
  98. package/src/modes/image-references.ts +111 -0
  99. package/src/modes/interactive-mode.ts +52 -17
  100. package/src/modes/theme/theme.ts +46 -10
  101. package/src/modes/types.ts +11 -2
  102. package/src/modes/utils/copy-targets.ts +254 -0
  103. package/src/modes/utils/ui-helpers.ts +23 -2
  104. package/src/prompts/ci-green-request.md +5 -3
  105. package/src/prompts/system/project-prompt.md +1 -0
  106. package/src/prompts/tools/ast-edit.md +1 -1
  107. package/src/prompts/tools/ast-grep.md +1 -1
  108. package/src/prompts/tools/read.md +1 -1
  109. package/src/prompts/tools/search.md +1 -1
  110. package/src/sdk.ts +17 -9
  111. package/src/session/agent-session.ts +43 -14
  112. package/src/session/blob-store.ts +96 -9
  113. package/src/session/session-manager.ts +19 -10
  114. package/src/slash-commands/builtin-registry.ts +3 -11
  115. package/src/system-prompt.ts +4 -0
  116. package/src/task/render.ts +38 -11
  117. package/src/tiny/title-client.ts +7 -1
  118. package/src/tool-discovery/mode.ts +24 -0
  119. package/src/tools/archive-reader.ts +339 -31
  120. package/src/tools/bash.ts +18 -8
  121. package/src/tools/browser/render.ts +5 -4
  122. package/src/tools/debug.ts +3 -3
  123. package/src/tools/eval-render.ts +24 -9
  124. package/src/tools/eval.ts +14 -19
  125. package/src/tools/fetch.ts +34 -14
  126. package/src/tools/gh.ts +65 -11
  127. package/src/tools/index.ts +6 -8
  128. package/src/tools/read.ts +65 -19
  129. package/src/tools/render-utils.ts +46 -0
  130. package/src/tools/search-tool-bm25.ts +4 -6
  131. package/src/tools/search.ts +60 -11
  132. package/src/tools/ssh.ts +21 -8
  133. package/src/tools/write.ts +17 -8
  134. package/src/tui/code-cell.ts +19 -4
  135. package/src/tui/hyperlink.ts +42 -7
  136. package/src/tui/output-block.ts +14 -0
  137. package/src/web/search/index.ts +2 -2
  138. package/src/web/search/render.ts +23 -55
  139. package/dist/types/eval/heartbeat.d.ts +0 -45
  140. package/src/eval/__tests__/heartbeat.test.ts +0 -84
  141. package/src/eval/heartbeat.ts +0 -74
  142. /package/dist/types/eval/__tests__/{heartbeat.test.d.ts → bridge-timeout.test.d.ts} +0 -0
@@ -30,6 +30,48 @@ interface BridgeServer {
30
30
  const registrations = new Map<string, PyToolBridgeEntry>();
31
31
  let serverPromise: Promise<BridgeServer> | null = null;
32
32
 
33
+ /**
34
+ * Forward a bridge call to {@link callSessionTool}, but resolve the HTTP request
35
+ * the instant the cell's signal aborts instead of waiting for the tool/subagent
36
+ * to fully tear down.
37
+ *
38
+ * The kernel invokes this bridge with a *blocking* `urllib` request from a
39
+ * worker thread (each `agent()` / `tool.*` call). When the cell is interrupted,
40
+ * `parallel()`'s `ThreadPoolExecutor.__exit__` joins those worker threads
41
+ * (`shutdown(wait=True)`), so they cannot unwind until their `urllib` call
42
+ * returns — i.e. until this handler responds. A host-side `agent()` teardown
43
+ * (aborting nested LLM streams + tools across a wide fan-out) routinely exceeds
44
+ * the kernel's SIGINT escalation window, so the kernel was hard-killed and its
45
+ * persistent state lost while the subagents were still winding down. Responding
46
+ * immediately on abort lets the kernel raise through the blocked call and settle
47
+ * cleanly (preserving state); the already-signaled call keeps tearing down in
48
+ * the background, its eventual result/rejection swallowed.
49
+ */
50
+ async function callSessionToolPromptOnAbort(name: string, args: unknown, entry: PyToolBridgeEntry): Promise<unknown> {
51
+ const call = callSessionTool(name, args, {
52
+ session: entry.toolSession,
53
+ signal: entry.signal,
54
+ emitStatus: entry.emitStatus,
55
+ });
56
+ const signal = entry.signal;
57
+ if (!signal) return await call;
58
+ if (signal.aborted) {
59
+ void call.catch(() => {});
60
+ throw new Error(`bridge call ${JSON.stringify(name)} aborted: eval cell was interrupted`);
61
+ }
62
+ const { promise: aborted, reject } = Promise.withResolvers<never>();
63
+ const onAbort = () => reject(new Error(`bridge call ${JSON.stringify(name)} aborted: eval cell was interrupted`));
64
+ signal.addEventListener("abort", onAbort, { once: true });
65
+ try {
66
+ return await Promise.race([call, aborted]);
67
+ } finally {
68
+ signal.removeEventListener("abort", onAbort);
69
+ // `call` may still be settling (subagent teardown after its own abort);
70
+ // swallow its outcome so an abort-won race can't surface as unhandled.
71
+ void call.catch(() => {});
72
+ }
73
+ }
74
+
33
75
  async function startServer(): Promise<BridgeServer> {
34
76
  const token = crypto.randomUUID();
35
77
  const server = Bun.serve({
@@ -66,11 +108,7 @@ async function startServer(): Promise<BridgeServer> {
66
108
  }
67
109
 
68
110
  try {
69
- const value = await callSessionTool(name, body.args, {
70
- session: entry.toolSession,
71
- signal: entry.signal,
72
- emitStatus: entry.emitStatus,
73
- });
111
+ const value = await callSessionToolPromptOnAbort(name, body.args, entry);
74
112
  return Response.json({ ok: true, value });
75
113
  } catch (err) {
76
114
  return Response.json({
@@ -294,6 +294,9 @@ export class TtsrManager {
294
294
 
295
295
  /** Add a TTSR rule to be monitored. */
296
296
  addRule(rule: Rule): boolean {
297
+ if (!this.#settings.enabled) {
298
+ return false;
299
+ }
297
300
  if (this.#rules.has(rule.name)) {
298
301
  return false;
299
302
  }
@@ -357,6 +360,9 @@ export class TtsrManager {
357
360
  }
358
361
 
359
362
  #matchBuffer(buffer: string, context: TtsrMatchContext): Rule[] {
363
+ if (!this.#settings.enabled) {
364
+ return [];
365
+ }
360
366
  const matches: Rule[] = [];
361
367
  for (const [name, entry] of this.#rules) {
362
368
  if (!this.#canTrigger(name)) {
@@ -433,6 +439,9 @@ export class TtsrManager {
433
439
 
434
440
  /** Check if any TTSR rules are registered. */
435
441
  hasRules(): boolean {
442
+ if (!this.#settings.enabled) {
443
+ return false;
444
+ }
436
445
  return this.#rules.size > 0;
437
446
  }
438
447
 
@@ -12,6 +12,35 @@ async function getHeadTag(api: CustomCommandAPI): Promise<string | undefined> {
12
12
  }
13
13
  }
14
14
 
15
+ async function getCurrentBranch(api: CustomCommandAPI): Promise<string> {
16
+ try {
17
+ return (await git.branch.current(api.cwd)) ?? "HEAD";
18
+ } catch {
19
+ return "HEAD";
20
+ }
21
+ }
22
+
23
+ async function getPushRemote(api: CustomCommandAPI, branch: string): Promise<string | undefined> {
24
+ try {
25
+ return (
26
+ (await git.config.getBranch(api.cwd, branch, "pushRemote")) ??
27
+ (await git.config.getBranch(api.cwd, branch, "remote"))
28
+ );
29
+ } catch {
30
+ return undefined;
31
+ }
32
+ }
33
+
34
+ async function getHeadTagContext(api: CustomCommandAPI): Promise<{ branch: string; headTag?: string; remote: string }> {
35
+ const branch = await getCurrentBranch(api);
36
+ const [headTag, pushRemote] = await Promise.all([getHeadTag(api), getPushRemote(api, branch)]);
37
+ return {
38
+ headTag,
39
+ branch,
40
+ remote: pushRemote ?? "origin",
41
+ };
42
+ }
43
+
15
44
  export class GreenCommand implements CustomCommand {
16
45
  name = "green";
17
46
  description = "Generate a prompt to iterate on CI failures until the branch is green";
@@ -19,7 +48,7 @@ export class GreenCommand implements CustomCommand {
19
48
  constructor(private api: CustomCommandAPI) {}
20
49
 
21
50
  async execute(_args: string[], _ctx: HookCommandContext): Promise<string> {
22
- const headTag = await getHeadTag(this.api);
23
- return prompt.render(ciGreenRequestTemplate, { headTag });
51
+ const { headTag, branch, remote } = await getHeadTagContext(this.api);
52
+ return prompt.render(ciGreenRequestTemplate, { headTag, branch, remote });
24
53
  }
25
54
  }
@@ -354,6 +354,8 @@ export class ExtensionRunner {
354
354
  "ctrl+o": true,
355
355
  "ctrl+t": true,
356
356
  "ctrl+g": true,
357
+ // Default chord for `app.message.followUp` (Windows Terminal can't deliver Ctrl+Enter; #1903).
358
+ "ctrl+q": true,
357
359
  "shift+tab": true,
358
360
  "shift+ctrl+p": true,
359
361
  "alt+enter": true,