@astralyn/pi 1.1.0 → 1.2.0
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.
- package/CHANGELOG.md +42 -0
- package/dist/bundle/chunks/anthropic-messages-NVP5OPIM.js +6 -0
- package/dist/bundle/chunks/{azure-openai-responses-CH74HGP4.js → azure-openai-responses-IBTOZ5MH.js} +1 -1
- package/dist/bundle/chunks/{chunk-H35KWBT5.js → chunk-4XZYHGVN.js} +1 -1
- package/dist/bundle/chunks/{chunk-3MMB5I7J.js → chunk-7HJ6CHUB.js} +1 -1
- package/dist/bundle/chunks/{chunk-MAC4N3BW.js → chunk-7UBIBLPN.js} +1 -1
- package/dist/bundle/chunks/{chunk-D3XW5X3Z.js → chunk-A5HU4TE6.js} +160 -229
- package/dist/bundle/chunks/{chunk-C2ARIVS3.js → chunk-B2UOWO4A.js} +1 -1
- package/dist/bundle/chunks/{chunk-KAC2YPTW.js → chunk-J75WV3FL.js} +1 -1
- package/dist/bundle/chunks/{chunk-TEAAYBTS.js → chunk-LHSPN2IO.js} +1 -1
- package/dist/bundle/chunks/chunk-Q74S7ILH.js +2 -0
- package/dist/bundle/chunks/{chunk-QLU3LESZ.js → chunk-QDDSFJ35.js} +1 -1
- package/dist/bundle/chunks/{chunk-EJEOEBSJ.js → chunk-UQECUCUH.js} +1 -1
- package/dist/bundle/chunks/{cloudflare-workers-ai-system-one-XO45ZT3V.js → cloudflare-workers-ai-system-one-HGOVFZDC.js} +1 -1
- package/dist/bundle/chunks/codemode-worker.js +17 -9
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-VVO64ZRQ.js → google-generative-ai-M44TSMAN.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-LKS5NUHA.js → google-vertex-3C4OWLFX.js} +1 -1
- package/dist/bundle/chunks/{mistral-conversations-NJUOG4ET.js → mistral-conversations-I5PL4VCZ.js} +1 -1
- package/dist/bundle/chunks/openai-codex-responses-O5EUDL54.js +10 -0
- package/dist/bundle/chunks/{openai-completions-7HTTU6FH.js → openai-completions-X3SSG5BQ.js} +1 -1
- package/dist/bundle/chunks/{openai-decisions-776H4VDZ.js → openai-decisions-TVCDIPZX.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-7A6BAQ5X.js → openai-responses-NYPNKVDV.js} +1 -1
- package/dist/bundle/chunks/{typesafe-system-one-2DQLG4R2.js → typesafe-system-one-LWPJYTJP.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-2NHGQRS6.js → virtual-modules-OZTPKGU7.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/agent-session.d.ts +14 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +93 -58
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +20 -13
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bug-report.d.ts +9 -1
- package/dist/core/bug-report.d.ts.map +1 -1
- package/dist/core/compaction/utils.d.ts +6 -0
- package/dist/core/compaction/utils.d.ts.map +1 -1
- package/dist/core/compaction/utils.js +7 -8
- package/dist/core/compaction/utils.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +4 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +2 -3
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +31 -7
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/key-id-schema.d.ts +6 -0
- package/dist/core/key-id-schema.d.ts.map +1 -0
- package/dist/core/key-id-schema.js +16 -0
- package/dist/core/key-id-schema.js.map +1 -0
- package/dist/core/keybinding-registry.d.ts +4 -3
- package/dist/core/keybinding-registry.d.ts.map +1 -1
- package/dist/core/keybinding-registry.js +4 -3
- package/dist/core/keybinding-registry.js.map +1 -1
- package/dist/core/keybindings-schema.d.ts +4 -0
- package/dist/core/keybindings-schema.d.ts.map +1 -0
- package/dist/core/keybindings-schema.js +16 -0
- package/dist/core/keybindings-schema.js.map +1 -0
- package/dist/core/keybindings.d.ts +258 -81
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +27 -24
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +713 -180
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +18 -179
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +11 -6
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +3 -3
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +2 -1
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +12 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +82 -24
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-defaults.d.ts +65 -0
- package/dist/core/settings-defaults.d.ts.map +1 -0
- package/dist/core/settings-defaults.js +66 -0
- package/dist/core/settings-defaults.js.map +1 -0
- package/dist/core/settings-manager.d.ts +4 -149
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +48 -44
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-schema.d.ts +231 -0
- package/dist/core/settings-schema.d.ts.map +1 -0
- package/dist/core/settings-schema.js +294 -0
- package/dist/core/settings-schema.js.map +1 -0
- package/dist/core/tools/render-utils.d.ts +18 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +46 -0
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +21 -50
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/extensions/btw/keybindings.d.ts +2 -2
- package/dist/extensions/btw/keybindings.d.ts.map +1 -1
- package/dist/extensions/btw/keybindings.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +64 -45
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/index.d.ts.map +1 -1
- package/dist/extensions/codemode/index.js +3 -7
- package/dist/extensions/codemode/index.js.map +1 -1
- package/dist/extensions/codemode/renderer.d.ts +2 -2
- package/dist/extensions/codemode/renderer.d.ts.map +1 -1
- package/dist/extensions/codemode/renderer.js +9 -3
- package/dist/extensions/codemode/renderer.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts +6 -12
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +44 -32
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/list-keybindings.d.ts +2 -2
- package/dist/extensions/list-keybindings.d.ts.map +1 -1
- package/dist/extensions/list-keybindings.js.map +1 -1
- package/dist/extensions/mcp/cli.js +5 -8
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +25 -34
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/resources.d.ts +0 -6
- package/dist/extensions/mcp/resources.d.ts.map +1 -1
- package/dist/extensions/mcp/resources.js +1 -1
- package/dist/extensions/mcp/resources.js.map +1 -1
- package/dist/extensions/mcp/runtime.d.ts +3 -6
- package/dist/extensions/mcp/runtime.d.ts.map +1 -1
- package/dist/extensions/mcp/runtime.js +4 -39
- package/dist/extensions/mcp/runtime.js.map +1 -1
- package/dist/extensions/mcp/tools.d.ts +2 -3
- package/dist/extensions/mcp/tools.d.ts.map +1 -1
- package/dist/extensions/mcp/tools.js +62 -6
- package/dist/extensions/mcp/tools.js.map +1 -1
- package/dist/extensions/provider/keybindings.d.ts +2 -2
- package/dist/extensions/provider/keybindings.d.ts.map +1 -1
- package/dist/extensions/provider/keybindings.js.map +1 -1
- package/dist/extensions/search/code-search.d.ts +0 -2
- package/dist/extensions/search/code-search.d.ts.map +1 -1
- package/dist/extensions/search/code-search.js +2 -2
- package/dist/extensions/search/code-search.js.map +1 -1
- package/dist/extensions/search/command.js +2 -2
- package/dist/extensions/search/command.js.map +1 -1
- package/dist/extensions/search/index.d.ts.map +1 -1
- package/dist/extensions/search/index.js +14 -11
- package/dist/extensions/search/index.js.map +1 -1
- package/dist/extensions/search/workspace.d.ts +11 -10
- package/dist/extensions/search/workspace.d.ts.map +1 -1
- package/dist/extensions/search/workspace.js +259 -141
- package/dist/extensions/search/workspace.js.map +1 -1
- package/dist/extensions/tool-search/index.d.ts.map +1 -1
- package/dist/extensions/tool-search/index.js +1 -6
- package/dist/extensions/tool-search/index.js.map +1 -1
- package/dist/extensions/tool-search/tool.d.ts +0 -2
- package/dist/extensions/tool-search/tool.d.ts.map +1 -1
- package/dist/extensions/tool-search/tool.js +2 -4
- package/dist/extensions/tool-search/tool.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.js +3 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +3 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +2 -2
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +11 -5
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/light.json +1 -1
- package/dist/modes/interactive/theme/theme-schema.d.ts +28 -0
- package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-schema.js +105 -0
- package/dist/modes/interactive/theme/theme-schema.js.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts +257 -0
- package/dist/modes/interactive/theme/theme-tokens.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme-tokens.js +94 -0
- package/dist/modes/interactive/theme/theme-tokens.js.map +1 -0
- package/dist/modes/interactive/theme/theme.d.ts +13 -16
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +23 -31
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +4 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +6 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/docs/bundled/extensions/search.md +2 -1
- package/docs/codemode.md +1 -1
- package/docs/compaction.md +2 -2
- package/docs/environment-variables.md +2 -1
- package/docs/extensions.md +10 -4
- package/docs/keybindings.md +1 -0
- package/docs/mcp.md +1 -1
- package/docs/models.md +1 -0
- package/docs/providers.md +16 -0
- package/docs/settings.md +2 -2
- package/docs/themes.md +4 -2
- package/docs/tui.md +1 -1
- package/docs/usage.md +2 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/overlay-test.ts +2 -2
- package/examples/extensions/plan-mode/index.ts +6 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +54 -102
- package/package.json +8 -20
- package/schemas/keybindings.schema.json +453 -0
- package/schemas/models.schema.json +1157 -0
- package/schemas/settings.schema.json +782 -0
- package/schemas/theme.schema.json +365 -0
- package/dist/bundle/chunks/anthropic-messages-3K3DWVY6.js +0 -6
- package/dist/bundle/chunks/openai-codex-responses-TZWBTTYM.js +0 -10
- package/dist/modes/interactive/theme/theme-json.d.ts +0 -85
- package/dist/modes/interactive/theme/theme-json.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-json.js +0 -132
- package/dist/modes/interactive/theme/theme-json.js.map +0 -1
- package/dist/modes/interactive/theme/theme-schema.json +0 -361
- package/examples/plugins/pi-example-plugin/README.md +0 -38
- package/examples/plugins/pi-example-plugin/package.json +0 -10
- package/examples/plugins/pi-example-plugin/src/contract.ts +0 -13
- package/examples/plugins/pi-example-plugin/src/session.ts +0 -24
- package/examples/plugins/pi-example-plugin/src/tui.ts +0 -31
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEvE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAIpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAOjD;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIjF;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIjD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,CAC5B,MAAM,EAAE;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,SAAS,EACzG,UAAU,EAAE,OAAO,GACjB,MAAM,CAsBR;AAED,MAAM,MAAM,oBAAoB,CAAC,QAAQ,IAAI;IAC5C,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,QAAQ,CAAC;CAClB,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAG,MAAM,CAkB5G;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAUrD;AAED,6GAA6G;AAC7G,UAAU,cAAc;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;CAC1C;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC,GAAG,IAAI,CAM/E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAkBhH;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEnD;AAED,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAKR"}
|
|
@@ -77,6 +77,52 @@ export function formatToolCallWithArgs(title, args, theme, expanded) {
|
|
|
77
77
|
const preview = pairs.length > COLLAPSED_ARGS_CHARS ? `${pairs.slice(0, COLLAPSED_ARGS_CHARS - 3)}...` : pairs;
|
|
78
78
|
return `${header} ${theme.fg("muted", preview)}`;
|
|
79
79
|
}
|
|
80
|
+
/** Duration as `4.2s` below a minute, then `1m 30s` and `2h 3m 4s`. */
|
|
81
|
+
export function formatToolDuration(ms) {
|
|
82
|
+
const seconds = ms / 1000;
|
|
83
|
+
if (seconds < 60)
|
|
84
|
+
return `${seconds.toFixed(1)}s`;
|
|
85
|
+
const totalSeconds = Math.floor(seconds);
|
|
86
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
87
|
+
const remainder = totalSeconds % 60;
|
|
88
|
+
if (minutes < 60)
|
|
89
|
+
return `${minutes}m ${remainder}s`;
|
|
90
|
+
return `${Math.floor(minutes / 60)}h ${minutes % 60}m ${remainder}s`;
|
|
91
|
+
}
|
|
92
|
+
/** Start the row's clock once execution starts. Call from `renderCall`. */
|
|
93
|
+
export function startToolTimer(context) {
|
|
94
|
+
const state = context.state;
|
|
95
|
+
if (context.executionStarted && state.startedAt === undefined) {
|
|
96
|
+
state.startedAt = Date.now();
|
|
97
|
+
state.endedAt = undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The row's timing line, from `renderResult`: `Elapsed 4.2s` while the result is partial, redrawn
|
|
102
|
+
* every second, and `Took 4.2s` once it is final. Undefined when the row has no start time and no
|
|
103
|
+
* recorded duration.
|
|
104
|
+
*/
|
|
105
|
+
export function toolTimerText(context, isPartial) {
|
|
106
|
+
const state = context.state;
|
|
107
|
+
if (state.startedAt !== undefined && isPartial && !state.interval) {
|
|
108
|
+
state.interval = setInterval(() => context.invalidate(), 1000);
|
|
109
|
+
}
|
|
110
|
+
if (!isPartial || context.isError) {
|
|
111
|
+
state.endedAt ??= Date.now();
|
|
112
|
+
if (state.interval) {
|
|
113
|
+
clearInterval(state.interval);
|
|
114
|
+
state.interval = undefined;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// A final result's recorded duration wins: it is monotonic and survives reloads. The renderer's own clock is the
|
|
118
|
+
// fallback for live progress and for results stored without one.
|
|
119
|
+
if (!isPartial && context.durationMs !== undefined)
|
|
120
|
+
return `Took ${formatToolDuration(context.durationMs)}`;
|
|
121
|
+
if (state.startedAt === undefined)
|
|
122
|
+
return undefined;
|
|
123
|
+
const endTime = state.endedAt ?? Date.now();
|
|
124
|
+
return `${isPartial ? "Elapsed" : "Took"} ${formatToolDuration(endTime - state.startedAt)}`;
|
|
125
|
+
}
|
|
80
126
|
export function invalidArgText(theme) {
|
|
81
127
|
return theme.fg("error", "[invalid arg]");
|
|
82
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-utils.js","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nconst COLLAPSED_ARGS_CHARS = 100;\n\n/**\n * Generic tool call header: the title followed by the arguments. Collapsed, they are `key=value`\n * pairs on the title line, cut to {@link COLLAPSED_ARGS_CHARS}. Expanded, each is a `key: value`\n * line below the title, with strings shown raw and continuation lines indented.\n */\nexport function formatToolCallWithArgs(title: string, args: unknown, theme: Theme, expanded: boolean): string {\n\tconst header = theme.fg(\"toolTitle\", theme.bold(title));\n\tif (args == null) return header;\n\tconst entries =\n\t\ttypeof args === \"object\" && !Array.isArray(args)\n\t\t\t? Object.entries(args)\n\t\t\t: ([[\"args\", args]] as [string, unknown][]);\n\tif (entries.length === 0) return header;\n\tif (expanded) {\n\t\tconst lines = entries.map(([key, value]) => {\n\t\t\tconst text = typeof value === \"string\" ? value : (JSON.stringify(value, null, 2) ?? String(value));\n\t\t\treturn ` ${key}: ${replaceTabs(text).replace(/\\r/g, \"\").split(\"\\n\").join(\"\\n \")}`;\n\t\t});\n\t\treturn `${header}\\n${theme.fg(\"muted\", lines.join(\"\\n\"))}`;\n\t}\n\tconst pairs = entries.map(([key, value]) => `${key}=${JSON.stringify(value) ?? String(value)}`).join(\" \");\n\tconst preview = pairs.length > COLLAPSED_ARGS_CHARS ? `${pairs.slice(0, COLLAPSED_ARGS_CHARS - 3)}...` : pairs;\n\treturn `${header} ${theme.fg(\"muted\", preview)}`;\n}\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"render-utils.js","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport { pathToFileURL } from \"node:url\";\nimport type { ImageContent, TextContent } from \"@earendil-works/pi-ai\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@earendil-works/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { sanitizeBinaryOutput } from \"../../utils/shell.ts\";\nimport type { ToolRenderContext } from \"../extensions/types.ts\";\n\nexport function shortenPath(path: unknown): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nconst COLLAPSED_ARGS_CHARS = 100;\n\n/**\n * Generic tool call header: the title followed by the arguments. Collapsed, they are `key=value`\n * pairs on the title line, cut to {@link COLLAPSED_ARGS_CHARS}. Expanded, each is a `key: value`\n * line below the title, with strings shown raw and continuation lines indented.\n */\nexport function formatToolCallWithArgs(title: string, args: unknown, theme: Theme, expanded: boolean): string {\n\tconst header = theme.fg(\"toolTitle\", theme.bold(title));\n\tif (args == null) return header;\n\tconst entries =\n\t\ttypeof args === \"object\" && !Array.isArray(args)\n\t\t\t? Object.entries(args)\n\t\t\t: ([[\"args\", args]] as [string, unknown][]);\n\tif (entries.length === 0) return header;\n\tif (expanded) {\n\t\tconst lines = entries.map(([key, value]) => {\n\t\t\tconst text = typeof value === \"string\" ? value : (JSON.stringify(value, null, 2) ?? String(value));\n\t\t\treturn ` ${key}: ${replaceTabs(text).replace(/\\r/g, \"\").split(\"\\n\").join(\"\\n \")}`;\n\t\t});\n\t\treturn `${header}\\n${theme.fg(\"muted\", lines.join(\"\\n\"))}`;\n\t}\n\tconst pairs = entries.map(([key, value]) => `${key}=${JSON.stringify(value) ?? String(value)}`).join(\" \");\n\tconst preview = pairs.length > COLLAPSED_ARGS_CHARS ? `${pairs.slice(0, COLLAPSED_ARGS_CHARS - 3)}...` : pairs;\n\treturn `${header} ${theme.fg(\"muted\", preview)}`;\n}\n\n/** Duration as `4.2s` below a minute, then `1m 30s` and `2h 3m 4s`. */\nexport function formatToolDuration(ms: number): string {\n\tconst seconds = ms / 1000;\n\tif (seconds < 60) return `${seconds.toFixed(1)}s`;\n\n\tconst totalSeconds = Math.floor(seconds);\n\tconst minutes = Math.floor(totalSeconds / 60);\n\tconst remainder = totalSeconds % 60;\n\tif (minutes < 60) return `${minutes}m ${remainder}s`;\n\n\treturn `${Math.floor(minutes / 60)}h ${minutes % 60}m ${remainder}s`;\n}\n\n/** Renderer state of {@link startToolTimer} and {@link toolTimerText}, kept in `ToolRenderContext.state`. */\ninterface ToolTimerState {\n\tstartedAt?: number;\n\tendedAt?: number;\n\tinterval?: ReturnType<typeof setInterval>;\n}\n\n/** Start the row's clock once execution starts. Call from `renderCall`. */\nexport function startToolTimer(context: ToolRenderContext<ToolTimerState>): void {\n\tconst state = context.state;\n\tif (context.executionStarted && state.startedAt === undefined) {\n\t\tstate.startedAt = Date.now();\n\t\tstate.endedAt = undefined;\n\t}\n}\n\n/**\n * The row's timing line, from `renderResult`: `Elapsed 4.2s` while the result is partial, redrawn\n * every second, and `Took 4.2s` once it is final. Undefined when the row has no start time and no\n * recorded duration.\n */\nexport function toolTimerText(context: ToolRenderContext<ToolTimerState>, isPartial: boolean): string | undefined {\n\tconst state = context.state;\n\tif (state.startedAt !== undefined && isPartial && !state.interval) {\n\t\tstate.interval = setInterval(() => context.invalidate(), 1000);\n\t}\n\tif (!isPartial || context.isError) {\n\t\tstate.endedAt ??= Date.now();\n\t\tif (state.interval) {\n\t\t\tclearInterval(state.interval);\n\t\t\tstate.interval = undefined;\n\t\t}\n\t}\n\t// A final result's recorded duration wins: it is monotonic and survives reloads. The renderer's own clock is the\n\t// fallback for live progress and for results stored without one.\n\tif (!isPartial && context.durationMs !== undefined) return `Took ${formatToolDuration(context.durationMs)}`;\n\tif (state.startedAt === undefined) return undefined;\n\tconst endTime = state.endedAt ?? Date.now();\n\treturn `${isPartial ? \"Elapsed\" : \"Took\"} ${formatToolDuration(endTime - state.startedAt)}`;\n}\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value)), value, cwd);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/renderers/bash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,cAAc,EAA8C,MAAM,2BAA2B,CAAC;AAE5G,OAAO,KAAK,EAAoC,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAI1F,eAAO,MAAM,uBAAuB,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/renderers/bash.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,cAAc,EAA8C,MAAM,2BAA2B,CAAC;AAE5G,OAAO,KAAK,EAAoC,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAI1F,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAqM3C,4GAA4G;AAC5G,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,QAAQ,CAAC,GAC9C,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY,GAAG,cAAc,CAAC,CAmB/D"}
|
|
@@ -9,7 +9,7 @@ import { Container, Spacer, Text, truncateToWidth, visibleWidth } from "@earendi
|
|
|
9
9
|
import { keyHint } from "../../../modes/interactive/components/keybinding-hints.js";
|
|
10
10
|
import { VisualLinePreview } from "../../../modes/interactive/components/visual-truncate.js";
|
|
11
11
|
import { highlightCode, theme } from "../../../modes/interactive/theme/theme.js";
|
|
12
|
-
import { getTextOutput, invalidArgText, str } from "../render-utils.js";
|
|
12
|
+
import { getTextOutput, invalidArgText, startToolTimer, str, toolTimerText } from "../render-utils.js";
|
|
13
13
|
import { DEFAULT_MAX_BYTES, formatSize } from "../truncate.js";
|
|
14
14
|
const BASH_PREVIEW_LINES = 5;
|
|
15
15
|
export const BASH_UPDATE_THROTTLE_MS = 100;
|
|
@@ -49,39 +49,28 @@ class BashCallRenderComponent {
|
|
|
49
49
|
return [formatTruncatedShellCall(this.command, this.timeout, width, this.config)];
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
const
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
const shellTimerHooked = Symbol("shellTimerHooked");
|
|
53
|
+
/**
|
|
54
|
+
* Start the row's clock and hook disposal once. Either slot can initialize timing, since
|
|
55
|
+
* extensions may replace the other slot; upstream's timer state outlives a replaced slot, but
|
|
56
|
+
* its refresh interval must still end when the row is disposed mid-run.
|
|
57
|
+
*/
|
|
58
|
+
function ensureShellTimer(context) {
|
|
59
|
+
startToolTimer(context);
|
|
57
60
|
const state = context.state;
|
|
58
|
-
if (state[
|
|
59
|
-
return
|
|
60
|
-
|
|
61
|
-
state[shellTiming] = timing;
|
|
61
|
+
if (state[shellTimerHooked])
|
|
62
|
+
return;
|
|
63
|
+
state[shellTimerHooked] = true;
|
|
62
64
|
const previousDispose = state.dispose;
|
|
63
65
|
state.dispose = () => {
|
|
64
66
|
try {
|
|
65
67
|
previousDispose?.call(state);
|
|
66
68
|
}
|
|
67
69
|
finally {
|
|
68
|
-
clearInterval(
|
|
69
|
-
|
|
70
|
-
timing.disposed = true;
|
|
70
|
+
clearInterval(state.interval);
|
|
71
|
+
state.interval = undefined;
|
|
71
72
|
}
|
|
72
73
|
};
|
|
73
|
-
return timing;
|
|
74
|
-
}
|
|
75
|
-
function formatDuration(ms) {
|
|
76
|
-
const seconds = ms / 1000;
|
|
77
|
-
if (seconds < 60)
|
|
78
|
-
return `${seconds.toFixed(1)}s`;
|
|
79
|
-
const totalSeconds = Math.floor(seconds);
|
|
80
|
-
const minutes = Math.floor(totalSeconds / 60);
|
|
81
|
-
const remainder = totalSeconds % 60;
|
|
82
|
-
if (minutes < 60)
|
|
83
|
-
return `${minutes}m ${remainder}s`;
|
|
84
|
-
return `${Math.floor(minutes / 60)}h ${minutes % 60}m ${remainder}s`;
|
|
85
74
|
}
|
|
86
75
|
function formatShellPrompt(prompt) {
|
|
87
76
|
return theme.fg("toolTitle", theme.bold(`${prompt} `));
|
|
@@ -121,7 +110,7 @@ function formatTruncatedShellCall(command, timeout, width, config) {
|
|
|
121
110
|
: theme.fg("muted", " …");
|
|
122
111
|
return fitCollapsedShellCall(styleShellCommand(firstNonEmptyLine, config), timeout, width, suffix, config);
|
|
123
112
|
}
|
|
124
|
-
function rebuildBashResultRenderComponent(component, result, options, showImages,
|
|
113
|
+
function rebuildBashResultRenderComponent(component, result, options, showImages, timerText, submittedAsBackground) {
|
|
125
114
|
component.clear();
|
|
126
115
|
const background = result.details?.background;
|
|
127
116
|
let output = background?.kind === "background"
|
|
@@ -169,42 +158,24 @@ function rebuildBashResultRenderComponent(component, result, options, showImages
|
|
|
169
158
|
}
|
|
170
159
|
component.addChild(new Text(`\n${theme.fg("warning", `[${warnings.join(". ")}]`)}`, 0, 0));
|
|
171
160
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (!options.isPartial && durationMs !== undefined) {
|
|
175
|
-
component.addChild(new Text(`\n${theme.fg("muted", `Took ${formatDuration(durationMs)}`)}`, 0, 0));
|
|
176
|
-
}
|
|
177
|
-
else if (startedAt !== undefined) {
|
|
178
|
-
const label = options.isPartial ? "Elapsed" : "Took";
|
|
179
|
-
const endTime = endedAt ?? Date.now();
|
|
180
|
-
component.addChild(new Text(`\n${theme.fg("muted", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));
|
|
181
|
-
}
|
|
161
|
+
if (timerText)
|
|
162
|
+
component.addChild(new Text(`\n${theme.fg("muted", timerText)}`, 0, 0));
|
|
182
163
|
}
|
|
183
164
|
/** Shell renderers are shared by bash and powershell, which differ in the prompt and highlight language. */
|
|
184
165
|
export function createShellRenderers(config) {
|
|
185
166
|
return {
|
|
186
167
|
renderCall(args, _theme, context) {
|
|
187
|
-
|
|
168
|
+
ensureShellTimer(context);
|
|
188
169
|
const component = context.lastComponent ?? new BashCallRenderComponent(config);
|
|
189
170
|
component.update(args, context.expanded);
|
|
190
171
|
return component;
|
|
191
172
|
},
|
|
192
173
|
renderResult(result, options, _theme, context) {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (!options.isPartial || context.isError) {
|
|
196
|
-
timing.endedAt ??= Date.now();
|
|
197
|
-
clearInterval(timing.interval);
|
|
198
|
-
timing.interval = undefined;
|
|
199
|
-
}
|
|
200
|
-
else if (!timing.disposed && timing.interval === undefined) {
|
|
201
|
-
timing.interval = setInterval(() => context.invalidate(), 1000);
|
|
202
|
-
timing.interval.unref?.();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
174
|
+
ensureShellTimer(context);
|
|
175
|
+
const timerText = toolTimerText(context, options.isPartial);
|
|
205
176
|
const component = context.lastComponent ?? new Container();
|
|
206
177
|
const submitted = context.args?.background === true;
|
|
207
|
-
rebuildBashResultRenderComponent(component, result, options, context.showImages,
|
|
178
|
+
rebuildBashResultRenderComponent(component, result, options, context.showImages, timerText, submitted);
|
|
208
179
|
component.invalidate();
|
|
209
180
|
return component;
|
|
210
181
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../../src/core/tools/renderers/bash.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Presentation for the shell tools.\n *\n * Renderers live apart from the implementation so a process that only displays tool output does not\n * load the execution path or its typebox parameter schema. `bash.ts` spreads these into the shell\n * tool definition, so the tool's public shape is unchanged.\n */\n\nimport { type Component, Container, Spacer, Text, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.ts\";\nimport { VisualLinePreview } from \"../../../modes/interactive/components/visual-truncate.ts\";\nimport { highlightCode, theme } from \"../../../modes/interactive/theme/theme.ts\";\nimport type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from \"../../extensions/types.ts\";\nimport { getTextOutput, invalidArgText, str } from \"../render-utils.ts\";\nimport type { BashRenderState, BashToolDetails, ShellToolConfig } from \"../shell-tool.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize } from \"../truncate.ts\";\n\nconst BASH_PREVIEW_LINES = 5;\nexport const BASH_UPDATE_THROTTLE_MS = 100;\nclass BashCallRenderComponent implements Component {\n\tprivate command: string | null = \"\";\n\tprivate timeout: number | undefined;\n\tprivate expanded = false;\n\tprivate cachedWidth: number | undefined;\n\tprivate cachedLines: string[] | undefined;\n\tprivate readonly config: Pick<ShellToolConfig, \"name\" | \"prompt\">;\n\n\tconstructor(config: Pick<ShellToolConfig, \"name\" | \"prompt\">) {\n\t\tthis.config = config;\n\t}\n\n\tupdate(args: { command?: string; timeout?: number } | undefined, expanded: boolean): void {\n\t\tconst command = str(args?.command);\n\t\tconst timeout = args?.timeout as number | undefined;\n\t\tif (this.command === command && this.timeout === timeout && this.expanded === expanded) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.command = command;\n\t\tthis.timeout = timeout;\n\t\tthis.expanded = expanded;\n\t\tthis.invalidate();\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.cachedLines === undefined || this.cachedWidth !== width) {\n\t\t\tthis.cachedLines = this.renderLines(Math.max(1, width));\n\t\t\tthis.cachedWidth = width;\n\t\t}\n\t\treturn this.cachedLines;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tprivate renderLines(width: number): string[] {\n\t\tconst fullCall = formatFullShellCall(this.command, this.timeout, this.config);\n\t\tconst fullLines = new Text(fullCall, 0, 0).render(width);\n\t\tif (this.expanded || fullLines.length <= 1) return fullLines;\n\t\treturn [formatTruncatedShellCall(this.command, this.timeout, width, this.config)];\n\t}\n}\nconst shellTiming = Symbol(\"shellTiming\");\ninterface ShellTiming {\n\tstartedAt: number;\n\tendedAt?: number;\n\tinterval?: ReturnType<typeof setInterval>;\n\tdisposed: boolean;\n}\ninterface ShellRenderState extends BashRenderState {\n\t[shellTiming]?: ShellTiming;\n}\n\n/** Either slot can initialize timing, since extensions may replace the other slot. */\nfunction getShellTiming(context: ToolRenderContext<ShellRenderState>): ShellTiming | undefined {\n\tif (!context.executionStarted) return undefined;\n\tconst state = context.state;\n\tif (state[shellTiming]) return state[shellTiming];\n\tconst timing: ShellTiming = { startedAt: Date.now(), disposed: false };\n\tstate[shellTiming] = timing;\n\tconst previousDispose = state.dispose;\n\tstate.dispose = () => {\n\t\ttry {\n\t\t\tpreviousDispose?.call(state);\n\t\t} finally {\n\t\t\tclearInterval(timing.interval);\n\t\t\ttiming.interval = undefined;\n\t\t\ttiming.disposed = true;\n\t\t}\n\t};\n\treturn timing;\n}\n\nfunction formatDuration(ms: number): string {\n\tconst seconds = ms / 1000;\n\tif (seconds < 60) return `${seconds.toFixed(1)}s`;\n\n\tconst totalSeconds = Math.floor(seconds);\n\tconst minutes = Math.floor(totalSeconds / 60);\n\tconst remainder = totalSeconds % 60;\n\tif (minutes < 60) return `${minutes}m ${remainder}s`;\n\n\treturn `${Math.floor(minutes / 60)}h ${minutes % 60}m ${remainder}s`;\n}\nfunction formatShellPrompt(prompt: string): string {\n\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} `));\n}\nfunction formatShellTimeout(timeout: number | undefined): string {\n\treturn timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n}\nfunction styleShellCommand(command: string, config: Pick<ShellToolConfig, \"name\" | \"prompt\">): string {\n\tconst language = config.name === \"powershell\" ? \"powershell\" : \"bash\";\n\treturn highlightCode(command, language).join(\"\\n\");\n}\nfunction formatFullShellCall(\n\tcommand: string | null,\n\ttimeout: number | undefined,\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): string {\n\tconst commandDisplay =\n\t\tcommand === null\n\t\t\t? invalidArgText(theme)\n\t\t\t: command\n\t\t\t\t? styleShellCommand(command, config)\n\t\t\t\t: theme.fg(\"toolOutput\", \"...\");\n\treturn formatShellPrompt(config.prompt) + commandDisplay + formatShellTimeout(timeout);\n}\nfunction fitCollapsedShellCall(\n\tbody: string,\n\ttimeout: number | undefined,\n\twidth: number,\n\tsuffix: string,\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): string {\n\tconst prompt = formatShellPrompt(config.prompt);\n\tconst timeoutSuffix = formatShellTimeout(timeout);\n\tconst bodyWidth = Math.max(0, width - visibleWidth(prompt) - visibleWidth(suffix) - visibleWidth(timeoutSuffix));\n\tconst fittedBody = truncateToWidth(body, bodyWidth, \"\");\n\treturn truncateToWidth(prompt + fittedBody + suffix + timeoutSuffix, width, \"…\");\n}\nfunction formatTruncatedShellCall(\n\tcommand: string | null,\n\ttimeout: number | undefined,\n\twidth: number,\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): string {\n\tif (command === null) return truncateToWidth(formatFullShellCall(command, timeout, config), width, \"…\");\n\tif (!command) return formatFullShellCall(command, timeout, config);\n\tconst physicalLines = command.split(/\\r?\\n/).filter((line) => line.trim());\n\tconst firstNonEmptyLine = physicalLines[0]?.trim() ?? command.trim();\n\tconst hiddenLines = Math.max(0, physicalLines.length - 1);\n\tconst suffix =\n\t\thiddenLines > 0\n\t\t\t? theme.fg(\"muted\", ` (+${hiddenLines} line${hiddenLines === 1 ? \"\" : \"s\"})`)\n\t\t\t: theme.fg(\"muted\", \" …\");\n\treturn fitCollapsedShellCall(styleShellCommand(firstNonEmptyLine, config), timeout, width, suffix, config);\n}\nfunction rebuildBashResultRenderComponent(\n\tcomponent: Container,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\tstartedAt: number | undefined,\n\tendedAt: number | undefined,\n\tdurationMs: number | undefined,\n\tsubmittedAsBackground: boolean,\n): void {\n\tcomponent.clear();\n\n\tconst background = result.details?.background;\n\tlet output =\n\t\tbackground?.kind === \"background\"\n\t\t\t? `${submittedAsBackground ? \"Running in the background\" : \"Moved to background\"} · ${background.taskId}`\n\t\t\t: getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild(new Spacer(1));\n\t\t\tcomponent.addChild(\n\t\t\t\tnew VisualLinePreview({\n\t\t\t\t\ttext: styledOutput,\n\t\t\t\t\tmaxVisualLines: BASH_PREVIEW_LINES,\n\t\t\t\t\tkeep: \"end\",\n\t\t\t\t\tformatHint: (hidden) =>\n\t\t\t\t\t\ttheme.fg(\"muted\", `... (${hidden} earlier lines,`) +\n\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\t// A final result's recorded duration wins: it is monotonic and survives reloads. The renderer's own clock is the\n\t// fallback for live progress and for results stored without one.\n\tif (!options.isPartial && durationMs !== undefined) {\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `Took ${formatDuration(durationMs)}`)}`, 0, 0));\n\t} else if (startedAt !== undefined) {\n\t\tconst label = options.isPartial ? \"Elapsed\" : \"Took\";\n\t\tconst endTime = endedAt ?? Date.now();\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"muted\", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));\n\t}\n}\n\n/** Shell renderers are shared by bash and powershell, which differ in the prompt and highlight language. */\nexport function createShellRenderers(\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): Pick<ToolDefinition<any, any>, \"renderCall\" | \"renderResult\"> {\n\treturn {\n\t\trenderCall(args, _theme, context) {\n\t\t\tgetShellTiming(context);\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashCallRenderComponent | undefined) ?? new BashCallRenderComponent(config);\n\t\t\tcomponent.update(args as { command?: string; timeout?: number } | undefined, context.expanded);\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tconst timing = getShellTiming(context);\n\t\t\tif (timing) {\n\t\t\t\tif (!options.isPartial || context.isError) {\n\t\t\t\t\ttiming.endedAt ??= Date.now();\n\t\t\t\t\tclearInterval(timing.interval);\n\t\t\t\t\ttiming.interval = undefined;\n\t\t\t\t} else if (!timing.disposed && timing.interval === undefined) {\n\t\t\t\t\ttiming.interval = setInterval(() => context.invalidate(), 1000);\n\t\t\t\t\ttiming.interval.unref?.();\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\tconst submitted = (context.args as { background?: boolean } | undefined)?.background === true;\n\t\t\trebuildBashResultRenderComponent(\n\t\t\t\tcomponent,\n\t\t\t\tresult as any,\n\t\t\t\toptions,\n\t\t\t\tcontext.showImages,\n\t\t\t\ttiming?.startedAt,\n\t\t\t\ttiming?.endedAt,\n\t\t\t\tcontext.durationMs,\n\t\t\t\tsubmitted,\n\t\t\t);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../../src/core/tools/renderers/bash.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Presentation for the shell tools.\n *\n * Renderers live apart from the implementation so a process that only displays tool output does not\n * load the execution path or its typebox parameter schema. `bash.ts` spreads these into the shell\n * tool definition, so the tool's public shape is unchanged.\n */\n\nimport { type Component, Container, Spacer, Text, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport { keyHint } from \"../../../modes/interactive/components/keybinding-hints.ts\";\nimport { VisualLinePreview } from \"../../../modes/interactive/components/visual-truncate.ts\";\nimport { highlightCode, theme } from \"../../../modes/interactive/theme/theme.ts\";\nimport type { ToolDefinition, ToolRenderContext, ToolRenderResultOptions } from \"../../extensions/types.ts\";\nimport { getTextOutput, invalidArgText, startToolTimer, str, toolTimerText } from \"../render-utils.ts\";\nimport type { BashRenderState, BashToolDetails, ShellToolConfig } from \"../shell-tool.ts\";\nimport { DEFAULT_MAX_BYTES, formatSize } from \"../truncate.ts\";\n\nconst BASH_PREVIEW_LINES = 5;\nexport const BASH_UPDATE_THROTTLE_MS = 100;\nclass BashCallRenderComponent implements Component {\n\tprivate command: string | null = \"\";\n\tprivate timeout: number | undefined;\n\tprivate expanded = false;\n\tprivate cachedWidth: number | undefined;\n\tprivate cachedLines: string[] | undefined;\n\tprivate readonly config: Pick<ShellToolConfig, \"name\" | \"prompt\">;\n\n\tconstructor(config: Pick<ShellToolConfig, \"name\" | \"prompt\">) {\n\t\tthis.config = config;\n\t}\n\n\tupdate(args: { command?: string; timeout?: number } | undefined, expanded: boolean): void {\n\t\tconst command = str(args?.command);\n\t\tconst timeout = args?.timeout as number | undefined;\n\t\tif (this.command === command && this.timeout === timeout && this.expanded === expanded) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.command = command;\n\t\tthis.timeout = timeout;\n\t\tthis.expanded = expanded;\n\t\tthis.invalidate();\n\t}\n\n\trender(width: number): string[] {\n\t\tif (this.cachedLines === undefined || this.cachedWidth !== width) {\n\t\t\tthis.cachedLines = this.renderLines(Math.max(1, width));\n\t\t\tthis.cachedWidth = width;\n\t\t}\n\t\treturn this.cachedLines;\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = undefined;\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tprivate renderLines(width: number): string[] {\n\t\tconst fullCall = formatFullShellCall(this.command, this.timeout, this.config);\n\t\tconst fullLines = new Text(fullCall, 0, 0).render(width);\n\t\tif (this.expanded || fullLines.length <= 1) return fullLines;\n\t\treturn [formatTruncatedShellCall(this.command, this.timeout, width, this.config)];\n\t}\n}\n\nconst shellTimerHooked = Symbol(\"shellTimerHooked\");\ntype ShellTimerState = BashRenderState & {\n\tinterval?: ReturnType<typeof setInterval>;\n\t[shellTimerHooked]?: true;\n};\n\n/**\n * Start the row's clock and hook disposal once. Either slot can initialize timing, since\n * extensions may replace the other slot; upstream's timer state outlives a replaced slot, but\n * its refresh interval must still end when the row is disposed mid-run.\n */\nfunction ensureShellTimer(context: ToolRenderContext<ShellTimerState>): void {\n\tstartToolTimer(context);\n\tconst state = context.state;\n\tif (state[shellTimerHooked]) return;\n\tstate[shellTimerHooked] = true;\n\tconst previousDispose = state.dispose;\n\tstate.dispose = () => {\n\t\ttry {\n\t\t\tpreviousDispose?.call(state);\n\t\t} finally {\n\t\t\tclearInterval(state.interval);\n\t\t\tstate.interval = undefined;\n\t\t}\n\t};\n}\n\nfunction formatShellPrompt(prompt: string): string {\n\treturn theme.fg(\"toolTitle\", theme.bold(`${prompt} `));\n}\nfunction formatShellTimeout(timeout: number | undefined): string {\n\treturn timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n}\nfunction styleShellCommand(command: string, config: Pick<ShellToolConfig, \"name\" | \"prompt\">): string {\n\tconst language = config.name === \"powershell\" ? \"powershell\" : \"bash\";\n\treturn highlightCode(command, language).join(\"\\n\");\n}\nfunction formatFullShellCall(\n\tcommand: string | null,\n\ttimeout: number | undefined,\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): string {\n\tconst commandDisplay =\n\t\tcommand === null\n\t\t\t? invalidArgText(theme)\n\t\t\t: command\n\t\t\t\t? styleShellCommand(command, config)\n\t\t\t\t: theme.fg(\"toolOutput\", \"...\");\n\treturn formatShellPrompt(config.prompt) + commandDisplay + formatShellTimeout(timeout);\n}\nfunction fitCollapsedShellCall(\n\tbody: string,\n\ttimeout: number | undefined,\n\twidth: number,\n\tsuffix: string,\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): string {\n\tconst prompt = formatShellPrompt(config.prompt);\n\tconst timeoutSuffix = formatShellTimeout(timeout);\n\tconst bodyWidth = Math.max(0, width - visibleWidth(prompt) - visibleWidth(suffix) - visibleWidth(timeoutSuffix));\n\tconst fittedBody = truncateToWidth(body, bodyWidth, \"\");\n\treturn truncateToWidth(prompt + fittedBody + suffix + timeoutSuffix, width, \"…\");\n}\nfunction formatTruncatedShellCall(\n\tcommand: string | null,\n\ttimeout: number | undefined,\n\twidth: number,\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): string {\n\tif (command === null) return truncateToWidth(formatFullShellCall(command, timeout, config), width, \"…\");\n\tif (!command) return formatFullShellCall(command, timeout, config);\n\tconst physicalLines = command.split(/\\r?\\n/).filter((line) => line.trim());\n\tconst firstNonEmptyLine = physicalLines[0]?.trim() ?? command.trim();\n\tconst hiddenLines = Math.max(0, physicalLines.length - 1);\n\tconst suffix =\n\t\thiddenLines > 0\n\t\t\t? theme.fg(\"muted\", ` (+${hiddenLines} line${hiddenLines === 1 ? \"\" : \"s\"})`)\n\t\t\t: theme.fg(\"muted\", \" …\");\n\treturn fitCollapsedShellCall(styleShellCommand(firstNonEmptyLine, config), timeout, width, suffix, config);\n}\nfunction rebuildBashResultRenderComponent(\n\tcomponent: Container,\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: BashToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\tshowImages: boolean,\n\ttimerText: string | undefined,\n\tsubmittedAsBackground: boolean,\n): void {\n\tcomponent.clear();\n\n\tconst background = result.details?.background;\n\tlet output =\n\t\tbackground?.kind === \"background\"\n\t\t\t? `${submittedAsBackground ? \"Running in the background\" : \"Moved to background\"} · ${background.taskId}`\n\t\t\t: getTextOutput(result as any, showImages).trim();\n\tconst truncation = result.details?.truncation;\n\tconst fullOutputPath = result.details?.fullOutputPath;\n\tif (!options.isPartial && truncation?.truncated && fullOutputPath && output.endsWith(\"]\")) {\n\t\tconst footerStart = output.lastIndexOf(\"\\n\\n[\");\n\t\tif (footerStart !== -1 && output.slice(footerStart).includes(fullOutputPath)) {\n\t\t\toutput = output.slice(0, footerStart).trimEnd();\n\t\t}\n\t}\n\n\tif (output) {\n\t\tconst styledOutput = output\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t.join(\"\\n\");\n\n\t\tif (options.expanded) {\n\t\t\tcomponent.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t} else {\n\t\t\tcomponent.addChild(new Spacer(1));\n\t\t\tcomponent.addChild(\n\t\t\t\tnew VisualLinePreview({\n\t\t\t\t\ttext: styledOutput,\n\t\t\t\t\tmaxVisualLines: BASH_PREVIEW_LINES,\n\t\t\t\t\tkeep: \"end\",\n\t\t\t\t\tformatHint: (hidden) =>\n\t\t\t\t\t\ttheme.fg(\"muted\", `... (${hidden} earlier lines,`) +\n\t\t\t\t\t\t` ${keyHint(\"app.tools.expand\", \"to expand\")}${theme.fg(\"muted\", \")\")}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tif (truncation?.truncated || fullOutputPath) {\n\t\tconst warnings: string[] = [];\n\t\tif (fullOutputPath) {\n\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t}\n\t\tif (truncation?.truncated) {\n\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t} else {\n\t\t\t\twarnings.push(\n\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tcomponent.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t}\n\n\tif (timerText) component.addChild(new Text(`\\n${theme.fg(\"muted\", timerText)}`, 0, 0));\n}\n\n/** Shell renderers are shared by bash and powershell, which differ in the prompt and highlight language. */\nexport function createShellRenderers(\n\tconfig: Pick<ShellToolConfig, \"name\" | \"prompt\">,\n): Pick<ToolDefinition<any, any>, \"renderCall\" | \"renderResult\"> {\n\treturn {\n\t\trenderCall(args, _theme, context) {\n\t\t\tensureShellTimer(context);\n\t\t\tconst component =\n\t\t\t\t(context.lastComponent as BashCallRenderComponent | undefined) ?? new BashCallRenderComponent(config);\n\t\t\tcomponent.update(args as { command?: string; timeout?: number } | undefined, context.expanded);\n\t\t\treturn component;\n\t\t},\n\t\trenderResult(result, options, _theme, context) {\n\t\t\tensureShellTimer(context);\n\t\t\tconst timerText = toolTimerText(context, options.isPartial);\n\t\t\tconst component = (context.lastComponent as Container | undefined) ?? new Container();\n\t\t\tconst submitted = (context.args as { background?: boolean } | undefined)?.background === true;\n\t\t\trebuildBashResultRenderComponent(component, result as any, options, context.showImages, timerText, submitted);\n\t\t\tcomponent.invalidate();\n\t\t\treturn component;\n\t\t},\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/keybindings.ts"],"names":[],"mappings":"AAEA,OAAO,QAAQ,
|
|
1
|
+
{"version":3,"file":"keybindings.d.ts","sourceRoot":"","sources":["../../../src/extensions/btw/keybindings.ts"],"names":[],"mappings":"AAEA,OAAO,QAAQ,wBAAwB,CAAC;IACvC,UAAU,WAAW;QACpB,eAAe,EAAE,IAAI,CAAC;QACtB,gBAAgB,EAAE,IAAI,CAAC;QACvB,kBAAkB,EAAE,IAAI,CAAC;QACzB,oBAAoB,EAAE,IAAI,CAAC;KAC3B;CACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../../../src/extensions/btw/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAWxE,mBAAmB,CAAC;IACnB,eAAe,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,4BAA4B,EAAE;IACrF,gBAAgB,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,yCAAyC,EAAE;IACnG,kBAAkB,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE;IAChG,oBAAoB,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,0CAA0C,EAAE;CACtG,CAAC,CAAC","sourcesContent":["import { registerKeybindings } from \"../../core/keybinding-registry.ts\";\n\ndeclare module \"
|
|
1
|
+
{"version":3,"file":"keybindings.js","sourceRoot":"","sources":["../../../src/extensions/btw/keybindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAWxE,mBAAmB,CAAC;IACnB,eAAe,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,4BAA4B,EAAE;IACrF,gBAAgB,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,yCAAyC,EAAE;IACnG,kBAAkB,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE;IAChG,oBAAoB,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,0CAA0C,EAAE;CACtG,CAAC,CAAC","sourcesContent":["import { registerKeybindings } from \"../../core/keybinding-registry.ts\";\n\ndeclare module \"@earendil-works/pi-tui\" {\n\tinterface Keybindings {\n\t\t\"app.btw.close\": true;\n\t\t\"app.btw.cancel\": true;\n\t\t\"app.btw.scrollUp\": true;\n\t\t\"app.btw.scrollDown\": true;\n\t}\n}\n\nregisterKeybindings({\n\t\"app.btw.close\": { defaultKeys: \"escape\", description: \"Close the BTW conversation\" },\n\t\"app.btw.cancel\": { defaultKeys: \"ctrl+c\", description: \"Stop the BTW answer, or close when idle\" },\n\t\"app.btw.scrollUp\": { defaultKeys: \"up\", description: \"Scroll BTW up when the editor is empty\" },\n\t\"app.btw.scrollDown\": { defaultKeys: \"down\", description: \"Scroll BTW down when the editor is empty\" },\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/extensions/codemode/execute.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAmC,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAsBtG,OAAO,KAAK,EAAE,oBAAoB,EAAiB,MAAM,gCAAgC,CAAC;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAKlE,OAAO,EAMN,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAGxB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/extensions/codemode/execute.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAmC,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAsBtG,OAAO,KAAK,EAAE,oBAAoB,EAAiB,MAAM,gCAAgC,CAAC;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAKlE,OAAO,EAMN,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAGxB,MAAM,WAAW,CAAC;AAgMnB,6FAA6F;AAC7F,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAU1F;AAyLD;;;GAGG;AACH,wBAAsB,eAAe,CACpC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,eAAe,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAC9E,GAAG,EAAE,oBAAoB,GAAG,SAAS,EACrC,OAAO,GAAE,mBAAwB,GAC/B,OAAO,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAoH/C"}
|
|
@@ -61,9 +61,6 @@ function toModelInfo(model) {
|
|
|
61
61
|
function withArticle(word) {
|
|
62
62
|
return `${/^[aeiou]/.test(word) ? "an" : "a"} ${word}`;
|
|
63
63
|
}
|
|
64
|
-
function isRecord(value) {
|
|
65
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
-
}
|
|
67
64
|
/** A script value in an error message: `undefined`, `a string`, `an array`, or its keys (`{ prompt }`). */
|
|
68
65
|
function describeValue(value) {
|
|
69
66
|
if (value === undefined || value === null)
|
|
@@ -82,52 +79,58 @@ const CLASSIFIER_CONTEXT_SHAPE = '{ state: { ... }, images?: [{ type: "image", d
|
|
|
82
79
|
/** Check a script's classifier context, so mistakes fail with the expected shape instead of a provider error. */
|
|
83
80
|
function checkClassifierContext(context) {
|
|
84
81
|
const fail = (problem) => new Error(`models.classify() ${problem}. Expected context: ${CLASSIFIER_CONTEXT_SHAPE}. See "Classify" in ${CODEMODE_DOCS_PATH}.`);
|
|
85
|
-
if (
|
|
82
|
+
if (typeof context !== "object" || context === null || Array.isArray(context)) {
|
|
86
83
|
throw fail(`expects a context object as its second argument, got ${describeValue(context)}`);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
}
|
|
85
|
+
const { state, images, questions } = context;
|
|
86
|
+
if (typeof state !== "object" || state === null || Array.isArray(state)) {
|
|
87
|
+
throw fail(`context.state must be an object, got ${describeValue(state)}`);
|
|
88
|
+
}
|
|
90
89
|
if (images !== undefined) {
|
|
91
90
|
if (!Array.isArray(images))
|
|
92
91
|
throw fail(`context.images must be an array, got ${describeValue(images)}`);
|
|
93
92
|
images.forEach((image, index) => {
|
|
94
|
-
if (
|
|
95
|
-
image.type !== "image" ||
|
|
96
|
-
typeof image.data !== "string" ||
|
|
97
|
-
typeof image.mimeType !== "string") {
|
|
93
|
+
if (image?.type !== "image" || typeof image.data !== "string" || typeof image.mimeType !== "string") {
|
|
98
94
|
throw fail(`context.images[${index}] must be an image block, got ${describeValue(image)}`);
|
|
99
95
|
}
|
|
100
96
|
});
|
|
101
97
|
}
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
if (typeof questions !== "object" ||
|
|
99
|
+
questions === null ||
|
|
100
|
+
Array.isArray(questions) ||
|
|
101
|
+
Object.keys(questions).length === 0) {
|
|
104
102
|
throw fail(`context.questions must map question IDs to questions, got ${describeValue(questions)}`);
|
|
105
103
|
}
|
|
106
104
|
const isStrings = (values) => values.length > 0 && values.every((value) => typeof value === "string");
|
|
107
105
|
for (const [id, question] of Object.entries(questions)) {
|
|
108
106
|
const at = `context.questions.${id}`;
|
|
109
|
-
if (
|
|
107
|
+
if (typeof question !== "object" || question === null || Array.isArray(question)) {
|
|
110
108
|
throw fail(`${at} must be a question object, got ${describeValue(question)}`);
|
|
111
|
-
|
|
109
|
+
}
|
|
110
|
+
const { type, instructions, criteria } = question;
|
|
111
|
+
if (typeof instructions !== "string")
|
|
112
112
|
throw fail(`${at}.instructions must be a string`);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
if (type === "choice") {
|
|
114
|
+
if (typeof criteria !== "object" ||
|
|
115
|
+
criteria === null ||
|
|
116
|
+
Array.isArray(criteria) ||
|
|
117
|
+
!isStrings(Object.values(criteria))) {
|
|
116
118
|
throw fail(`${at} is a "choice" question, so criteria must map each label to its meaning`);
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
|
-
else if (
|
|
121
|
+
else if (type === "score") {
|
|
120
122
|
if (!Array.isArray(criteria) || !isStrings(criteria)) {
|
|
121
123
|
throw fail(`${at} is a "score" question, so criteria must list the levels as strings, lowest first`);
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
|
-
else if (
|
|
125
|
-
|
|
126
|
+
else if (type === "bool") {
|
|
127
|
+
const labels = criteria;
|
|
128
|
+
if (typeof labels?.true !== "string" || typeof labels.false !== "string") {
|
|
126
129
|
throw fail(`${at} is a "bool" question, so criteria must be { true: string, false: string }`);
|
|
127
130
|
}
|
|
128
131
|
}
|
|
129
132
|
else {
|
|
130
|
-
throw fail(`${at}.type must be "choice", "score", or "bool", got ${JSON.stringify(
|
|
133
|
+
throw fail(`${at}.type must be "choice", "score", or "bool", got ${JSON.stringify(type)}`);
|
|
131
134
|
}
|
|
132
135
|
}
|
|
133
136
|
return context;
|
|
@@ -135,21 +138,18 @@ function checkClassifierContext(context) {
|
|
|
135
138
|
/** Check a script's image context, so mistakes such as `{ prompt }` fail with the expected shape. */
|
|
136
139
|
function checkImagesContext(context) {
|
|
137
140
|
const fail = (problem) => new Error(`models.generateImages() ${problem}. Expected context: { input: [{ type: "text", text: <prompt> }, ...optional { type: "image", data: <base64>, mimeType } references] }. See "Generate images" in ${CODEMODE_DOCS_PATH}.`);
|
|
138
|
-
if (
|
|
141
|
+
if (typeof context !== "object" || context === null || Array.isArray(context)) {
|
|
139
142
|
throw fail(`expects a context object as its second argument, got ${describeValue(context)}`);
|
|
143
|
+
}
|
|
140
144
|
const { input } = context;
|
|
141
145
|
if (!Array.isArray(input) || input.length === 0) {
|
|
142
146
|
throw fail(`context.input must be a non-empty array of blocks, got ${describeValue(input)}`);
|
|
143
147
|
}
|
|
144
148
|
input.forEach((block, index) => {
|
|
145
|
-
if (
|
|
149
|
+
if (block?.type === "text" && typeof block.text === "string")
|
|
146
150
|
return;
|
|
147
|
-
if (
|
|
148
|
-
block.type === "image" &&
|
|
149
|
-
typeof block.data === "string" &&
|
|
150
|
-
typeof block.mimeType === "string") {
|
|
151
|
+
if (block?.type === "image" && typeof block.data === "string" && typeof block.mimeType === "string")
|
|
151
152
|
return;
|
|
152
|
-
}
|
|
153
153
|
throw fail(`context.input[${index}] must be a text or image block, got ${describeValue(block)}`);
|
|
154
154
|
});
|
|
155
155
|
return context;
|
|
@@ -232,19 +232,36 @@ function formatOutput(output) {
|
|
|
232
232
|
}
|
|
233
233
|
return items;
|
|
234
234
|
}
|
|
235
|
-
/**
|
|
235
|
+
/**
|
|
236
|
+
* Join adjacent text items into one, each part starting on its own line. The separator check looks
|
|
237
|
+
* at the last non-empty part, not the joined text: reading the end of a growing concatenation makes
|
|
238
|
+
* V8 copy it on every item, which is quadratic (#10678).
|
|
239
|
+
*/
|
|
236
240
|
function joinAdjacentText(items) {
|
|
237
241
|
const joined = [];
|
|
242
|
+
let parts = [];
|
|
243
|
+
let lastPart = "";
|
|
244
|
+
const flush = () => {
|
|
245
|
+
if (parts.length > 0)
|
|
246
|
+
joined.push({ type: "text", text: parts.join("") });
|
|
247
|
+
parts = [];
|
|
248
|
+
lastPart = "";
|
|
249
|
+
};
|
|
238
250
|
for (const item of items) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
const separator = last.text === "" || last.text.endsWith("\n") ? "" : "\n";
|
|
242
|
-
joined[joined.length - 1] = { type: "text", text: `${last.text}${separator}${item.text}` };
|
|
243
|
-
}
|
|
244
|
-
else {
|
|
251
|
+
if (item.type !== "text") {
|
|
252
|
+
flush();
|
|
245
253
|
joined.push(item);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (lastPart !== "" && !lastPart.endsWith("\n")) {
|
|
257
|
+
parts.push("\n");
|
|
258
|
+
lastPart = "\n";
|
|
246
259
|
}
|
|
260
|
+
parts.push(item.text);
|
|
261
|
+
if (item.text !== "")
|
|
262
|
+
lastPart = item.text;
|
|
247
263
|
}
|
|
264
|
+
flush();
|
|
248
265
|
return joined;
|
|
249
266
|
}
|
|
250
267
|
function formatCallSummary(calls) {
|
|
@@ -376,6 +393,8 @@ export async function executeCodemode(toolCallId, input, signal, onUpdate, ctx,
|
|
|
376
393
|
};
|
|
377
394
|
const snapshot = () => ({ calls: calls.map((call) => ({ ...call })) });
|
|
378
395
|
const publish = () => onUpdate?.({ content: [], details: snapshot() });
|
|
396
|
+
// Show the script as running before its first nested call, so the row's timer starts.
|
|
397
|
+
publish();
|
|
379
398
|
const callable = ctx ? getCodemodeCallableTools(ctx.tools) : [];
|
|
380
399
|
// ALL_TOOLS entries carry the declaration.
|
|
381
400
|
const guidelines = options.getToolGuidelines?.();
|
|
@@ -472,14 +491,12 @@ export async function executeCodemode(toolCallId, input, signal, onUpdate, ctx,
|
|
|
472
491
|
};
|
|
473
492
|
}
|
|
474
493
|
/**
|
|
475
|
-
* Whether `query` names the namespace: its name
|
|
476
|
-
* `
|
|
494
|
+
* Whether `query` names the namespace: its name or one of its aliases, as written or as the same
|
|
495
|
+
* script identifier (`dev-radius` and `dev_radius` are both `dev_radius`).
|
|
477
496
|
*/
|
|
478
497
|
function isNamespaceName(namespace, query) {
|
|
479
|
-
const id = toCodemodeIdentifier(namespace);
|
|
480
498
|
const queryId = toCodemodeIdentifier(query);
|
|
481
|
-
|
|
482
|
-
return namespace === query || id === queryId || suffix(namespace) === query || suffix(id) === queryId;
|
|
499
|
+
return [namespace.name, ...(namespace.aliases ?? [])].some((name) => name === query || toCodemodeIdentifier(name) === queryId);
|
|
483
500
|
}
|
|
484
501
|
/**
|
|
485
502
|
* `searchTools()`, `describeTool()`, and `describeNamespace()`: ranked search and lookup over the
|
|
@@ -506,7 +523,7 @@ function createDiscoveryGlobals(tools, samples, options) {
|
|
|
506
523
|
}
|
|
507
524
|
const documents = tools.flatMap((tool) => {
|
|
508
525
|
const toolNamespace = options.getToolNamespace?.(tool.name);
|
|
509
|
-
if (namespace && (!toolNamespace || !isNamespaceName(toolNamespace
|
|
526
|
+
if (namespace && (!toolNamespace || !isNamespaceName(toolNamespace, namespace)))
|
|
510
527
|
return [];
|
|
511
528
|
return [createToolSearchDocument(tool, toolNamespace)];
|
|
512
529
|
});
|
|
@@ -535,7 +552,7 @@ function createDiscoveryGlobals(tools, samples, options) {
|
|
|
535
552
|
const names = [];
|
|
536
553
|
for (const tool of tools) {
|
|
537
554
|
const toolNamespace = options.getToolNamespace?.(tool.name);
|
|
538
|
-
if (!toolNamespace || !isNamespaceName(toolNamespace
|
|
555
|
+
if (!toolNamespace || !isNamespaceName(toolNamespace, name))
|
|
539
556
|
continue;
|
|
540
557
|
namespace ??= toolNamespace;
|
|
541
558
|
names.push(toCodemodeIdentifier(tool.name));
|
|
@@ -566,14 +583,16 @@ function createModelGlobals(models, toolCallId, calls, publish, addUsage, addGen
|
|
|
566
583
|
*/
|
|
567
584
|
const runModelCall = async (name, type, [model, context], checkContext, run) => {
|
|
568
585
|
const listHint = `List the ${type} models you can use with models.getAvailableOfType("${type}").`;
|
|
569
|
-
|
|
586
|
+
const given = model;
|
|
587
|
+
if (typeof given?.provider !== "string" || typeof given.id !== "string") {
|
|
570
588
|
// undefined arrives as null: spread arguments cross the sandbox as a JSON array.
|
|
571
589
|
const undefinedHint = model === undefined || model === null
|
|
572
590
|
? " models.getModelOfType() returns undefined for an unknown provider or id."
|
|
573
591
|
: "";
|
|
574
592
|
throw new Error(`${name}() expects ${withArticle(type)} model as its first argument, got ${describeValue(model)}.${undefinedHint} ${listHint}`);
|
|
575
593
|
}
|
|
576
|
-
const
|
|
594
|
+
const provider = given.provider;
|
|
595
|
+
const id = given.id;
|
|
577
596
|
const ref = `${provider}/${id}`;
|
|
578
597
|
const resolved = models.getModelOfType(type, provider, id);
|
|
579
598
|
if (!resolved) {
|