@earendil-works/pi-coding-agent 0.85.0 → 0.85.1
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 +18 -0
- package/README.md +0 -2
- package/dist/bun/cli.d.ts +3 -1
- package/dist/bun/cli.d.ts.map +1 -1
- package/dist/bun/cli.js +3 -12
- package/dist/bun/cli.js.map +1 -1
- package/dist/bun/sandbox-env-setup.d.ts +2 -0
- package/dist/bun/sandbox-env-setup.d.ts.map +1 -0
- package/dist/bun/sandbox-env-setup.js +4 -0
- package/dist/bun/sandbox-env-setup.js.map +1 -0
- package/dist/bundle/chunks/{anthropic-messages-QAQLEQIY.js → anthropic-messages-VWZZOSJQ.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-Q7MJBRE6.js → azure-openai-responses-BJLAM6CD.js} +1 -1
- package/dist/bundle/chunks/{chunk-R7UUJ4C2.js → chunk-CLNPYIDP.js} +1 -1
- package/dist/bundle/chunks/chunk-JVUZSMYM.js +1547 -0
- package/dist/bundle/chunks/{chunk-2KVJKXS2.js → chunk-U6ZMQKGD.js} +1 -1
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-BSMTYDAM.js → google-generative-ai-Q2K7FBDI.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-5C3HASOJ.js → google-vertex-7UJBF4S7.js} +1 -1
- package/dist/bundle/chunks/{node-EM5FIVUN.js → node-KG362ECQ.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-YJOO52RW.js → openai-codex-responses-R6VYZTVY.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-QOT3QX7D.js → openai-completions-EKZT2IH2.js} +1 -1
- package/dist/bundle/chunks/openai-responses-TFDINO6W.js +2 -0
- package/dist/bundle/chunks/{pi-messages-EGZIFQGG.js → pi-messages-PML4SPVJ.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/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +0 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +12 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -25
- package/dist/cli.js.map +1 -1
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +4 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +0 -122
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +5 -5
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +8 -8
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +4 -4
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/docs/containerization.md +45 -0
- package/docs/development.md +19 -0
- package/docs/environment-variables.md +2 -2
- package/docs/keybindings.md +2 -1
- package/docs/models.md +1 -1
- 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/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- 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 +20 -46
- package/package.json +13 -12
- package/dist/bundle/chunks/chunk-EQ6DR6XK.js +0 -5
- package/dist/bundle/chunks/chunk-LZKJTKCT.js +0 -2
- package/dist/bundle/chunks/chunk-WBE4J4AU.js +0 -9
- package/dist/bundle/chunks/chunk-WZB2R5YO.js +0 -1558
- package/dist/bundle/chunks/openai-responses-U7LNPQN4.js +0 -2
- package/dist/bundle/client.js +0 -2
- package/dist/bundle/coordinator.js +0 -3
- package/dist/cli/experimental/cli.d.ts +0 -10
- package/dist/cli/experimental/cli.d.ts.map +0 -1
- package/dist/cli/experimental/cli.js +0 -9
- package/dist/cli/experimental/cli.js.map +0 -1
- package/dist/cli/experimental/command-options.d.ts +0 -28
- package/dist/cli/experimental/command-options.d.ts.map +0 -1
- package/dist/cli/experimental/command-options.js +0 -84
- package/dist/cli/experimental/command-options.js.map +0 -1
- package/dist/cli/experimental/command.d.ts +0 -70
- package/dist/cli/experimental/command.d.ts.map +0 -1
- package/dist/cli/experimental/command.js +0 -144
- package/dist/cli/experimental/command.js.map +0 -1
- package/dist/cli/experimental/commands/client.d.ts +0 -19
- package/dist/cli/experimental/commands/client.d.ts.map +0 -1
- package/dist/cli/experimental/commands/client.js +0 -63
- package/dist/cli/experimental/commands/client.js.map +0 -1
- package/dist/cli/experimental/commands/server.d.ts +0 -17
- package/dist/cli/experimental/commands/server.d.ts.map +0 -1
- package/dist/cli/experimental/commands/server.js +0 -44
- package/dist/cli/experimental/commands/server.js.map +0 -1
- package/dist/client/index.d.ts +0 -2
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js +0 -2
- package/dist/client/index.js.map +0 -1
- package/dist/experimental/client-runtime.d.ts +0 -43
- package/dist/experimental/client-runtime.d.ts.map +0 -1
- package/dist/experimental/client-runtime.js +0 -183
- package/dist/experimental/client-runtime.js.map +0 -1
- package/dist/experimental/client-tui-chat.d.ts +0 -14
- package/dist/experimental/client-tui-chat.d.ts.map +0 -1
- package/dist/experimental/client-tui-chat.js +0 -171
- package/dist/experimental/client-tui-chat.js.map +0 -1
- package/dist/experimental/client-tui.d.ts +0 -37
- package/dist/experimental/client-tui.d.ts.map +0 -1
- package/dist/experimental/client-tui.js +0 -702
- package/dist/experimental/client-tui.js.map +0 -1
- package/dist/experimental/client.d.ts +0 -25
- package/dist/experimental/client.d.ts.map +0 -1
- package/dist/experimental/client.js +0 -99
- package/dist/experimental/client.js.map +0 -1
- package/dist/experimental/coordinator-entry.d.ts +0 -3
- package/dist/experimental/coordinator-entry.d.ts.map +0 -1
- package/dist/experimental/coordinator-entry.js +0 -11
- package/dist/experimental/coordinator-entry.js.map +0 -1
- package/dist/experimental/coordinator.d.ts +0 -38
- package/dist/experimental/coordinator.d.ts.map +0 -1
- package/dist/experimental/coordinator.js +0 -570
- package/dist/experimental/coordinator.js.map +0 -1
- package/dist/experimental/mini/main.d.ts +0 -7
- package/dist/experimental/mini/main.d.ts.map +0 -1
- package/dist/experimental/mini/main.js +0 -21
- package/dist/experimental/mini/main.js.map +0 -1
- package/dist/experimental/mini/server/entry.d.ts +0 -3
- package/dist/experimental/mini/server/entry.d.ts.map +0 -1
- package/dist/experimental/mini/server/entry.js +0 -11
- package/dist/experimental/mini/server/entry.js.map +0 -1
- package/dist/experimental/mini/server/run.d.ts +0 -13
- package/dist/experimental/mini/server/run.d.ts.map +0 -1
- package/dist/experimental/mini/server/run.js +0 -150
- package/dist/experimental/mini/server/run.js.map +0 -1
- package/dist/experimental/mini/shared/protocol.d.ts +0 -127
- package/dist/experimental/mini/shared/protocol.d.ts.map +0 -1
- package/dist/experimental/mini/shared/protocol.js +0 -13
- package/dist/experimental/mini/shared/protocol.js.map +0 -1
- package/dist/experimental/mini/shared/rpc.d.ts +0 -49
- package/dist/experimental/mini/shared/rpc.d.ts.map +0 -1
- package/dist/experimental/mini/shared/rpc.js +0 -171
- package/dist/experimental/mini/shared/rpc.js.map +0 -1
- package/dist/experimental/mini/shared/transport.d.ts +0 -35
- package/dist/experimental/mini/shared/transport.d.ts.map +0 -1
- package/dist/experimental/mini/shared/transport.js +0 -94
- package/dist/experimental/mini/shared/transport.js.map +0 -1
- package/dist/experimental/mini/tui/run.d.ts +0 -9
- package/dist/experimental/mini/tui/run.d.ts.map +0 -1
- package/dist/experimental/mini/tui/run.js +0 -62
- package/dist/experimental/mini/tui/run.js.map +0 -1
- package/dist/experimental/mini/tui/session.d.ts +0 -26
- package/dist/experimental/mini/tui/session.d.ts.map +0 -1
- package/dist/experimental/mini/tui/session.js +0 -94
- package/dist/experimental/mini/tui/session.js.map +0 -1
- package/dist/experimental/mini/tui/view.d.ts +0 -10
- package/dist/experimental/mini/tui/view.d.ts.map +0 -1
- package/dist/experimental/mini/tui/view.js +0 -459
- package/dist/experimental/mini/tui/view.js.map +0 -1
- package/dist/experimental/mini/worker/entry.d.ts +0 -3
- package/dist/experimental/mini/worker/entry.d.ts.map +0 -1
- package/dist/experimental/mini/worker/entry.js +0 -10
- package/dist/experimental/mini/worker/entry.js.map +0 -1
- package/dist/experimental/mini/worker/lane-service.d.ts +0 -44
- package/dist/experimental/mini/worker/lane-service.d.ts.map +0 -1
- package/dist/experimental/mini/worker/lane-service.js +0 -97
- package/dist/experimental/mini/worker/lane-service.js.map +0 -1
- package/dist/experimental/mini/worker/models-service.d.ts +0 -19
- package/dist/experimental/mini/worker/models-service.d.ts.map +0 -1
- package/dist/experimental/mini/worker/models-service.js +0 -136
- package/dist/experimental/mini/worker/models-service.js.map +0 -1
- package/dist/experimental/mini/worker/run.d.ts +0 -14
- package/dist/experimental/mini/worker/run.d.ts.map +0 -1
- package/dist/experimental/mini/worker/run.js +0 -88
- package/dist/experimental/mini/worker/run.js.map +0 -1
- package/dist/experimental/plugin.d.ts +0 -4
- package/dist/experimental/plugin.d.ts.map +0 -1
- package/dist/experimental/plugin.js +0 -4
- package/dist/experimental/plugin.js.map +0 -1
- package/dist/experimental/plugins/bundled.d.ts +0 -7
- package/dist/experimental/plugins/bundled.d.ts.map +0 -1
- package/dist/experimental/plugins/bundled.js +0 -48
- package/dist/experimental/plugins/bundled.js.map +0 -1
- package/dist/experimental/plugins/package.d.ts +0 -18
- package/dist/experimental/plugins/package.d.ts.map +0 -1
- package/dist/experimental/plugins/package.js +0 -113
- package/dist/experimental/plugins/package.js.map +0 -1
- package/dist/experimental/process.d.ts +0 -20
- package/dist/experimental/process.d.ts.map +0 -1
- package/dist/experimental/process.js +0 -85
- package/dist/experimental/process.js.map +0 -1
- package/dist/experimental/radius-auth.d.ts +0 -17
- package/dist/experimental/radius-auth.d.ts.map +0 -1
- package/dist/experimental/radius-auth.js +0 -52
- package/dist/experimental/radius-auth.js.map +0 -1
- package/dist/experimental/radius-relay.d.ts +0 -90
- package/dist/experimental/radius-relay.d.ts.map +0 -1
- package/dist/experimental/radius-relay.js +0 -582
- package/dist/experimental/radius-relay.js.map +0 -1
- package/dist/experimental/server.d.ts +0 -75
- package/dist/experimental/server.d.ts.map +0 -1
- package/dist/experimental/server.js +0 -682
- package/dist/experimental/server.js.map +0 -1
- package/dist/experimental/services/agent-controller-provider.d.ts +0 -4
- package/dist/experimental/services/agent-controller-provider.d.ts.map +0 -1
- package/dist/experimental/services/agent-controller-provider.js +0 -84
- package/dist/experimental/services/agent-controller-provider.js.map +0 -1
- package/dist/experimental/services/agent-controller.d.ts +0 -57
- package/dist/experimental/services/agent-controller.d.ts.map +0 -1
- package/dist/experimental/services/agent-controller.js +0 -3
- package/dist/experimental/services/agent-controller.js.map +0 -1
- package/dist/experimental/services/connection.d.ts +0 -40
- package/dist/experimental/services/connection.d.ts.map +0 -1
- package/dist/experimental/services/connection.js +0 -300
- package/dist/experimental/services/connection.js.map +0 -1
- package/dist/experimental/services/models-provider.d.ts +0 -16
- package/dist/experimental/services/models-provider.d.ts.map +0 -1
- package/dist/experimental/services/models-provider.js +0 -116
- package/dist/experimental/services/models-provider.js.map +0 -1
- package/dist/experimental/services/models.d.ts +0 -36
- package/dist/experimental/services/models.d.ts.map +0 -1
- package/dist/experimental/services/models.js +0 -3
- package/dist/experimental/services/models.js.map +0 -1
- package/dist/experimental/services/plugins.d.ts +0 -16
- package/dist/experimental/services/plugins.d.ts.map +0 -1
- package/dist/experimental/services/plugins.js +0 -4
- package/dist/experimental/services/plugins.js.map +0 -1
- package/dist/experimental/services/presentation-ui.d.ts +0 -13
- package/dist/experimental/services/presentation-ui.d.ts.map +0 -1
- package/dist/experimental/services/presentation-ui.js +0 -3
- package/dist/experimental/services/presentation-ui.js.map +0 -1
- package/dist/experimental/services/server.d.ts +0 -19
- package/dist/experimental/services/server.d.ts.map +0 -1
- package/dist/experimental/services/server.js +0 -104
- package/dist/experimental/services/server.js.map +0 -1
- package/dist/experimental/services/sessions.d.ts +0 -28
- package/dist/experimental/services/sessions.d.ts.map +0 -1
- package/dist/experimental/services/sessions.js +0 -4
- package/dist/experimental/services/sessions.js.map +0 -1
- package/dist/experimental/services/slash-commands-provider.d.ts +0 -14
- package/dist/experimental/services/slash-commands-provider.d.ts.map +0 -1
- package/dist/experimental/services/slash-commands-provider.js +0 -200
- package/dist/experimental/services/slash-commands-provider.js.map +0 -1
- package/dist/experimental/services/slash-commands.d.ts +0 -24
- package/dist/experimental/services/slash-commands.d.ts.map +0 -1
- package/dist/experimental/services/slash-commands.js +0 -3
- package/dist/experimental/services/slash-commands.js.map +0 -1
- package/dist/experimental/services/transcript-provider.d.ts +0 -12
- package/dist/experimental/services/transcript-provider.d.ts.map +0 -1
- package/dist/experimental/services/transcript-provider.js +0 -109
- package/dist/experimental/services/transcript-provider.js.map +0 -1
- package/dist/experimental/services/transcript.d.ts +0 -13
- package/dist/experimental/services/transcript.d.ts.map +0 -1
- package/dist/experimental/services/transcript.js +0 -3
- package/dist/experimental/services/transcript.js.map +0 -1
- package/dist/experimental/services/worker.d.ts +0 -28
- package/dist/experimental/services/worker.d.ts.map +0 -1
- package/dist/experimental/services/worker.js +0 -107
- package/dist/experimental/services/worker.js.map +0 -1
- package/dist/experimental/session-worker-manager.d.ts +0 -24
- package/dist/experimental/session-worker-manager.d.ts.map +0 -1
- package/dist/experimental/session-worker-manager.js +0 -691
- package/dist/experimental/session-worker-manager.js.map +0 -1
- package/dist/experimental/session-worker.d.ts +0 -188
- package/dist/experimental/session-worker.d.ts.map +0 -1
- package/dist/experimental/session-worker.js +0 -785
- package/dist/experimental/session-worker.js.map +0 -1
- package/dist/experimental/source-resolver.d.ts +0 -2
- package/dist/experimental/source-resolver.d.ts.map +0 -1
- package/dist/experimental/source-resolver.js +0 -71
- package/dist/experimental/source-resolver.js.map +0 -1
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { type FacetLoader } from "@earendil-works/chord";
|
|
2
|
-
import { type Component, type TUI } from "@earendil-works/pi-tui";
|
|
3
|
-
import type { ClientCommand } from "../cli/experimental/commands/client.ts";
|
|
4
|
-
import { type OpenClientRuntimeOptions } from "./client-runtime.ts";
|
|
5
|
-
import type { ServerServiceSource, SessionServiceSource } from "./services/connection.ts";
|
|
6
|
-
export interface RunClientTuiOptions extends OpenClientRuntimeOptions {
|
|
7
|
-
readonly facetLoader?: FacetLoader;
|
|
8
|
-
}
|
|
9
|
-
export interface ClientTuiServer {
|
|
10
|
-
readonly serverId: string;
|
|
11
|
-
readonly radius: boolean;
|
|
12
|
-
readonly server: ServerServiceSource;
|
|
13
|
-
readonly session: SessionServiceSource;
|
|
14
|
-
}
|
|
15
|
-
/** Service-only presentation driven by a replicated main-lane snapshot. */
|
|
16
|
-
export declare class ExperimentalClientTui implements Component {
|
|
17
|
-
#private;
|
|
18
|
-
private constructor();
|
|
19
|
-
static create(options: {
|
|
20
|
-
readonly command: ClientCommand;
|
|
21
|
-
readonly ui: TUI;
|
|
22
|
-
readonly servers: readonly ClientTuiServer[];
|
|
23
|
-
readonly facetLoader?: FacetLoader;
|
|
24
|
-
requestRender(): void;
|
|
25
|
-
finish(): void;
|
|
26
|
-
}): Promise<ExperimentalClientTui>;
|
|
27
|
-
get layoutRoot(): Component;
|
|
28
|
-
render(width: number): string[];
|
|
29
|
-
handleInput(data: string): void;
|
|
30
|
-
invalidate(): void;
|
|
31
|
-
dispose(): void;
|
|
32
|
-
refreshTheme(): void;
|
|
33
|
-
showError(error: string): void;
|
|
34
|
-
close(): Promise<void>;
|
|
35
|
-
}
|
|
36
|
-
export declare function runClientTui(command: ClientCommand, options?: RunClientTuiOptions): Promise<void>;
|
|
37
|
-
//# sourceMappingURL=client-tui.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client-tui.d.ts","sourceRoot":"","sources":["../../src/experimental/client-tui.ts"],"names":[],"mappings":"AACA,OAAO,EAKN,KAAK,WAAW,EAGhB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAEN,KAAK,SAAS,EAMd,KAAK,GAAG,EACR,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAU5E,OAAO,EAAE,KAAK,wBAAwB,EAAqB,MAAM,qBAAqB,CAAC;AAIvF,OAAO,KAAK,EAEX,mBAAmB,EAEnB,oBAAoB,EACpB,MAAM,0BAA0B,CAAC;AAWlC,MAAM,WAAW,mBAAoB,SAAQ,wBAAwB;IACpE,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;CACnC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;CACvC;AA6BD,2EAA2E;AAC3E,qBAAa,qBAAsB,YAAW,SAAS;;IAiCtD,OAAO,eA6BN;IAED,OAAa,MAAM,CAAC,OAAO,EAAE;QAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAChC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC;QACjB,QAAQ,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,CAAC;QAC7C,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;QACnC,aAAa,IAAI,IAAI,CAAC;QACtB,MAAM,IAAI,IAAI,CAAC;KACf,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkBjC;IAED,IAAI,UAAU,IAAI,SAAS,CAE1B;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ9B;IAED,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAgB9B;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,OAAO,IAAI,IAAI,CAEd;IAED,YAAY,IAAI,IAAI,CAInB;IAED,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG7B;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAGrB;CAuYD;AAoGD,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoE3G","sourcesContent":["import { resolve } from \"node:path\";\nimport {\n\tcombineFacetLoaders,\n\tcreateFacetHost,\n\tdefineFacet,\n\ttype FacetHost,\n\ttype FacetLoader,\n\ttype JsonValue,\n\ttype LoadedFacets,\n} from \"@earendil-works/chord\";\nimport { BACKGROUND_CONTEXT } from \"@earendil-works/chord/context\";\nimport {\n\tCombinedAutocompleteProvider,\n\ttype Component,\n\tContainer,\n\ttype SelectItem,\n\tSelectList,\n\tsetKeybindings,\n\tText,\n\ttype TUI,\n} from \"@earendil-works/pi-tui\";\nimport type { ClientCommand } from \"../cli/experimental/commands/client.ts\";\nimport { getAgentDir } from \"../config.ts\";\nimport { KeybindingsManager } from \"../core/keybindings.ts\";\nimport { DefaultResourceLoader } from \"../core/resource-loader.ts\";\nimport { SettingsManager } from \"../core/settings-manager.ts\";\nimport { createChatViewport } from \"../modes/interactive/chat-viewport.ts\";\nimport { CustomEditor } from \"../modes/interactive/components/custom-editor.ts\";\nimport { getEditorTheme, setRegisteredThemes, stopThemeWatcher, theme } from \"../modes/interactive/theme/theme.ts\";\nimport { InteractiveThemeController } from \"../modes/interactive/theme/theme-controller.ts\";\nimport { createInteractiveTui } from \"../modes/interactive/tui-renderer.ts\";\nimport { type OpenClientRuntimeOptions, openClientRuntime } from \"./client-runtime.ts\";\nimport { ExperimentalChatView } from \"./client-tui-chat.ts\";\nimport { createPresentationFacetLoaders } from \"./plugins/bundled.ts\";\nimport { AgentController, type AgentOperationResponse, type AgentQueueResponse } from \"./services/agent-controller.ts\";\nimport type {\n\tServerConnectionState,\n\tServerServiceSource,\n\tSessionAttachmentState,\n\tSessionServiceSource,\n} from \"./services/connection.ts\";\nimport { PresentationPlugins } from \"./services/plugins.ts\";\nimport { PresentationUI } from \"./services/presentation-ui.ts\";\nimport { SessionDirectory, SessionManagement, type SessionSummary } from \"./services/sessions.ts\";\nimport { SlashCommands } from \"./services/slash-commands.ts\";\nimport {\n\tcreateBuiltInSlashCommandsFacet,\n\tcreateSlashCommandsRuntimeFacet,\n} from \"./services/slash-commands-provider.ts\";\nimport { Transcript, type Transcript as TranscriptService } from \"./services/transcript.ts\";\n\nexport interface RunClientTuiOptions extends OpenClientRuntimeOptions {\n\treadonly facetLoader?: FacetLoader;\n}\n\nexport interface ClientTuiServer {\n\treadonly serverId: string;\n\treadonly radius: boolean;\n\treadonly server: ServerServiceSource;\n\treadonly session: SessionServiceSource;\n}\n\ninterface SessionFeature {\n\treadonly serverId: string;\n\treadonly session: SessionServiceSource;\n\treadonly transcript: TranscriptService;\n}\n\ninterface PreparedClientSession {\n\treadonly server: ClientTuiServer;\n\treadonly summary: SessionSummary;\n\treadonly presentationPlugins: JsonValue;\n}\n\ninterface PendingSelection {\n\treadonly title: string;\n\treadonly items: readonly SelectItem[];\n\treadonly selectedValue?: string;\n\tresolve(value: string | undefined): void;\n}\n\nconst selectTheme = {\n\tselectedPrefix: (text: string) => theme.fg(\"accent\", text),\n\tselectedText: (text: string) => theme.fg(\"accent\", text),\n\tdescription: (text: string) => theme.fg(\"muted\", text),\n\tscrollInfo: (text: string) => theme.fg(\"dim\", text),\n\tnoMatch: (text: string) => theme.fg(\"warning\", text),\n};\n\n/** Service-only presentation driven by a replicated main-lane snapshot. */\nexport class ExperimentalClientTui implements Component {\n\treadonly #ui: TUI;\n\treadonly #requestRender: () => void;\n\treadonly #finish: () => void;\n\treadonly #documentContainer = new Container();\n\treadonly #sessionHeading = new Text(\"\", 1, 0);\n\treadonly #pendingMessagesContainer = new Container();\n\treadonly #statusContainer = new Container();\n\treadonly #editorContainer = new Container();\n\treadonly #footerComponent = new Text(\"\", 1, 0);\n\treadonly #layoutRoot: Component;\n\treadonly #sharedFacets: LoadedFacets;\n\treadonly #keybindings = KeybindingsManager.create();\n\t#presentationFacets: LoadedFacets | undefined;\n\t#facetHost: FacetHost | undefined;\n\t#facetReloadTail = Promise.resolve();\n\t#session: SessionFeature | undefined;\n\t#slashCommands: SlashCommands | undefined;\n\t#controller: AgentController | undefined;\n\treadonly #chatInput: CustomEditor;\n\t#selectList: SelectList | undefined;\n\t#selection: PendingSelection | undefined;\n\t#screen: \"select\" | \"chat\" = \"chat\";\n\t#selectedServerId: string | undefined;\n\t#sessionId: string | undefined;\n\t#status = \"Starting Session…\";\n\t#busy = false;\n\t#closed = false;\n\t#closePromise: Promise<void> | undefined;\n\t#recoveryTransition: Promise<void> = Promise.resolve();\n\t#laneUnsubscribe: (() => void) | undefined;\n\t#chatView: ExperimentalChatView | undefined;\n\n\tprivate constructor(ui: TUI, requestRender: () => void, finish: () => void, loadedFacets: LoadedFacets) {\n\t\tthis.#ui = ui;\n\t\tthis.#requestRender = requestRender;\n\t\tthis.#finish = finish;\n\t\tthis.#sharedFacets = loadedFacets;\n\t\tsetKeybindings(this.#keybindings);\n\t\tthis.#chatInput = new CustomEditor(ui, getEditorTheme(), this.#keybindings, { paddingX: 1 });\n\t\tthis.#chatInput.onSubmit = (message) => void this.#runPrompt(message);\n\t\tthis.#chatInput.onEscape = () => this.#interrupt();\n\t\tthis.#chatInput.onCtrlD = finish;\n\t\tthis.#chatInput.onAction(\"app.clear\", finish);\n\t\tthis.#chatInput.onAction(\"app.model.select\", () => void this.#executeSlashCommand(\"model\", \"\"));\n\t\tthis.#chatInput.onAction(\"app.message.followUp\", () => {\n\t\t\tconst text = this.#chatInput.getText().trim();\n\t\t\tif (text.length === 0) return;\n\t\t\tthis.#chatInput.setText(\"\");\n\t\t\tvoid this.#queueFollowUp(text);\n\t\t});\n\t\tthis.#editorContainer.addChild(this.#chatInput);\n\t\tthis.#layoutRoot = createChatViewport({\n\t\t\tdocument: this.#documentContainer,\n\t\t\tpendingMessages: this.#pendingMessagesContainer,\n\t\t\tstatus: this.#statusContainer,\n\t\t\teditor: this.#editorContainer,\n\t\t\tfooter: this.#footerComponent,\n\t\t\tscrollbarTrackStyle: (text) => theme.fg(\"scrollbarTrack\", text),\n\t\t\tscrollbarThumbStyle: (text) => theme.fg(\"scrollbarThumb\", text),\n\t\t}).root;\n\t\tthis.#rebuild();\n\t}\n\n\tstatic async create(options: {\n\t\treadonly command: ClientCommand;\n\t\treadonly ui: TUI;\n\t\treadonly servers: readonly ClientTuiServer[];\n\t\treadonly facetLoader?: FacetLoader;\n\t\trequestRender(): void;\n\t\tfinish(): void;\n\t}): Promise<ExperimentalClientTui> {\n\t\tconst prepared = await prepareClientSession(options.command, options.servers);\n\t\tconst loadedFacets = await combineFacetLoaders(\n\t\t\toptions.facetLoader === undefined ? [] : [options.facetLoader],\n\t\t).load();\n\t\tconst component = new ExperimentalClientTui(options.ui, options.requestRender, options.finish, loadedFacets);\n\t\ttry {\n\t\t\tawait component.#start(prepared);\n\t\t\tawait component.#openPreparedSession(prepared);\n\t\t\treturn component;\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tawait component.close();\n\t\t\t} catch (cleanupError) {\n\t\t\t\tthrow new AggregateError([error, cleanupError], \"Experimental TUI startup and cleanup failed\");\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tget layoutRoot(): Component {\n\t\treturn this.#layoutRoot;\n\t}\n\n\trender(width: number): string[] {\n\t\treturn [\n\t\t\t...this.#documentContainer.render(width),\n\t\t\t...this.#pendingMessagesContainer.render(width),\n\t\t\t...this.#statusContainer.render(width),\n\t\t\t...this.#editorContainer.render(width),\n\t\t\t...this.#footerComponent.render(width),\n\t\t];\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.#busy) {\n\t\t\tif (\n\t\t\t\tthis.#keybindings.matches(data, \"app.clear\") ||\n\t\t\t\t(this.#chatInput.getText().length === 0 && this.#keybindings.matches(data, \"app.exit\"))\n\t\t\t) {\n\t\t\t\tthis.#finish();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (this.#screen === \"chat\") {\n\t\t\tthis.#chatInput.handleInput(data);\n\t\t\tthis.#requestRender();\n\t\t\treturn;\n\t\t}\n\t\tthis.#selectList?.handleInput(data);\n\t}\n\n\tinvalidate(): void {\n\t\tthis.#layoutRoot.invalidate();\n\t}\n\n\tdispose(): void {\n\t\tvoid this.close().catch(() => {});\n\t}\n\n\trefreshTheme(): void {\n\t\tconst snapshot = this.#laneSnapshot();\n\t\tif (snapshot !== undefined) this.#chatView?.refreshTheme(snapshot);\n\t\tthis.#rebuild();\n\t}\n\n\tshowError(error: string): void {\n\t\tthis.#status = `Error: ${error}`;\n\t\tthis.#rebuild();\n\t}\n\n\tclose(): Promise<void> {\n\t\tthis.#closePromise ??= this.#close();\n\t\treturn this.#closePromise;\n\t}\n\n\tasync #start(prepared: PreparedClientSession): Promise<void> {\n\t\tconst server = prepared.server;\n\t\tlet presentationFacets = await combineFacetLoaders(\n\t\t\tcreatePresentationFacetLoaders(prepared.presentationPlugins),\n\t\t).load();\n\t\tthis.#presentationFacets = presentationFacets;\n\t\tlet facetHost!: FacetHost;\n\t\tconst reloadPresentationPlugins = (data: JsonValue): Promise<void> => {\n\t\t\tconst operation = this.#facetReloadTail.then(async () => {\n\t\t\t\tconst candidate = await combineFacetLoaders(createPresentationFacetLoaders(data)).load();\n\t\t\t\ttry {\n\t\t\t\t\tawait facetHost.reload(candidate.facets);\n\t\t\t\t} catch (error) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait candidate.dispose();\n\t\t\t\t\t} catch (cleanupError) {\n\t\t\t\t\t\tthrow new AggregateError([error, cleanupError], \"TUI plugin reload and cleanup failed\");\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tconst retired = presentationFacets;\n\t\t\t\tpresentationFacets = candidate;\n\t\t\t\tthis.#presentationFacets = candidate;\n\t\t\t\tawait retired.dispose();\n\t\t\t});\n\t\t\tthis.#facetReloadTail = operation.catch(() => {});\n\t\t\treturn operation;\n\t\t};\n\t\tconst presentationBridgeFacet = defineFacet({\n\t\t\tid: \"@pi/presentation-bridge\",\n\t\t\tsetup: (env) => {\n\t\t\t\tenv.provide(PresentationUI, {\n\t\t\t\t\tselect: (title, items, selectedValue) =>\n\t\t\t\t\t\tthis.#select(\n\t\t\t\t\t\t\ttitle,\n\t\t\t\t\t\t\titems.map((item) => ({ ...item })),\n\t\t\t\t\t\t\tselectedValue,\n\t\t\t\t\t\t),\n\t\t\t\t\tshowStatus: (status) => {\n\t\t\t\t\t\tthis.#status = status;\n\t\t\t\t\t\tthis.#rebuild();\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tconst commands = env.use(SlashCommands);\n\t\t\t\tconst controller = env.use(AgentController);\n\t\t\t\tconst transcript = env.use(Transcript);\n\t\t\t\tconst sessionFeature: SessionFeature = {\n\t\t\t\t\tserverId: server.serverId,\n\t\t\t\t\tsession: server.session,\n\t\t\t\t\ttranscript,\n\t\t\t\t};\n\t\t\t\tenv.onActivate(() => {\n\t\t\t\t\tif (this.#session !== undefined || this.#slashCommands !== undefined || this.#controller !== undefined) {\n\t\t\t\t\t\tthrow new Error(\"Presentation services are already active\");\n\t\t\t\t\t}\n\t\t\t\t\tthis.#session = sessionFeature;\n\t\t\t\t\tthis.#slashCommands = commands;\n\t\t\t\t\tthis.#controller = controller;\n\t\t\t\t\tenv.own(() => {\n\t\t\t\t\t\tif (this.#session === sessionFeature) this.#session = undefined;\n\t\t\t\t\t\tif (this.#slashCommands === commands) this.#slashCommands = undefined;\n\t\t\t\t\t\tif (this.#controller === controller) this.#controller = undefined;\n\t\t\t\t\t});\n\t\t\t\t\tenv.own(commands.subscribe(() => this.#updateAutocomplete()));\n\t\t\t\t\tif (server.radius) {\n\t\t\t\t\t\tenv.own(\n\t\t\t\t\t\t\tserver.server.connection.subscribe((state) => this.#handleConnectionState(server.serverId, state)),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tenv.own(\n\t\t\t\t\t\t\tserver.session.attachment.subscribe((state) => this.#handleAttachmentState(sessionFeature, state)),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t\tfacetHost = await createFacetHost({\n\t\t\tfacets: [\n\t\t\t\tcreateSlashCommandsRuntimeFacet(),\n\t\t\t\tpresentationBridgeFacet,\n\t\t\t\tcreateBuiltInSlashCommandsFacet({ reloadPresentationPlugins }),\n\t\t\t\t...this.#sharedFacets.facets,\n\t\t\t\t...presentationFacets.facets,\n\t\t\t],\n\t\t\tserviceSources: [server.server, server.session],\n\t\t});\n\t\tthis.#facetHost = facetHost;\n\t}\n\n\tasync #openPreparedSession(prepared: PreparedClientSession): Promise<void> {\n\t\tconst feature = this.#session;\n\t\tif (feature === undefined) throw new Error(`No Session service is available for ${prepared.server.serverId}`);\n\t\tawait feature.session.whenAttached(prepared.summary.sessionId, BACKGROUND_CONTEXT);\n\t\tthis.#selectedServerId = feature.serverId;\n\t\tthis.#sessionId = prepared.summary.sessionId;\n\t\tthis.#updateAutocomplete();\n\t\tawait this.#openLane(feature);\n\t\tthis.#screen = \"chat\";\n\t\tthis.#status = \"\";\n\t\tthis.#rebuild();\n\t}\n\n\tasync #close(): Promise<void> {\n\t\tthis.#closed = true;\n\t\tthis.#completeSelection(undefined);\n\t\tconst errors: unknown[] = [];\n\t\ttry {\n\t\t\tawait this.#recoveryTransition;\n\t\t\tawait this.#closeLane();\n\t\t\tawait this.#facetReloadTail;\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tif (this.#facetHost !== undefined) {\n\t\t\ttry {\n\t\t\t\tawait this.#facetHost.dispose();\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error);\n\t\t\t}\n\t\t\tthis.#facetHost = undefined;\n\t\t}\n\t\tconst generations = [this.#presentationFacets, this.#sharedFacets].filter(\n\t\t\t(generation): generation is LoadedFacets => generation !== undefined,\n\t\t);\n\t\tthis.#presentationFacets = undefined;\n\t\tconst results = await Promise.allSettled(generations.map((generation) => generation.dispose()));\n\t\terrors.push(...results.flatMap((result) => (result.status === \"rejected\" ? [result.reason] : [])));\n\t\tif (errors.length === 1) throw errors[0];\n\t\tif (errors.length > 1) throw new AggregateError(errors, \"Failed to dispose experimental TUI facets\");\n\t}\n\n\t#rebuild(): void {\n\t\tthis.#sessionHeading.setText(\n\t\t\tthis.#sessionId === undefined || this.#selectedServerId === undefined\n\t\t\t\t? \"\"\n\t\t\t\t: theme.fg(\"dim\", `Server: ${this.#selectedServerId}\\nSession: ${this.#sessionId}`),\n\t\t);\n\t\tthis.#statusContainer.clear();\n\t\tif (this.#status.length > 0) {\n\t\t\tthis.#statusContainer.addChild(new Text(theme.fg(\"dim\", this.#status), 1, 0));\n\t\t}\n\t\tif (this.#chatView !== undefined) this.#statusContainer.addChild(this.#chatView.status);\n\t\tthis.#footerComponent.setText(theme.fg(\"dim\", this.#footer()));\n\t\tthis.#editorContainer.clear();\n\t\tif (this.#screen === \"select\" && this.#selection !== undefined) {\n\t\t\tthis.#chatInput.focused = false;\n\t\t\tconst selector = new Container();\n\t\t\tselector.addChild(new Text(theme.bold(this.#selection.title), 1, 1));\n\t\t\tconst items = [...this.#selection.items];\n\t\t\tthis.#selectList = new SelectList(items, Math.min(Math.max(items.length, 1), 12), selectTheme);\n\t\t\tconst selectedIndex = items.findIndex((item) => item.value === this.#selection?.selectedValue);\n\t\t\tif (selectedIndex >= 0) this.#selectList.setSelectedIndex(selectedIndex);\n\t\t\tthis.#selectList.onSelect = (item) => this.#completeSelection(item.value);\n\t\t\tthis.#selectList.onCancel = () => this.#completeSelection(undefined);\n\t\t\tselector.addChild(this.#selectList);\n\t\t\tthis.#editorContainer.addChild(selector);\n\t\t} else {\n\t\t\tthis.#selectList = undefined;\n\t\t\tthis.#chatInput.focused = !this.#busy;\n\t\t\tthis.#editorContainer.addChild(this.#chatInput);\n\t\t}\n\t\tthis.#layoutRoot.invalidate();\n\t\tthis.#requestRender();\n\t}\n\n\t#select(title: string, items: readonly SelectItem[], selectedValue?: string): Promise<string | undefined> {\n\t\tif (this.#selection !== undefined) throw new Error(\"A slash command selector is already active\");\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.#selection = { title, items, ...(selectedValue === undefined ? {} : { selectedValue }), resolve };\n\t\t\tthis.#screen = \"select\";\n\t\t\tthis.#rebuild();\n\t\t});\n\t}\n\n\t#completeSelection(value: string | undefined): void {\n\t\tconst selection = this.#selection;\n\t\tif (selection === undefined) return;\n\t\tthis.#selection = undefined;\n\t\tthis.#screen = \"chat\";\n\t\tselection.resolve(value);\n\t\tif (!this.#closed) this.#rebuild();\n\t}\n\n\t#updateAutocomplete(): void {\n\t\tconst commands = this.#selectedSlashCommands()?.list() ?? [];\n\t\tthis.#chatInput.setAutocompleteProvider(\n\t\t\tnew CombinedAutocompleteProvider(\n\t\t\t\tcommands.map((command) => ({\n\t\t\t\t\tname: command.name,\n\t\t\t\t\tdescription: command.description,\n\t\t\t\t\t...(command.argumentHint === undefined ? {} : { argumentHint: command.argumentHint }),\n\t\t\t\t\t...(command.getArgumentCompletions === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tgetArgumentCompletions: async (prefix: string) => {\n\t\t\t\t\t\t\t\t\tconst items = await command.getArgumentCompletions!(prefix);\n\t\t\t\t\t\t\t\t\treturn items === null ? null : [...items];\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}),\n\t\t\t\t})),\n\t\t\t\tprocess.cwd(),\n\t\t\t),\n\t\t);\n\t\tthis.#requestRender();\n\t}\n\n\t#selectedSlashCommands(): SlashCommands | undefined {\n\t\treturn this.#slashCommands;\n\t}\n\n\t#handleConnectionState(serverId: string, state: ServerConnectionState): void {\n\t\tif (this.#closed || this.#selectedServerId !== serverId) return;\n\t\tif (state.status === \"connected\") {\n\t\t\tif (this.#laneUnsubscribe === undefined) {\n\t\t\t\tthis.#busy = true;\n\t\t\t\tthis.#status = \"Reattaching Session…\";\n\t\t\t\tthis.#rebuild();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.#busy = true;\n\t\tthis.#status = state.status === \"connecting\" ? \"Reconnecting to Radius…\" : \"Radius disconnected; retrying…\";\n\t\tthis.#queueRecovery(() => this.#closeLane());\n\t\tthis.#rebuild();\n\t}\n\n\t#handleAttachmentState(feature: SessionFeature, state: SessionAttachmentState): void {\n\t\tif (this.#closed || this.#selectedServerId !== feature.serverId || this.#sessionId === undefined) return;\n\t\tif (state.status === \"attached\" && state.sessionId === this.#sessionId) {\n\t\t\tthis.#queueRecovery(async () => {\n\t\t\t\tif (this.#laneUnsubscribe === undefined) await this.#openLane(feature);\n\t\t\t\tthis.#busy = false;\n\t\t\t\tthis.#status = \"\";\n\t\t\t\tthis.#rebuild();\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (state.status === \"attaching\" && state.sessionId === this.#sessionId) {\n\t\t\tthis.#busy = true;\n\t\t\tthis.#status = \"Reattaching Session…\";\n\t\t\tthis.#rebuild();\n\t\t}\n\t}\n\n\t#queueRecovery(operation: () => Promise<void>): void {\n\t\tthis.#recoveryTransition = this.#recoveryTransition\n\t\t\t.then(async () => {\n\t\t\t\tif (!this.#closed) await operation();\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (this.#closed) return;\n\t\t\t\tthis.#busy = true;\n\t\t\t\tthis.#status = `Reconnect error: ${message(error)}`;\n\t\t\t\tthis.#rebuild();\n\t\t\t});\n\t}\n\n\tasync #openLane(feature: SessionFeature): Promise<void> {\n\t\tawait this.#closeLane();\n\t\tconst view = new ExperimentalChatView(this.#ui, process.cwd());\n\t\tthis.#chatView = view;\n\t\tthis.#documentContainer.addChild(this.#sessionHeading);\n\t\tthis.#documentContainer.addChild(view.transcript);\n\t\tthis.#pendingMessagesContainer.addChild(view.pendingMessages);\n\t\tthis.#laneUnsubscribe = feature.transcript.state.subscribe((value) => {\n\t\t\tif (value.snapshot === null) return;\n\t\t\tview.apply(value.snapshot);\n\t\t\tthis.#rebuild();\n\t\t});\n\t\tif (feature.transcript.state.value?.snapshot === null || feature.transcript.state.value?.snapshot === undefined) {\n\t\t\tawait this.#closeLane();\n\t\t\tthrow new Error(\"Transcript has no initialized snapshot\");\n\t\t}\n\t}\n\n\tasync #closeLane(): Promise<void> {\n\t\tthis.#laneUnsubscribe?.();\n\t\tthis.#laneUnsubscribe = undefined;\n\t\tthis.#chatView?.dispose();\n\t\tthis.#chatView = undefined;\n\t\tthis.#documentContainer.clear();\n\t\tthis.#pendingMessagesContainer.clear();\n\t\tthis.#statusContainer.clear();\n\t}\n\n\tasync #runPrompt(messageText: string): Promise<void> {\n\t\tconst prompt = messageText.trim();\n\t\tif (prompt.length === 0) return;\n\t\tif (prompt.startsWith(\"/\")) {\n\t\t\tconst separator = prompt.indexOf(\" \");\n\t\t\tconst name = prompt.slice(1, separator === -1 ? undefined : separator);\n\t\t\tconst args = separator === -1 ? \"\" : prompt.slice(separator + 1).trim();\n\t\t\tawait this.#executeSlashCommand(name, args);\n\t\t\treturn;\n\t\t}\n\t\tthis.#chatInput.setText(\"\");\n\t\ttry {\n\t\t\tawait this.#submitPrompt(prompt);\n\t\t} catch (error) {\n\t\t\tthis.#status = `Error: ${message(error)}`;\n\t\t\tthis.#rebuild();\n\t\t}\n\t}\n\n\tasync #executeSlashCommand(name: string, args: string): Promise<void> {\n\t\tconst command = this.#selectedSlashCommands()\n\t\t\t?.list()\n\t\t\t.find((candidate) => candidate.name === name);\n\t\tthis.#chatInput.setText(\"\");\n\t\tif (command === undefined) {\n\t\t\tthis.#status = `Unknown slash command: /${name}`;\n\t\t\tthis.#rebuild();\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tconst result = await command.run(args, BACKGROUND_CONTEXT);\n\t\t\tif (result !== undefined) {\n\t\t\t\tif (\"entryId\" in result) this.#reportQueue(result);\n\t\t\t\telse this.#reportOperation(result);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis.#status = `Error: ${message(error)}`;\n\t\t\tthis.#rebuild();\n\t\t}\n\t}\n\n\tasync #submitPrompt(prompt: string): Promise<void> {\n\t\tconst controller = this.#selectedController();\n\t\tif (controller === undefined) throw new Error(\"No Session AgentController service is available\");\n\t\tconst operation = this.#laneSnapshot()?.operation;\n\t\tconst running = operation !== null && operation !== undefined;\n\t\tthis.#status = running ? \"Queueing steering message…\" : \"Running turn…\";\n\t\tthis.#rebuild();\n\t\tif (running) this.#reportQueue(await controller.steer({ message: prompt, images: null }, BACKGROUND_CONTEXT));\n\t\telse this.#reportOperation(await controller.prompt({ message: prompt, images: null }, BACKGROUND_CONTEXT));\n\t}\n\n\tasync #queueFollowUp(text: string): Promise<void> {\n\t\tconst controller = this.#selectedController();\n\t\tif (controller === undefined) return;\n\t\ttry {\n\t\t\tthis.#status = \"Queueing follow-up…\";\n\t\t\tthis.#rebuild();\n\t\t\tthis.#reportQueue(await controller.followUp({ message: text, images: null }, BACKGROUND_CONTEXT));\n\t\t} catch (error) {\n\t\t\tthis.#status = `Error: ${message(error)}`;\n\t\t\tthis.#rebuild();\n\t\t}\n\t}\n\n\t#reportOperation(response: AgentOperationResponse): void {\n\t\tthis.#status = response.accepted\n\t\t\t? response.error === null\n\t\t\t\t? \"\"\n\t\t\t\t: `Operation failed: ${response.error.message}`\n\t\t\t: `Operation rejected: ${response.error.message}`;\n\t\tthis.#rebuild();\n\t}\n\n\t#reportQueue(response: AgentQueueResponse): void {\n\t\tthis.#status = response.accepted ? `Queued ${response.entryId}.` : `Message rejected: ${response.error.message}`;\n\t\tthis.#rebuild();\n\t}\n\n\t#interrupt(): void {\n\t\tconst operation = this.#laneSnapshot()?.operation;\n\t\tconst controller = this.#selectedController();\n\t\tif (operation === null || operation === undefined || controller === undefined) return;\n\t\tthis.#status = `Aborting ${operation.id}…`;\n\t\tthis.#rebuild();\n\t\tvoid controller.requestAbort(operation.id, BACKGROUND_CONTEXT).catch((error: unknown) => {\n\t\t\tthis.#status = `Error: ${message(error)}`;\n\t\t\tthis.#rebuild();\n\t\t});\n\t}\n\n\t#selectedController(): AgentController | undefined {\n\t\treturn this.#controller;\n\t}\n\n\t#laneSnapshot() {\n\t\tconst snapshot = this.#session?.transcript.state.value?.snapshot;\n\t\treturn snapshot === null ? undefined : snapshot;\n\t}\n\n\t#footer(): string {\n\t\tconst snapshot = this.#laneSnapshot();\n\t\tif (!snapshot) return \"/model · /thinking · /compact · /reload\";\n\t\treturn `${snapshot.configuration.model.provider}/${snapshot.configuration.model.modelId} · thinking:${snapshot.configuration.thinkingLevel} · ${snapshot.stats.messageCount} messages · /model · /thinking · /compact · /reload`;\n\t}\n}\n\nasync function prepareClientSession(\n\tcommand: ClientCommand,\n\tservers: readonly ClientTuiServer[],\n): Promise<PreparedClientSession> {\n\tconst opened = servers.map((server) => ({\n\t\tserver,\n\t\tservices: server.server.open({\n\t\t\tservices: [SessionDirectory, SessionManagement, PresentationPlugins],\n\t\t\tassertAccess() {},\n\t\t\tonError() {},\n\t\t}),\n\t}));\n\ttry {\n\t\tconst features = opened.map(({ server, services }) => ({\n\t\t\tserver,\n\t\t\tdirectory: services.use(SessionDirectory),\n\t\t\tmanagement: services.use(SessionManagement),\n\t\t\tplugins: services.use(PresentationPlugins),\n\t\t}));\n\t\tawait Promise.all(opened.map(({ services }) => services.ready(BACKGROUND_CONTEXT)));\n\t\tlet selected:\n\t\t\t| {\n\t\t\t\t\treadonly server: ClientTuiServer;\n\t\t\t\t\treadonly management: SessionManagement;\n\t\t\t\t\treadonly plugins: PresentationPlugins;\n\t\t\t\t\treadonly summary: SessionSummary;\n\t\t\t }\n\t\t\t| undefined;\n\t\tif (command.sessionId !== undefined) {\n\t\t\tconst matches = features.flatMap((feature) =>\n\t\t\t\t(feature.directory.state.value?.sessions ?? [])\n\t\t\t\t\t.filter((session) => session.sessionId === command.sessionId)\n\t\t\t\t\t.map((summary) => ({\n\t\t\t\t\t\tserver: feature.server,\n\t\t\t\t\t\tmanagement: feature.management,\n\t\t\t\t\t\tplugins: feature.plugins,\n\t\t\t\t\t\tsummary,\n\t\t\t\t\t})),\n\t\t\t);\n\t\t\tif (matches.length > 1) throw new Error(`Session ${command.sessionId} is available from more than one server`);\n\t\t\tselected = matches[0];\n\t\t\tif (selected === undefined) {\n\t\t\t\tif (command.connect?.transport === \"radius\") {\n\t\t\t\t\tthrow new Error(`Remote server does not contain Session ${command.sessionId}`);\n\t\t\t\t}\n\t\t\t\tconst feature = requireSingleServer(features);\n\t\t\t\tselected = {\n\t\t\t\t\tserver: feature.server,\n\t\t\t\t\tmanagement: feature.management,\n\t\t\t\t\tplugins: feature.plugins,\n\t\t\t\t\tsummary: await feature.management.create({ id: command.sessionId }, BACKGROUND_CONTEXT),\n\t\t\t\t};\n\t\t\t}\n\t\t} else if (command.continue === true || command.resume === true) {\n\t\t\tselected = features\n\t\t\t\t.flatMap((feature) =>\n\t\t\t\t\t(feature.directory.state.value?.sessions ?? []).map((summary) => ({\n\t\t\t\t\t\tserver: feature.server,\n\t\t\t\t\t\tmanagement: feature.management,\n\t\t\t\t\t\tplugins: feature.plugins,\n\t\t\t\t\t\tsummary,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.sort(\n\t\t\t\t\t(left, right) =>\n\t\t\t\t\t\tright.summary.createdAt - left.summary.createdAt ||\n\t\t\t\t\t\tleft.summary.serverId.localeCompare(right.summary.serverId) ||\n\t\t\t\t\t\tleft.summary.sessionId.localeCompare(right.summary.sessionId),\n\t\t\t\t)[0];\n\t\t}\n\t\tif (selected === undefined) {\n\t\t\tconst feature = requireSingleServer(features);\n\t\t\tselected = {\n\t\t\t\tserver: feature.server,\n\t\t\t\tmanagement: feature.management,\n\t\t\t\tplugins: feature.plugins,\n\t\t\t\tsummary: await feature.management.create({}, BACKGROUND_CONTEXT),\n\t\t\t};\n\t\t}\n\t\tconst presentationPlugins = await selected.plugins.prepareSession(\n\t\t\t{\n\t\t\t\tsessionId: selected.summary.sessionId,\n\t\t\t\tpackagePaths: command.pluginPackages?.map((packagePath) => resolve(packagePath)) ?? null,\n\t\t\t},\n\t\t\tBACKGROUND_CONTEXT,\n\t\t);\n\t\tawait selected.management.attach(selected.summary.sessionId, BACKGROUND_CONTEXT);\n\t\tawait selected.server.session.whenAttached(selected.summary.sessionId, BACKGROUND_CONTEXT);\n\t\treturn {\n\t\t\tserver: selected.server,\n\t\t\tsummary: selected.summary,\n\t\t\tpresentationPlugins,\n\t\t};\n\t} finally {\n\t\tawait Promise.allSettled(opened.map(({ services }) => services.dispose(BACKGROUND_CONTEXT)));\n\t}\n}\n\nexport async function runClientTui(command: ClientCommand, options: RunClientTuiOptions = {}): Promise<void> {\n\tconst cwd = process.cwd();\n\tconst agentDir = getAgentDir();\n\tconst settingsManager = SettingsManager.create(cwd, agentDir);\n\tconst resourceLoader = new DefaultResourceLoader({\n\t\tcwd,\n\t\tagentDir,\n\t\tsettingsManager,\n\t\tnoExtensions: true,\n\t\tnoSkills: true,\n\t\tnoPromptTemplates: true,\n\t\tnoContextFiles: true,\n\t});\n\tawait resourceLoader.reload();\n\tsetRegisteredThemes(resourceLoader.getThemes().themes);\n\tconst runtime = await openClientRuntime(command, options);\n\tconst tui = createInteractiveTui({\n\t\ttuiMode: \"fullscreen\",\n\t\tshowHardwareCursor: settingsManager.getShowHardwareCursor(),\n\t\tlogDirectory: agentDir,\n\t});\n\ttui.setClearOnShrink(settingsManager.getClearOnShrink());\n\tlet component: ExperimentalClientTui | undefined;\n\tlet tuiStarted = false;\n\tconst themeController = new InteractiveThemeController(tui, {\n\t\tgetSettingsManager: () => settingsManager,\n\t\tshowError: (error) => component?.showError(error),\n\t\tonChanged: () => component?.refreshTheme(),\n\t});\n\ttry {\n\t\tlet finish!: () => void;\n\t\tconst finished = new Promise<void>((resolve) => {\n\t\t\tfinish = () => {\n\t\t\t\tthemeController.disableAutoSync();\n\t\t\t\tif (tuiStarted) {\n\t\t\t\t\ttui.stop();\n\t\t\t\t\ttuiStarted = false;\n\t\t\t\t}\n\t\t\t\tresolve();\n\t\t\t};\n\t\t});\n\t\tcomponent = await ExperimentalClientTui.create({\n\t\t\tcommand,\n\t\t\tui: tui,\n\t\t\tservers: runtime.servers.map((server) => ({\n\t\t\t\tserverId: server.route.serverId,\n\t\t\t\tradius: server.route.transport === \"radius\",\n\t\t\t\tserver: server.server,\n\t\t\t\tsession: server.session,\n\t\t\t})),\n\t\t\tfacetLoader: options.facetLoader,\n\t\t\trequestRender: () => tui.requestRender(),\n\t\t\tfinish,\n\t\t});\n\t\ttui.addChild(component);\n\t\ttui.setLayoutRoot(component.layoutRoot);\n\t\ttui.setFocus(component);\n\t\ttuiStarted = true;\n\t\ttui.start();\n\t\tawait themeController.applyFromSettings();\n\t\tawait finished;\n\t} finally {\n\t\tthemeController.dispose();\n\t\tstopThemeWatcher();\n\t\tif (tuiStarted) tui.stop();\n\t\tawait component?.close();\n\t\tawait runtime.dispose();\n\t}\n}\n\nfunction requireSingleServer<T>(features: readonly T[]): T {\n\tif (features.length !== 1) throw new Error(\"Starting a Session requires exactly one server\");\n\treturn features[0]!;\n}\n\nfunction message(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n"]}
|