@oh-my-pi/pi-coding-agent 15.7.6 → 15.8.2

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 (117) hide show
  1. package/CHANGELOG.md +172 -198
  2. package/dist/types/async/job-manager.d.ts +3 -3
  3. package/dist/types/cli/args.d.ts +1 -0
  4. package/dist/types/cli/claude-trace-cli.d.ts +54 -0
  5. package/dist/types/cli/session-picker.d.ts +10 -3
  6. package/dist/types/cli/update-cli.d.ts +17 -0
  7. package/dist/types/commands/launch.d.ts +3 -0
  8. package/dist/types/config/keybindings.d.ts +10 -1
  9. package/dist/types/config/settings-schema.d.ts +2 -2
  10. package/dist/types/config/settings.d.ts +13 -0
  11. package/dist/types/edit/index.d.ts +6 -0
  12. package/dist/types/edit/streaming.d.ts +8 -0
  13. package/dist/types/eval/concurrency-bridge.d.ts +26 -0
  14. package/dist/types/eval/js/tool-bridge.d.ts +2 -1
  15. package/dist/types/export/ttsr.d.ts +9 -0
  16. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +11 -0
  17. package/dist/types/main.d.ts +5 -0
  18. package/dist/types/mcp/transports/stdio.d.ts +19 -0
  19. package/dist/types/modes/components/custom-editor.d.ts +3 -1
  20. package/dist/types/modes/components/hook-selector.d.ts +3 -0
  21. package/dist/types/modes/components/session-selector.d.ts +32 -5
  22. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  23. package/dist/types/modes/controllers/extension-ui-controller.d.ts +2 -2
  24. package/dist/types/modes/controllers/input-controller.d.ts +1 -0
  25. package/dist/types/modes/interactive-mode.d.ts +9 -2
  26. package/dist/types/modes/types.d.ts +4 -2
  27. package/dist/types/registry/agent-registry.d.ts +1 -1
  28. package/dist/types/sdk.d.ts +2 -2
  29. package/dist/types/session/agent-session.d.ts +4 -2
  30. package/dist/types/session/history-storage.d.ts +16 -1
  31. package/dist/types/session/session-manager.d.ts +4 -0
  32. package/dist/types/task/output-manager.d.ts +6 -15
  33. package/dist/types/tools/find.d.ts +0 -9
  34. package/dist/types/tools/index.d.ts +1 -1
  35. package/dist/types/tools/path-utils.d.ts +16 -0
  36. package/dist/types/tools/sqlite-reader.d.ts +25 -8
  37. package/dist/types/tools/write.d.ts +2 -0
  38. package/dist/types/utils/clipboard.d.ts +4 -0
  39. package/dist/types/utils/jj.d.ts +49 -0
  40. package/dist/types/web/kagi.d.ts +76 -0
  41. package/dist/types/web/search/providers/exa.d.ts +7 -1
  42. package/dist/types/web/search/providers/kagi.d.ts +1 -0
  43. package/package.json +9 -9
  44. package/src/async/job-manager.ts +3 -3
  45. package/src/cli/args.ts +6 -2
  46. package/src/cli/claude-trace-cli.ts +783 -0
  47. package/src/cli/session-picker.ts +36 -10
  48. package/src/cli/update-cli.ts +35 -2
  49. package/src/commands/launch.ts +3 -0
  50. package/src/config/keybindings.ts +14 -1
  51. package/src/config/model-registry.ts +18 -7
  52. package/src/config/settings-schema.ts +2 -2
  53. package/src/config/settings.ts +23 -0
  54. package/src/discovery/builtin-rules/index.ts +2 -0
  55. package/src/discovery/builtin-rules/ts-no-deprecated-leftovers.md +44 -0
  56. package/src/discovery/claude-plugins.ts +7 -9
  57. package/src/edit/index.ts +10 -0
  58. package/src/edit/streaming.ts +65 -0
  59. package/src/eval/__tests__/agent-bridge.test.ts +58 -4
  60. package/src/eval/concurrency-bridge.ts +34 -0
  61. package/src/eval/js/shared/prelude.txt +20 -17
  62. package/src/eval/js/tool-bridge.ts +5 -0
  63. package/src/eval/py/prelude.py +23 -15
  64. package/src/export/ttsr.ts +18 -1
  65. package/src/extensibility/custom-commands/bundled/review/index.ts +74 -45
  66. package/src/extensibility/plugins/legacy-pi-compat.ts +115 -131
  67. package/src/extensibility/skills.ts +0 -1
  68. package/src/internal-urls/docs-index.generated.ts +12 -11
  69. package/src/main.ts +92 -24
  70. package/src/mcp/transports/stdio.ts +55 -22
  71. package/src/modes/acp/acp-event-mapper.ts +54 -4
  72. package/src/modes/components/custom-editor.ts +10 -0
  73. package/src/modes/components/hook-selector.ts +89 -31
  74. package/src/modes/components/oauth-selector.ts +12 -6
  75. package/src/modes/components/session-selector.ts +179 -24
  76. package/src/modes/components/tool-execution.ts +16 -3
  77. package/src/modes/controllers/command-controller.ts +2 -11
  78. package/src/modes/controllers/extension-ui-controller.ts +3 -2
  79. package/src/modes/controllers/input-controller.ts +19 -1
  80. package/src/modes/controllers/selector-controller.ts +61 -21
  81. package/src/modes/interactive-mode.ts +125 -15
  82. package/src/modes/types.ts +5 -2
  83. package/src/prompts/agents/reviewer.md +2 -2
  84. package/src/prompts/review-request.md +1 -1
  85. package/src/prompts/system/empty-stop-retry.md +6 -0
  86. package/src/prompts/system/orchestrate-notice.md +5 -3
  87. package/src/prompts/system/workflow-notice.md +2 -2
  88. package/src/prompts/tools/eval.md +5 -5
  89. package/src/prompts/tools/find.md +1 -1
  90. package/src/prompts/tools/irc.md +6 -6
  91. package/src/prompts/tools/search-tool-bm25.md +9 -2
  92. package/src/prompts/tools/search.md +1 -1
  93. package/src/prompts/tools/task.md +1 -1
  94. package/src/registry/agent-registry.ts +1 -1
  95. package/src/sdk.ts +85 -31
  96. package/src/session/agent-session.ts +209 -54
  97. package/src/session/history-storage.ts +56 -12
  98. package/src/session/session-manager.ts +34 -0
  99. package/src/task/output-manager.ts +40 -48
  100. package/src/task/render.ts +3 -8
  101. package/src/tools/browser/tab-worker.ts +8 -5
  102. package/src/tools/find.ts +5 -29
  103. package/src/tools/index.ts +1 -1
  104. package/src/tools/path-utils.ts +144 -1
  105. package/src/tools/read.ts +47 -0
  106. package/src/tools/search-tool-bm25.ts +7 -1
  107. package/src/tools/search.ts +2 -27
  108. package/src/tools/sqlite-reader.ts +92 -9
  109. package/src/tools/write.ts +6 -0
  110. package/src/utils/clipboard.ts +38 -1
  111. package/src/utils/git.ts +19 -23
  112. package/src/utils/jj.ts +225 -0
  113. package/src/utils/open.ts +37 -2
  114. package/src/web/kagi.ts +168 -49
  115. package/src/web/search/providers/anthropic.ts +1 -1
  116. package/src/web/search/providers/exa.ts +20 -86
  117. package/src/web/search/providers/kagi.ts +4 -0
@@ -9,8 +9,8 @@ export interface AsyncJob {
9
9
  resultText?: string;
10
10
  errorText?: string;
11
11
  /**
12
- * Registry id of the agent that registered the job (e.g. "0-Main",
13
- * "3-AuthLoader"). Used by scoped cancel/list APIs so a subagent's teardown
12
+ * Registry id of the agent that registered the job (e.g. "Main",
13
+ * "AuthLoader"). Used by scoped cancel/list APIs so a subagent's teardown
14
14
  * does not cancel its parent's jobs. Undefined for callers that don't
15
15
  * supply an id (e.g. legacy tests, SDK consumers without an agent context).
16
16
  */
@@ -36,7 +36,7 @@ export interface AsyncJobRegisterOptions {
36
36
  /**
37
37
  * Filter applied to job query/cancel APIs. With `ownerId`, results are
38
38
  * restricted to jobs registered by that agent (registry id from
39
- * `AgentRegistry`, e.g. "0-Main", "3-AuthLoader").
39
+ * `AgentRegistry`, e.g. "Main", "AuthLoader").
40
40
  */
41
41
  export interface AsyncJobFilter {
42
42
  ownerId?: string;
@@ -15,6 +15,7 @@ export interface Args {
15
15
  systemPrompt?: string;
16
16
  appendSystemPrompt?: string;
17
17
  thinking?: Effort;
18
+ hideThinking?: boolean;
18
19
  continue?: boolean;
19
20
  resume?: string | true;
20
21
  help?: boolean;
@@ -0,0 +1,54 @@
1
+ export declare const CLAUDE_TRACE_DEBUG_CERT = "-----BEGIN CERTIFICATE-----\nMIIDFzCCAf+gAwIBAgIUAe9omAqLbydZc5ZYZGhwbbpMSF0wDQYJKoZIhvcNAQEL\nBQAwGzEZMBcGA1UEAwwQb21wLWNsYXVkZS10cmFjZTAeFw0yNjA2MDIwODA2MjFa\nFw0zNjA1MzAwODA2MjFaMBsxGTAXBgNVBAMMEG9tcC1jbGF1ZGUtdHJhY2UwggEi\nMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmpGe5T8B0oA2L82Rn5JJdXOBS\nZX0DyBjiIK+Tqe8T3oAr41XDLnweqtrMDSBDYbVqAoKjNbaTUSYYcxSm0MAVs63w\n08SfJmShZM9pElfANqXqMiyhksFgji7JEyt/rbbId207a7s5KvRvm3g/sxN/wGtr\nC5LCLMlc2GWEGD8qrVIQbmLw884qvtXi70RFUPP3Wpy4wGMWSdE+9IA27R5cMJS5\noHsO4HGB6J8VzLY+HGY2yr4BJ9qrAyjd1UetFd9RdcjyWpsbAfX8nWP+uleTNOiT\nExNz7dPt/k6OPLNmI1iT/ruRS0uUzHZTimPd67TPQR/70RaW7Bh5wArawGw9AgMB\nAAGjUzBRMB0GA1UdDgQWBBQa4Ir8P3GAolZoPiuB4V2cq3riAjAfBgNVHSMEGDAW\ngBQa4Ir8P3GAolZoPiuB4V2cq3riAjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\nDQEBCwUAA4IBAQClPYki235gDEUu7eDm60qsAGWxbKVv4pSh+vB+xgNgzMk4aOuU\nmSfp8Y8covwklph8VfDoKTaEGqqX0Q5s74Ctl6Mwy7b0u8Zztk/g4GynLocI7TQD\nftZMgZka49+FkEsjp+XZtQbO4vOL5UsccpsLhFQQQuhVyiJ4gNo/VzgvSDkBuf3Q\nRz7xFiDKCqFEoMPty4+nKEw5832FJ5mDCOyMk6fGSO8Wbt/hmRQQFu2cSdoBs0OT\nAQQJETQjPkKeTDX4jdSAlOeKwfyjfdfgeQuMkzX8xafisJa66MLPzOVbIuGbvbWD\nQVCd76iYPcfNK+JZUhmAUvTHSuwgJMZ6+NgI\n-----END CERTIFICATE-----";
2
+ export declare const CLAUDE_TRACE_DEBUG_KEY = "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCmpGe5T8B0oA2L\n82Rn5JJdXOBSZX0DyBjiIK+Tqe8T3oAr41XDLnweqtrMDSBDYbVqAoKjNbaTUSYY\ncxSm0MAVs63w08SfJmShZM9pElfANqXqMiyhksFgji7JEyt/rbbId207a7s5KvRv\nm3g/sxN/wGtrC5LCLMlc2GWEGD8qrVIQbmLw884qvtXi70RFUPP3Wpy4wGMWSdE+\n9IA27R5cMJS5oHsO4HGB6J8VzLY+HGY2yr4BJ9qrAyjd1UetFd9RdcjyWpsbAfX8\nnWP+uleTNOiTExNz7dPt/k6OPLNmI1iT/ruRS0uUzHZTimPd67TPQR/70RaW7Bh5\nwArawGw9AgMBAAECggEADX2mhA3H0pPuj35J36X/5Me9xWM//AwOr6febwGalazg\nCtg3EOZ01/VptzaiKQetAdhoLmxidooNn9HD7JQJKPid7q7w7m1+R26mN/xrLD2A\nWyBqv+iQoo+ANs5y1BMChuIxmVY/FwFk6UWDNlekuXqgzPln4okbrYTmBbaszniO\nMu1SI/3fpnTA3iJ634FUSRVoUPP8r0WEEUtpW1wAhsJR701gvKRYw/+YcRglkhm7\nT4l6TuBcgIVzUqAc3oZLHVIMKN0ZprZSeopSRozTcUANfYONakvK9Hx1qf+/rmTR\nqZHg2uOxlqvxyABnwdk8rmyFx8YqUeN9jaAbbXxtBQKBgQDQRjc0gVg4STqcFqUu\nFW35MZ88S7+xTuRd/EG1dpsu2lptx1yhSLTsF5GfxBQKXCQUfWrpkyuCmlV6s+wJ\nH0LSyAJQ4ffBsFterQz7dRKTlhRJNk5PYn8jjNCAuBYVSbQZqZ3yZgG3CT3G5+PZ\n8Ln3tJHqTRfP5B8KTMcNYiLI0wKBgQDM0/gdb9Dvdz/32GIpxwNNIb52IxnNVVrm\nM69+4XNg6CqvctZFuaMQ03W2J5IKAdESaCGLz9pwHZRjfBORcw3BPKD2QkfN5NJg\nhWvLlfAsblCYiCCjTCB6rf1OJOQ5fHoNFh1wqDaQCk0flsb9nlZmQQR5ZUHaJhSC\nQqMmeKvMrwKBgQDDzp+sH0Z/dGlDwg59auw/caWRHG4WFmOg8L4eCmoO/H4z41B0\n2VQu+mGQYNmue733/Yl8Gz62xL5EY88vLFK4tA1pWWiCknj0Y6Fm70QNuPVNd17c\nR2/cTlDgEzG/xdEqp0q1T62hFXEdBXoztZxBA2SDcQNIEeIU3uXs8SxevQKBgFp4\nacf+wody4aNERR900sV32RtvJ49lWxAA1kwxone0NF5oV7JWa2scK4r4cW3QHZuG\nuQJ7HV2WAxvqCu6cpf+rGuGKpxKPNkkBxXoX0Qye8SReRCQ8lL/7J74jV1b43yP2\nl6xR8D+w/R2tyFjvXfQuVZ6VFgAX/8kFS/DLLf7rAoGAcnFgCwyzcq6FWL8iW23J\nGnbZ0IQk6SPch87MzMmnOFlEXrCf5l832vwI65tNzOoB0yQoWVfBv5sb4Zy9zeFj\nFbkpRZC0Kfi9PLzDV4IawoIINYthOJxIKJg+yrmrUWCggXxwdzYIYKLRIskMXoYs\nmNMXfUstElEcKO7+DKiPi6U=\n-----END PRIVATE KEY-----";
3
+ export interface HeaderEntry {
4
+ name: string;
5
+ value: string;
6
+ }
7
+ export interface CapturedRequest {
8
+ method: string;
9
+ path: string;
10
+ version: string;
11
+ headers: HeaderEntry[];
12
+ body: string;
13
+ }
14
+ export interface CapturedResponse {
15
+ statusCode: number | undefined;
16
+ statusMessage: string;
17
+ version: string;
18
+ headers: HeaderEntry[];
19
+ body: string;
20
+ }
21
+ export interface CapturedMessagesExchange {
22
+ target: string;
23
+ request: CapturedRequest;
24
+ response: CapturedResponse;
25
+ }
26
+ export interface ClaudeMessagesProxyOptions {
27
+ host?: string;
28
+ port?: number;
29
+ upstreamTlsRejectUnauthorized?: boolean;
30
+ }
31
+ export interface ClaudeTraceCommandArgs {
32
+ command?: string;
33
+ message?: string;
34
+ cwd?: string;
35
+ host?: string;
36
+ port?: number;
37
+ timeoutMs?: number;
38
+ inputDelayMs?: number;
39
+ json?: boolean;
40
+ upstreamTlsRejectUnauthorized?: boolean;
41
+ }
42
+ export declare function formatCapturedMessagesExchange(exchange: CapturedMessagesExchange): string;
43
+ export declare class ClaudeMessagesProxy {
44
+ #private;
45
+ constructor(options?: ClaudeMessagesProxyOptions);
46
+ get host(): string;
47
+ get port(): number;
48
+ get url(): string;
49
+ start(): Promise<void>;
50
+ stop(): Promise<void>;
51
+ waitForCapture(timeoutMs: number): Promise<CapturedMessagesExchange>;
52
+ }
53
+ export declare function runClaudeMessagesCapture(args?: ClaudeTraceCommandArgs): Promise<CapturedMessagesExchange>;
54
+ export declare function runClaudeTraceCommand(args?: ClaudeTraceCommandArgs): Promise<void>;
@@ -1,3 +1,10 @@
1
- import type { SessionInfo } from "../session/session-manager";
2
- /** Show TUI session selector and return selected session path or null if cancelled */
3
- export declare function selectSession(sessions: SessionInfo[]): Promise<string | null>;
1
+ import { type SessionInfo } from "../session/session-manager";
2
+ /**
3
+ * Show the TUI session selector and return the selected session, or null if
4
+ * cancelled. Tab toggles between current-folder and all-projects scope; the
5
+ * all-projects list is loaded lazily via `SessionManager.listAll`.
6
+ */
7
+ export declare function selectSession(sessions: SessionInfo[], options?: {
8
+ allSessions?: SessionInfo[];
9
+ startInAllScope?: boolean;
10
+ }): Promise<SessionInfo | null>;
@@ -25,6 +25,23 @@ export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: s
25
25
  * Atomically replace the installed binary and roll back if version verification fails.
26
26
  */
27
27
  export declare function replaceBinaryForUpdate(options: BinaryReplacementOptions): Promise<InstalledVersionVerification>;
28
+ /**
29
+ * Build the bun argv used to globally install a specific omp version.
30
+ *
31
+ * The version is selected by hitting {@link NPM_REGISTRY} directly in
32
+ * {@link getLatestRelease}, so the install MUST observe the same catalog:
33
+ *
34
+ * - `--registry=${NPM_REGISTRY}` pins the install to the official registry
35
+ * regardless of the user's bunfig/`.npmrc`. A mirror (corporate proxy,
36
+ * Taobao, …) that hasn't yet replicated the release would otherwise reject
37
+ * a version the upstream registry already advertises.
38
+ * - `--no-cache` tells bun to ignore its on-disk manifest snapshot so it
39
+ * re-fetches metadata from that registry on every invocation.
40
+ *
41
+ * Together these two flags make `omp update` produce exactly the registry
42
+ * lookup the version check just performed. See #1686.
43
+ */
44
+ export declare function buildBunInstallArgs(expectedVersion: string): string[];
28
45
  /**
29
46
  * Run the update command.
30
47
  */
@@ -81,6 +81,9 @@ export default class Index extends Command {
81
81
  description: string;
82
82
  options: import("@oh-my-pi/pi-ai").Effort[];
83
83
  };
84
+ "hide-thinking": import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
85
+ description: string;
86
+ };
84
87
  hook: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"string"> & {
85
88
  description: string;
86
89
  multiple: true;
@@ -19,6 +19,7 @@ interface AppKeybindings {
19
19
  "app.message.followUp": true;
20
20
  "app.message.dequeue": true;
21
21
  "app.clipboard.pasteImage": true;
22
+ "app.clipboard.pasteTextRaw": true;
22
23
  "app.clipboard.copyLine": true;
23
24
  "app.clipboard.copyPrompt": true;
24
25
  "app.session.new": true;
@@ -42,6 +43,10 @@ declare module "@oh-my-pi/pi-tui" {
42
43
  interface Keybindings extends AppKeybindings {
43
44
  }
44
45
  }
46
+ /**
47
+ * Resolve default image-paste shortcuts for the current terminal platform.
48
+ */
49
+ export declare function getDefaultPasteImageKeys(platform?: NodeJS.Platform): KeyId[];
45
50
  /**
46
51
  * All keybindings definitions: TUI + app-specific.
47
52
  */
@@ -227,9 +232,13 @@ export declare const KEYBINDINGS: {
227
232
  readonly description: "Dequeue message";
228
233
  };
229
234
  readonly "app.clipboard.pasteImage": {
230
- readonly defaultKeys: "alt+v" | "ctrl+v";
235
+ readonly defaultKeys: KeyId[];
231
236
  readonly description: "Paste image from clipboard";
232
237
  };
238
+ readonly "app.clipboard.pasteTextRaw": {
239
+ readonly defaultKeys: ["ctrl+shift+v", "alt+shift+v"];
240
+ readonly description: "Paste text from clipboard as raw text (no collapse)";
241
+ };
233
242
  readonly "app.clipboard.copyLine": {
234
243
  readonly defaultKeys: "alt+shift+l";
235
244
  readonly description: "Copy current line";
@@ -3281,7 +3281,7 @@ export declare const SETTINGS_SCHEMA: {
3281
3281
  }, {
3282
3282
  readonly value: "exa";
3283
3283
  readonly label: "Exa";
3284
- readonly description: "Uses Exa API when EXA_API_KEY is set; falls back to Exa MCP";
3284
+ readonly description: "Requires EXA_API_KEY";
3285
3285
  }, {
3286
3286
  readonly value: "brave";
3287
3287
  readonly label: "Brave";
@@ -3321,7 +3321,7 @@ export declare const SETTINGS_SCHEMA: {
3321
3321
  }, {
3322
3322
  readonly value: "kagi";
3323
3323
  readonly label: "Kagi";
3324
- readonly description: "Requires KAGI_API_KEY and Kagi Search API beta access";
3324
+ readonly description: "Requires KAGI_API_KEY (Kagi V1 Search API)";
3325
3325
  }, {
3326
3326
  readonly value: "synthetic";
3327
3327
  readonly label: "Synthetic";
@@ -74,6 +74,19 @@ export declare class Settings {
74
74
  */
75
75
  flush(): Promise<void>;
76
76
  cloneForCwd(cwd: string): Promise<Settings>;
77
+ /**
78
+ * Re-scope this instance to a new working directory *in place*: reload the
79
+ * project layer (`.claude/settings.yml` etc.) from `cwd`, re-resolve
80
+ * path-scoped settings against it, and re-fire side-effect hooks (theme,
81
+ * symbols, tab width, …). Global settings and runtime overrides are preserved.
82
+ *
83
+ * Unlike {@link cloneForCwd}, this mutates the live instance, so every holder
84
+ * (the `settings` proxy, the active session, controllers) observes the new
85
+ * project scope without swapping references — used when the process changes
86
+ * directory mid-run (`/move`, cross-project resume). No-op when `cwd` is
87
+ * already the current scope.
88
+ */
89
+ reloadForCwd(cwd: string): Promise<void>;
77
90
  getStorage(): AgentStorage | null;
78
91
  getCwd(): string;
79
92
  getAgentDir(): string;
@@ -52,5 +52,11 @@ export declare class EditTool implements AgentTool<TInput> {
52
52
  * internal `name` and `customWireName`, so returned calls route correctly.
53
53
  */
54
54
  get customWireName(): string | undefined;
55
+ /**
56
+ * Normalize streamed args into the source text this edit introduces, so
57
+ * stream matchers (TTSR rules) run against real file content instead of the
58
+ * mode-specific patch grammar.
59
+ */
60
+ matcherDigest(args: unknown): string | undefined;
55
61
  execute(_toolCallId: string, params: EditParams, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<EditToolDetails, TInput>, context?: AgentToolContext): Promise<AgentToolResult<EditToolDetails, TInput>>;
56
62
  }
@@ -52,6 +52,14 @@ export interface EditStreamingStrategy<Args = unknown> {
52
52
  * compute returned `null` because args are still too partial).
53
53
  */
54
54
  renderStreamingFallback(args: Args, uiTheme: Theme): string;
55
+ /**
56
+ * Project the (potentially partial) args onto the plain text the edit
57
+ * introduces into files — added lines without patch grammar — so stream
58
+ * matchers (TTSR rules) can run source-level patterns against real content
59
+ * instead of the mode-specific wire format. Returns `undefined` when the
60
+ * args don't yet carry any content.
61
+ */
62
+ matcherDigest(args: Args): string | undefined;
55
63
  }
56
64
  /**
57
65
  * Given an edits array parsed from partial JSON, drop the last entry when the
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Host-side handler for the eval `parallel()` / `pipeline()` worker pool.
3
+ *
4
+ * The pool ceiling is not a kernel-side knob: it tracks the `task.maxConcurrency`
5
+ * setting so an eval fan-out runs as wide as a `task` tool batch would. `0` means
6
+ * unbounded — run every item at once, exactly like `task.maxConcurrency = 0`.
7
+ */
8
+ import type { ToolSession } from "../tools";
9
+ import type { JsStatusEvent } from "./js/shared/types";
10
+ /** Synthetic bridge name reserved for the parallel-pool ceiling across both runtimes. */
11
+ export declare const EVAL_CONCURRENCY_BRIDGE_NAME = "__concurrency__";
12
+ export interface EvalConcurrencyBridgeOptions {
13
+ session: ToolSession;
14
+ signal?: AbortSignal;
15
+ emitStatus?: (event: JsStatusEvent) => void;
16
+ }
17
+ export interface EvalConcurrencyResult {
18
+ /** Worker-pool ceiling; `0` means unbounded (run every item at once). */
19
+ limit: number;
20
+ }
21
+ /**
22
+ * Resolve the worker-pool ceiling for an eval cell's `parallel()`/`pipeline()`
23
+ * helpers from the live `task.maxConcurrency` setting. Negative/non-finite
24
+ * values collapse to `0` (unbounded), matching the `task` tool's own handling.
25
+ */
26
+ export declare function runEvalConcurrency(_args: unknown, options: EvalConcurrencyBridgeOptions): EvalConcurrencyResult;
@@ -1,5 +1,6 @@
1
1
  import type { ToolSession } from "../../tools";
2
2
  import { type EvalBudgetResult } from "../budget-bridge";
3
+ import { type EvalConcurrencyResult } from "../concurrency-bridge";
3
4
  import type { JsStatusEvent } from "./shared/types";
4
5
  export type { JsStatusEvent } from "./shared/types";
5
6
  interface ToolBridgeOptions {
@@ -7,7 +8,7 @@ interface ToolBridgeOptions {
7
8
  signal?: AbortSignal;
8
9
  emitStatus?: (event: JsStatusEvent) => void;
9
10
  }
10
- type ToolValue = string | EvalBudgetResult | {
11
+ type ToolValue = string | EvalBudgetResult | EvalConcurrencyResult | {
11
12
  text: string;
12
13
  details?: unknown;
13
14
  images?: Array<{
@@ -23,6 +23,15 @@ export declare class TtsrManager {
23
23
  * assistant prose, thinking text, and unrelated tool argument streams.
24
24
  */
25
25
  checkDelta(delta: string, context: TtsrMatchContext): Rule[];
26
+ /**
27
+ * Replace the scoped buffer with a tool-provided normalized snapshot and
28
+ * return matching rules.
29
+ *
30
+ * Used for tools exposing `matcherDigest`: the digest is recomputed from the
31
+ * full (partial) arguments on every delta, so it replaces the buffer instead
32
+ * of being appended to it.
33
+ */
34
+ checkSnapshot(snapshot: string, context: TtsrMatchContext): Rule[];
26
35
  /** Mark rules as injected (won't trigger again until conditions allow). */
27
36
  markInjected(rulesToMark: Rule[]): void;
28
37
  /** Mark rule names as injected (won't trigger again until conditions allow). */
@@ -13,6 +13,17 @@ import * as path from "node:path";
13
13
  * Exported for tests; production callers use `BUNFS_PACKAGE_ROOT` below.
14
14
  */
15
15
  export declare function __computeBunfsPackageRoot(metaDir: string, pathImpl?: typeof path): string;
16
+ /**
17
+ * Load a legacy Pi extension module from its real on-disk location.
18
+ *
19
+ * The extension runs in place, so its `import.meta.url` is the real source file
20
+ * and `__dirname`-relative `readFileSync` asset loads (HTML/CSS bundled next to
21
+ * the entry) resolve exactly as they do under the original Pi runtime — no
22
+ * temp-directory mirroring and no asset copying. An `onLoad` hook scoped to the
23
+ * entry's relative-import graph rewrites only the legacy `@(scope)/pi-*` and
24
+ * `@sinclair/typebox` imports in the extension's own source; everything else
25
+ * resolves natively.
26
+ */
16
27
  export declare function loadLegacyPiModule(resolvedPath: string): Promise<unknown>;
17
28
  export declare function installLegacyPiSpecifierShim(): void;
18
29
  /** Test seam: clears the memoized canonical specifier resolutions. */
@@ -12,6 +12,7 @@ import type { SubmittedUserInput } from "./modes/types";
12
12
  import { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession, discoverAuthStorage } from "./sdk";
13
13
  import type { AgentSession } from "./session/agent-session";
14
14
  import type { AuthStorage } from "./session/auth-storage";
15
+ import { type SessionInfo, SessionManager } from "./session/session-manager";
15
16
  export interface InteractiveModeNotify {
16
17
  kind: "warn" | "error" | "info";
17
18
  message: string;
@@ -39,6 +40,10 @@ export interface AcpSessionFactoryOptions {
39
40
  * tool registry and shadow the client-supplied servers (issue #1234).
40
41
  */
41
42
  export declare function createAcpSessionFactory(args: AcpSessionFactoryOptions): AcpSessionFactory;
43
+ type ForkSessionPromptResult = "accepted" | "declined" | "unavailable";
44
+ type ForkSessionPrompt = (session: SessionInfo) => Promise<ForkSessionPromptResult>;
45
+ /** Resolves CLI session flags into an existing, forked, in-memory, or cancelled session manager. */
46
+ export declare function createSessionManager(parsed: Args, cwd: string, activeSettings?: Settings, askToForkSession?: ForkSessionPrompt): Promise<SessionManager | undefined>;
42
47
  interface RunRootCommandDependencies {
43
48
  createAgentSession?: typeof createAgentSession;
44
49
  discoverAuthStorage?: typeof discoverAuthStorage;
@@ -5,6 +5,24 @@
5
5
  * Messages are newline-delimited JSON.
6
6
  */
7
7
  import type { MCPRequestOptions, MCPStdioServerConfig, MCPTransport } from "../../mcp/types";
8
+ /** Minimal write surface of `Subprocess.stdin` we need for framed sends. */
9
+ interface FrameSink {
10
+ write(chunk: string): unknown;
11
+ flush(): unknown;
12
+ }
13
+ /**
14
+ * Write a newline-delimited JSON-RPC frame to the subprocess's stdin sink,
15
+ * swallowing synchronous errors so the caller can decide how to react.
16
+ *
17
+ * Bun's `FileSink` may throw synchronously (most reliably on Windows) when
18
+ * the read end of the pipe has been closed by a subprocess that exited
19
+ * between read-loop ticks. Letting that throw escape an `async` method
20
+ * surfaces as an unhandled promise rejection at the call site.
21
+ *
22
+ * Returns `true` when the frame was accepted by the sink, `false` when the
23
+ * sink threw — callers signal transport closure on `false`.
24
+ */
25
+ export declare function writeFrame(stdin: FrameSink, frame: string): boolean;
8
26
  /**
9
27
  * Stdio transport for MCP servers.
10
28
  * Spawns a subprocess and communicates via stdin/stdout.
@@ -30,3 +48,4 @@ export declare class StdioTransport implements MCPTransport {
30
48
  * Create and connect a stdio transport.
31
49
  */
32
50
  export declare function createStdioTransport(config: MCPStdioServerConfig): Promise<StdioTransport>;
51
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { Editor, type KeyId } from "@oh-my-pi/pi-tui";
2
2
  import type { AppKeybinding } from "../../config/keybindings";
3
- type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.clipboard.pasteImage" | "app.clipboard.copyPrompt">;
3
+ type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
4
4
  /**
5
5
  * Custom editor that handles configurable app-level shortcuts for coding-agent.
6
6
  */
@@ -26,6 +26,8 @@ export declare class CustomEditor extends Editor {
26
26
  onCopyPrompt?: () => void;
27
27
  /** Called when the configured image-paste shortcut is pressed. */
28
28
  onPasteImage?: () => Promise<boolean>;
29
+ /** Called when the configured raw text-paste shortcut is pressed. */
30
+ onPasteTextRaw?: () => void;
29
31
  /** Called when the configured dequeue shortcut is pressed. */
30
32
  onDequeue?: () => void;
31
33
  /** Called when Caps Lock is pressed. */
@@ -41,6 +41,9 @@ export interface HookSelectorOptions {
41
41
  onExternalEditor?: () => void;
42
42
  helpText?: string;
43
43
  slider?: HookSelectorSlider;
44
+ /** Indices into the original options that cannot be selected: they render
45
+ * dimmed, are skipped during navigation, and reject enter/timeout. */
46
+ disabledIndices?: readonly number[];
44
47
  }
45
48
  export interface HookSelectorOption {
46
49
  label: string;
@@ -1,28 +1,55 @@
1
1
  import { type Component, Container } from "@oh-my-pi/pi-tui";
2
2
  import type { SessionInfo } from "../../session/session-manager";
3
+ /** Returns the IDs of sessions whose recorded prompts match a query, best first. */
4
+ export type SessionHistoryMatcher = (query: string) => string[];
5
+ /**
6
+ * Combine fuzzy session matches with prompt-history matches for ranking, using
7
+ * both signals rather than replacing one with the other.
8
+ *
9
+ * - `fuzzy` is the ordered fuzzy-filter result over session metadata (best first).
10
+ * - `historyIds` are session IDs whose recorded prompts matched the query,
11
+ * ordered by history relevance (best first); duplicates are tolerated.
12
+ *
13
+ * Ranking: sessions matched by **both** signals lead (keeping fuzzy order), then
14
+ * fuzzy-only matches, then history-only matches (by history order). A fuzzy match
15
+ * is never dropped, and history matches not present in `allSessions` (e.g. deleted
16
+ * or out-of-scope sessions) are ignored since they cannot be resumed from here.
17
+ */
18
+ export declare function mergeSessionRanking(allSessions: SessionInfo[], fuzzy: SessionInfo[], historyIds: string[]): SessionInfo[];
3
19
  /**
4
20
  * Custom session list component with multi-line items and search
5
21
  */
6
22
  declare class SessionList implements Component {
7
23
  #private;
8
- private readonly allSessions;
9
- private readonly showCwd;
10
- onSelect?: (sessionPath: string) => void;
24
+ onSelect?: (session: SessionInfo) => void;
11
25
  onCancel?: () => void;
12
26
  onExit: () => void;
27
+ onToggleScope?: () => void;
13
28
  onDeleteRequest?: (session: SessionInfo) => void;
14
- constructor(allSessions: SessionInfo[], showCwd?: boolean);
29
+ constructor(sessions: SessionInfo[], showCwd?: boolean, historyMatcher?: SessionHistoryMatcher);
30
+ /** Replace the visible dataset, e.g. when toggling folder/all-projects scope. */
31
+ setSessions(sessions: SessionInfo[], showCwd: boolean): void;
15
32
  removeSession(sessionPath: string): void;
16
33
  invalidate(): void;
17
34
  render(width: number): string[];
18
35
  handleInput(keyData: string): void;
19
36
  }
37
+ export interface SessionSelectorOptions {
38
+ onDelete?: (session: SessionInfo) => Promise<boolean>;
39
+ historyMatcher?: SessionHistoryMatcher;
40
+ /** Loads sessions across all projects for the all-projects scope toggle (Tab). */
41
+ loadAllSessions?: () => Promise<SessionInfo[]>;
42
+ /** Preloaded all-projects list; cached so the first Tab toggle is instant. */
43
+ allSessions?: SessionInfo[];
44
+ /** Open directly in all-projects scope (e.g. the current folder has no sessions). */
45
+ startInAllScope?: boolean;
46
+ }
20
47
  /**
21
48
  * Component that renders a session selector with optional confirmation dialog
22
49
  */
23
50
  export declare class SessionSelectorComponent extends Container {
24
51
  #private;
25
- constructor(sessions: SessionInfo[], onSelect: (sessionPath: string) => void, onCancel: () => void, onExit: () => void, onDelete?: (session: SessionInfo) => Promise<boolean>);
52
+ constructor(sessions: SessionInfo[], onSelect: (session: SessionInfo) => void, onCancel: () => void, onExit: () => void, options?: SessionSelectorOptions);
26
53
  setOnRequestRender(callback: () => void): void;
27
54
  handleInput(keyData: string): void;
28
55
  getSessionList(): SessionList;
@@ -34,6 +34,14 @@ export declare class ToolExecutionComponent extends Container {
34
34
  * This triggers an immediate final diff computation for edit-like tools.
35
35
  */
36
36
  setArgsComplete(_toolCallId?: string): void;
37
+ /**
38
+ * Await the streaming diff recompute kicked off by the most recent
39
+ * `updateArgs`/`setArgsComplete`. The recompute reads the file and re-runs the
40
+ * whole-file Myers diff off the render path, signalling completion only via a
41
+ * throttled `requestRender`. Tests await this to sample a *settled* preview
42
+ * deterministically instead of racing the spinner's render ticks.
43
+ */
44
+ whenPreviewSettled(): Promise<void>;
37
45
  updateResult(result: {
38
46
  content: Array<{
39
47
  type: string;
@@ -3,7 +3,7 @@ import { KeybindingsManager } from "../../config/keybindings";
3
3
  import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions, TerminalInputHandler } from "../../extensibility/extensions";
4
4
  import { type HookSelectorSlider } from "../../modes/components/hook-selector";
5
5
  import { type Theme } from "../../modes/theme/theme";
6
- import type { InteractiveModeContext } from "../../modes/types";
6
+ import type { InteractiveModeContext, InteractiveSelectorDialogOptions } from "../../modes/types";
7
7
  export declare class ExtensionUiController {
8
8
  #private;
9
9
  private ctx;
@@ -30,7 +30,7 @@ export declare class ExtensionUiController {
30
30
  /**
31
31
  * Show a selector for hooks.
32
32
  */
33
- showHookSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: ExtensionUIDialogOptions, extra?: {
33
+ showHookSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: InteractiveSelectorDialogOptions, extra?: {
34
34
  slider?: HookSelectorSlider;
35
35
  }): Promise<string | undefined>;
36
36
  /**
@@ -18,6 +18,7 @@ export declare class InputController {
18
18
  }): number;
19
19
  handleBackgroundCommand(): void;
20
20
  handleImagePaste(): Promise<boolean>;
21
+ handleClipboardTextRawPaste(): Promise<void>;
21
22
  createAutocompleteProvider(commands: SlashCommand[], basePath: string): AutocompleteProvider;
22
23
  /** Copy the current editor line to the system clipboard. */
23
24
  handleCopyCurrentLine(): void;
@@ -26,7 +26,7 @@ import type { ToolExecutionHandle } from "./components/tool-execution";
26
26
  import { type LoopLimitRuntime } from "./loop-limit";
27
27
  import { OAuthManualInputManager } from "./oauth-manual-input";
28
28
  import type { Theme } from "./theme/theme";
29
- import type { CompactionQueuedMessage, InteractiveModeContext, InteractiveModeInitOptions, SubmittedUserInput, TodoItem, TodoPhase } from "./types";
29
+ import type { CompactionQueuedMessage, InteractiveModeContext, InteractiveModeInitOptions, InteractiveSelectorDialogOptions, SubmittedUserInput, TodoItem, TodoPhase } from "./types";
30
30
  /** Options for creating an InteractiveMode instance (for future API use) */
31
31
  export interface InteractiveModeOptions {
32
32
  /** Providers that were migrated during startup */
@@ -112,6 +112,13 @@ export declare class InteractiveMode implements InteractiveModeContext {
112
112
  init(options?: InteractiveModeInitOptions): Promise<void>;
113
113
  /** Reload slash commands and autocomplete for the provided working directory. */
114
114
  refreshSlashCommandState(cwd?: string): Promise<void>;
115
+ /**
116
+ * Re-point the process and every cwd-derived cache at `newCwd` after the
117
+ * active session's working directory changed (`/move` relocation or resuming
118
+ * a session from another project). The SessionManager's cwd MUST already
119
+ * reflect `newCwd` before this is called.
120
+ */
121
+ applyCwdChange(newCwd: string): Promise<void>;
115
122
  getUserInput(): Promise<SubmittedUserInput>;
116
123
  disableLoopMode(message?: string): void;
117
124
  /**
@@ -253,7 +260,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
253
260
  emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown", previousSessionFile?: string): Promise<void>;
254
261
  setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void;
255
262
  setHookStatus(key: string, text: string | undefined): void;
256
- showHookSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: ExtensionUIDialogOptions, extra?: {
263
+ showHookSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: InteractiveSelectorDialogOptions, extra?: {
257
264
  slider?: HookSelectorSlider;
258
265
  }): Promise<string | undefined>;
259
266
  hideHookSelector(): void;
@@ -19,7 +19,7 @@ import type { CustomEditor } from "./components/custom-editor";
19
19
  import type { EvalExecutionComponent } from "./components/eval-execution";
20
20
  import type { HookEditorComponent } from "./components/hook-editor";
21
21
  import type { HookInputComponent } from "./components/hook-input";
22
- import type { HookSelectorComponent } from "./components/hook-selector";
22
+ import type { HookSelectorComponent, HookSelectorOptions } from "./components/hook-selector";
23
23
  import type { StatusLineComponent } from "./components/status-line";
24
24
  import type { ToolExecutionHandle } from "./components/tool-execution";
25
25
  import type { LoopLimitRuntime } from "./loop-limit";
@@ -51,6 +51,7 @@ export type TodoPhase = {
51
51
  export interface InteractiveModeInitOptions {
52
52
  suppressWelcomeIntro?: boolean;
53
53
  }
54
+ export type InteractiveSelectorDialogOptions = ExtensionUIDialogOptions & Pick<HookSelectorOptions, "disabledIndices">;
54
55
  export interface InteractiveModeContext {
55
56
  ui: TUI;
56
57
  chatContainer: Container;
@@ -217,6 +218,7 @@ export interface InteractiveModeContext {
217
218
  executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean): Promise<CompactionOutcome>;
218
219
  openInBrowser(urlOrPath: string): void;
219
220
  refreshSlashCommandState(cwd?: string): Promise<void>;
221
+ applyCwdChange(newCwd: string): Promise<void>;
220
222
  showSettingsSelector(): void;
221
223
  showHistorySearch(): void;
222
224
  showExtensionsDashboard(): void;
@@ -264,7 +266,7 @@ export interface InteractiveModeContext {
264
266
  emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown", previousSessionFile?: string): Promise<void>;
265
267
  setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void;
266
268
  setHookStatus(key: string, text: string | undefined): void;
267
- showHookSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: ExtensionUIDialogOptions): Promise<string | undefined>;
269
+ showHookSelector(title: string, options: ExtensionUISelectItem[], dialogOptions?: InteractiveSelectorDialogOptions): Promise<string | undefined>;
268
270
  hideHookSelector(): void;
269
271
  showHookInput(title: string, placeholder?: string): Promise<string | undefined>;
270
272
  hideHookInput(): void;
@@ -6,7 +6,7 @@
6
6
  * creation and removed when the owner releases them.
7
7
  */
8
8
  import type { AgentSession } from "../session/agent-session";
9
- export declare const MAIN_AGENT_ID = "0-Main";
9
+ export declare const MAIN_AGENT_ID = "Main";
10
10
  export type AgentStatus = "running" | "idle" | "completed" | "aborted";
11
11
  export type AgentKind = "main" | "sub";
12
12
  export interface AgentRef {
@@ -101,13 +101,13 @@ export interface CreateAgentSessionOptions {
101
101
  parentHindsightSessionState?: HindsightSessionState;
102
102
  /** Parent Mnemopi state to alias for subagent memory tools. */
103
103
  parentMnemopiSessionState?: MnemopiSessionState;
104
- /** Pre-allocated agent identity for IRC routing. Default: "0-Main" for top-level, parentTaskPrefix-derived for sub. */
104
+ /** Pre-allocated agent identity for IRC routing. Default: "Main" for top-level, parentTaskPrefix-derived for sub. */
105
105
  agentId?: string;
106
106
  /** Display name for the agent in IRC. Default: "main" or "sub". */
107
107
  agentDisplayName?: string;
108
108
  /** Optional shared agent registry for IRC routing. Default: AgentRegistry.global(). */
109
109
  agentRegistry?: AgentRegistry;
110
- /** Parent task ID prefix for nested artifact naming (e.g., "6-Extensions") */
110
+ /** Parent task ID prefix for nested artifact naming (e.g., "Extensions") */
111
111
  parentTaskPrefix?: string;
112
112
  /** Inherited eval executor session id for subagents sharing parent eval state. */
113
113
  parentEvalSessionId?: string;
@@ -201,7 +201,7 @@ export interface AgentSessionConfig {
201
201
  * **MUST NOT** dispose it on their own teardown.
202
202
  */
203
203
  ownedAsyncJobManager?: AsyncJobManager;
204
- /** Agent identity (registry id like "0-Main" or "3-Alice") used for IRC routing. */
204
+ /** Agent identity (registry id like "Main" or "Alice") used for IRC routing. */
205
205
  agentId?: string;
206
206
  /** Shared agent registry (for forwarding IRC observations to the main session UI). */
207
207
  agentRegistry?: AgentRegistry;
@@ -973,7 +973,9 @@ export declare class AgentSession {
973
973
  * Uses the last assistant message's usage data when available,
974
974
  * otherwise estimates tokens for all messages.
975
975
  */
976
- getContextUsage(): ContextUsage | undefined;
976
+ getContextUsage(options?: {
977
+ contextWindow?: number;
978
+ }): ContextUsage | undefined;
977
979
  fetchUsageReports(signal?: AbortSignal): Promise<UsageReport[] | null>;
978
980
  /**
979
981
  * Export session to HTML.