@mariozechner/pi-coding-agent 0.30.2 → 0.31.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 +244 -1
- package/README.md +105 -84
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +5 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/file-processor.d.ts +3 -3
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +7 -10
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +73 -34
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +464 -210
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -2
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +2 -2
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts +2 -2
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +2 -2
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +84 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
- package/dist/core/compaction/branch-summarization.js +233 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -0
- package/dist/core/{compaction.d.ts → compaction/compaction.d.ts} +38 -19
- package/dist/core/compaction/compaction.d.ts.map +1 -0
- package/dist/core/compaction/compaction.js +558 -0
- package/dist/core/compaction/compaction.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -0
- package/dist/core/compaction/index.d.ts.map +1 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/index.js.map +1 -0
- package/dist/core/compaction/utils.d.ts +35 -0
- package/dist/core/compaction/utils.d.ts.map +1 -0
- package/dist/core/compaction/utils.js +138 -0
- package/dist/core/compaction/utils.js.map +1 -0
- package/dist/core/custom-tools/index.d.ts +2 -1
- package/dist/core/custom-tools/index.d.ts.map +1 -1
- package/dist/core/custom-tools/index.js +1 -0
- package/dist/core/custom-tools/index.js.map +1 -1
- package/dist/core/custom-tools/loader.d.ts.map +1 -1
- package/dist/core/custom-tools/loader.js +13 -80
- package/dist/core/custom-tools/loader.js.map +1 -1
- package/dist/core/custom-tools/types.d.ts +84 -59
- package/dist/core/custom-tools/types.d.ts.map +1 -1
- package/dist/core/custom-tools/types.js.map +1 -1
- package/dist/core/custom-tools/wrapper.d.ts +15 -0
- package/dist/core/custom-tools/wrapper.d.ts.map +1 -0
- package/dist/core/custom-tools/wrapper.js +23 -0
- package/dist/core/custom-tools/wrapper.js.map +1 -0
- package/dist/core/exec.d.ts +29 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +71 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/export-html/index.d.ts +17 -0
- package/dist/core/export-html/index.d.ts.map +1 -0
- package/dist/core/export-html/index.js +171 -0
- package/dist/core/export-html/index.js.map +1 -0
- package/dist/core/export-html/template.css +781 -0
- package/dist/core/export-html/template.html +54 -0
- package/dist/core/export-html/template.js +1185 -0
- package/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/dist/core/export-html/vendor/marked.min.js +6 -0
- package/dist/core/hooks/index.d.ts +4 -4
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js +3 -3
- package/dist/core/hooks/index.js.map +1 -1
- package/dist/core/hooks/loader.d.ts +40 -5
- package/dist/core/hooks/loader.d.ts.map +1 -1
- package/dist/core/hooks/loader.js +43 -10
- package/dist/core/hooks/loader.js.map +1 -1
- package/dist/core/hooks/runner.d.ts +94 -18
- package/dist/core/hooks/runner.d.ts.map +1 -1
- package/dist/core/hooks/runner.js +199 -120
- package/dist/core/hooks/runner.js.map +1 -1
- package/dist/core/hooks/tool-wrapper.d.ts +1 -1
- package/dist/core/hooks/tool-wrapper.d.ts.map +1 -1
- package/dist/core/hooks/tool-wrapper.js +36 -19
- package/dist/core/hooks/tool-wrapper.js.map +1 -1
- package/dist/core/hooks/types.d.ts +407 -96
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/core/index.d.ts +4 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +44 -12
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +82 -34
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -5
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +7 -7
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +7 -7
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +45 -14
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/sdk.d.ts +7 -10
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +88 -32
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +202 -36
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +565 -133
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +9 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +13 -12
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +6 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +33 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -0
- package/dist/core/tools/edit-diff.js +171 -0
- package/dist/core/tools/edit-diff.js.map +1 -0
- package/dist/core/tools/edit.d.ts +7 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +20 -95
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +22 -21
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +3 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +6 -2
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +12 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.js +30 -0
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts +14 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.js +35 -0
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +14 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +36 -0
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +5 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +5 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +12 -6
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +57 -25
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/hook-editor.d.ts +15 -0
- package/dist/modes/interactive/components/hook-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/hook-editor.js +95 -0
- package/dist/modes/interactive/components/hook-editor.js.map +1 -0
- package/dist/modes/interactive/components/hook-message.d.ts +18 -0
- package/dist/modes/interactive/components/hook-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/hook-message.js +80 -0
- package/dist/modes/interactive/components/hook-message.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +3 -3
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +15 -2
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +70 -21
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts +52 -0
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector.js +745 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +3 -3
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +2 -5
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +29 -12
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +589 -208
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +13 -1
- package/dist/modes/interactive/theme/light.json +13 -1
- package/dist/modes/interactive/theme/theme-schema.json +34 -0
- package/dist/modes/interactive/theme/theme.d.ts +20 -2
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +135 -2
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts +3 -3
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +26 -20
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +13 -10
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +11 -10
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +88 -35
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +30 -11
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/shell.d.ts +4 -2
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +36 -7
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +2 -2
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/compaction.md +388 -0
- package/docs/custom-tools.md +146 -43
- package/docs/extension-loading.md +1004 -0
- package/docs/hooks.md +562 -596
- package/docs/rpc.md +33 -19
- package/docs/sdk.md +93 -21
- package/docs/session-tree-plan.md +441 -0
- package/docs/session.md +172 -21
- package/docs/skills.md +2 -0
- package/docs/theme.md +31 -2
- package/docs/tree.md +197 -0
- package/docs/tui.md +343 -0
- package/examples/README.md +1 -9
- package/examples/custom-tools/hello/index.ts +4 -3
- package/examples/custom-tools/question/index.ts +4 -4
- package/examples/custom-tools/subagent/index.ts +7 -6
- package/examples/custom-tools/todo/index.ts +11 -5
- package/examples/hooks/README.md +29 -71
- package/examples/hooks/auto-commit-on-exit.ts +8 -9
- package/examples/hooks/confirm-destructive.ts +29 -30
- package/examples/hooks/custom-compaction.ts +20 -21
- package/examples/hooks/dirty-repo-guard.ts +41 -40
- package/examples/hooks/file-trigger.ts +10 -5
- package/examples/hooks/git-checkpoint.ts +16 -12
- package/examples/hooks/handoff.ts +150 -0
- package/examples/hooks/permission-gate.ts +1 -1
- package/examples/hooks/protected-paths.ts +1 -1
- package/examples/hooks/qna.ts +119 -0
- package/examples/hooks/snake.ts +343 -0
- package/examples/hooks/status-line.ts +40 -0
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/02-custom-model.ts +1 -1
- package/examples/sdk/03-custom-prompt.ts +1 -1
- package/examples/sdk/04-skills.ts +1 -1
- package/examples/sdk/05-tools.ts +4 -4
- package/examples/sdk/06-hooks.ts +1 -1
- package/examples/sdk/07-context-files.ts +1 -1
- package/examples/sdk/08-slash-commands.ts +6 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
- package/examples/sdk/10-settings.ts +1 -1
- package/examples/sdk/11-sessions.ts +1 -1
- package/examples/sdk/12-full-control.ts +4 -7
- package/package.json +6 -6
- package/dist/core/compaction.d.ts.map +0 -1
- package/dist/core/compaction.js +0 -412
- package/dist/core/compaction.js.map +0 -1
- package/dist/core/export-html.d.ts +0 -23
- package/dist/core/export-html.d.ts.map +0 -1
- package/dist/core/export-html.js +0 -1185
- package/dist/core/export-html.js.map +0 -1
- package/dist/modes/interactive/components/compaction.d.ts +0 -15
- package/dist/modes/interactive/components/compaction.d.ts.map +0 -1
- package/dist/modes/interactive/components/compaction.js +0 -41
- package/dist/modes/interactive/components/compaction.js.map +0 -1
- package/docs/hooks-v2.md +0 -385
- package/docs/session-tree.md +0 -452
|
@@ -4,50 +4,55 @@
|
|
|
4
4
|
* Custom tools are TypeScript modules that define additional tools for the agent.
|
|
5
5
|
* They can provide custom rendering for tool calls and results in the TUI.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { AgentToolResult, AgentToolUpdateCallback } from "@mariozechner/pi-agent-core";
|
|
8
|
+
import type { Model } from "@mariozechner/pi-ai";
|
|
8
9
|
import type { Component } from "@mariozechner/pi-tui";
|
|
9
10
|
import type { Static, TSchema } from "@sinclair/typebox";
|
|
10
11
|
import type { Theme } from "../../modes/interactive/theme/theme.js";
|
|
12
|
+
import type { ExecOptions, ExecResult } from "../exec.js";
|
|
11
13
|
import type { HookUIContext } from "../hooks/types.js";
|
|
12
|
-
import type {
|
|
14
|
+
import type { ModelRegistry } from "../model-registry.js";
|
|
15
|
+
import type { ReadonlySessionManager } from "../session-manager.js";
|
|
13
16
|
/** Alias for clarity */
|
|
14
|
-
export type
|
|
17
|
+
export type CustomToolUIContext = HookUIContext;
|
|
15
18
|
/** Re-export for custom tools to use in execute signature */
|
|
16
|
-
export type { AgentToolUpdateCallback };
|
|
17
|
-
export
|
|
18
|
-
stdout: string;
|
|
19
|
-
stderr: string;
|
|
20
|
-
code: number;
|
|
21
|
-
/** True if the process was killed due to signal or timeout */
|
|
22
|
-
killed?: boolean;
|
|
23
|
-
}
|
|
24
|
-
export interface ExecOptions {
|
|
25
|
-
/** AbortSignal to cancel the process */
|
|
26
|
-
signal?: AbortSignal;
|
|
27
|
-
/** Timeout in milliseconds */
|
|
28
|
-
timeout?: number;
|
|
29
|
-
}
|
|
19
|
+
export type { AgentToolResult, AgentToolUpdateCallback };
|
|
20
|
+
export type { ExecOptions, ExecResult } from "../exec.js";
|
|
30
21
|
/** API passed to custom tool factory (stable across session changes) */
|
|
31
|
-
export interface
|
|
22
|
+
export interface CustomToolAPI {
|
|
32
23
|
/** Current working directory */
|
|
33
24
|
cwd: string;
|
|
34
25
|
/** Execute a command */
|
|
35
26
|
exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
|
|
36
|
-
/** UI methods for user interaction (select, confirm, input, notify) */
|
|
37
|
-
ui:
|
|
27
|
+
/** UI methods for user interaction (select, confirm, input, notify, custom) */
|
|
28
|
+
ui: CustomToolUIContext;
|
|
38
29
|
/** Whether UI is available (false in print/RPC mode) */
|
|
39
30
|
hasUI: boolean;
|
|
40
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Context passed to tool execute and onSession callbacks.
|
|
34
|
+
* Provides access to session state and model information.
|
|
35
|
+
*/
|
|
36
|
+
export interface CustomToolContext {
|
|
37
|
+
/** Session manager (read-only) */
|
|
38
|
+
sessionManager: ReadonlySessionManager;
|
|
39
|
+
/** Model registry - use for API key resolution and model retrieval */
|
|
40
|
+
modelRegistry: ModelRegistry;
|
|
41
|
+
/** Current model (may be undefined if no model is selected yet) */
|
|
42
|
+
model: Model<any> | undefined;
|
|
43
|
+
/** Whether the agent is idle (not streaming) */
|
|
44
|
+
isIdle(): boolean;
|
|
45
|
+
/** Whether there are queued messages waiting to be processed */
|
|
46
|
+
hasQueuedMessages(): boolean;
|
|
47
|
+
/** Abort the current agent operation (fire-and-forget, does not wait) */
|
|
48
|
+
abort(): void;
|
|
49
|
+
}
|
|
41
50
|
/** Session event passed to onSession callback */
|
|
42
|
-
export interface
|
|
43
|
-
/** All session entries (including pre-compaction history) */
|
|
44
|
-
entries: SessionEntry[];
|
|
45
|
-
/** Current session file path, or null in --no-session mode */
|
|
46
|
-
sessionFile: string | null;
|
|
47
|
-
/** Previous session file path, or null for "start" and "new" */
|
|
48
|
-
previousSessionFile: string | null;
|
|
51
|
+
export interface CustomToolSessionEvent {
|
|
49
52
|
/** Reason for the session event */
|
|
50
|
-
reason: "start" | "switch" | "branch" | "
|
|
53
|
+
reason: "start" | "switch" | "branch" | "tree" | "shutdown";
|
|
54
|
+
/** Previous session file path, or undefined for "start" and "shutdown" */
|
|
55
|
+
previousSessionFile: string | undefined;
|
|
51
56
|
}
|
|
52
57
|
/** Rendering options passed to renderResult */
|
|
53
58
|
export interface RenderResultOptions {
|
|
@@ -56,55 +61,75 @@ export interface RenderResultOptions {
|
|
|
56
61
|
/** Whether this is a partial/streaming result */
|
|
57
62
|
isPartial: boolean;
|
|
58
63
|
}
|
|
64
|
+
export type CustomToolResult<TDetails = any> = AgentToolResult<TDetails>;
|
|
59
65
|
/**
|
|
60
|
-
* Custom tool
|
|
66
|
+
* Custom tool definition.
|
|
67
|
+
*
|
|
68
|
+
* Custom tools are standalone - they don't extend AgentTool directly.
|
|
69
|
+
* When loaded, they are wrapped in an AgentTool for the agent to use.
|
|
61
70
|
*
|
|
62
|
-
* The execute
|
|
63
|
-
*
|
|
64
|
-
* - The callback emits partial results to subscribers (e.g. TUI/RPC), not to the LLM.
|
|
65
|
-
* - Partial updates should use the same TDetails type as the final result (use a union if needed).
|
|
71
|
+
* The execute callback receives a ToolContext with access to session state,
|
|
72
|
+
* model registry, and current model.
|
|
66
73
|
*
|
|
67
74
|
* @example
|
|
68
75
|
* ```typescript
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
76
|
+
* const factory: CustomToolFactory = (pi) => ({
|
|
77
|
+
* name: "my_tool",
|
|
78
|
+
* label: "My Tool",
|
|
79
|
+
* description: "Does something useful",
|
|
80
|
+
* parameters: Type.Object({ input: Type.String() }),
|
|
72
81
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
82
|
+
* async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
83
|
+
* // Access session state via ctx.sessionManager
|
|
84
|
+
* // Access model registry via ctx.modelRegistry
|
|
85
|
+
* // Current model via ctx.model
|
|
86
|
+
* return { content: [{ type: "text", text: "Done" }] };
|
|
87
|
+
* },
|
|
88
|
+
*
|
|
89
|
+
* onSession(event, ctx) {
|
|
90
|
+
* if (event.reason === "shutdown") {
|
|
91
|
+
* // Cleanup
|
|
92
|
+
* }
|
|
93
|
+
* // Reconstruct state from ctx.sessionManager.getEntries()
|
|
81
94
|
* }
|
|
82
|
-
*
|
|
83
|
-
* }
|
|
95
|
+
* });
|
|
84
96
|
* ```
|
|
85
|
-
*
|
|
86
|
-
* Progress updates are rendered via renderResult with isPartial: true.
|
|
87
97
|
*/
|
|
88
|
-
export interface
|
|
89
|
-
/**
|
|
90
|
-
|
|
98
|
+
export interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {
|
|
99
|
+
/** Tool name (used in LLM tool calls) */
|
|
100
|
+
name: string;
|
|
101
|
+
/** Human-readable label for UI */
|
|
102
|
+
label: string;
|
|
103
|
+
/** Description for LLM */
|
|
104
|
+
description: string;
|
|
105
|
+
/** Parameter schema (TypeBox) */
|
|
106
|
+
parameters: TParams;
|
|
107
|
+
/**
|
|
108
|
+
* Execute the tool.
|
|
109
|
+
* @param toolCallId - Unique ID for this tool call
|
|
110
|
+
* @param params - Parsed parameters matching the schema
|
|
111
|
+
* @param onUpdate - Callback for streaming partial results (for UI, not LLM)
|
|
112
|
+
* @param ctx - Context with session manager, model registry, and current model
|
|
113
|
+
* @param signal - Optional abort signal for cancellation
|
|
114
|
+
*/
|
|
115
|
+
execute(toolCallId: string, params: Static<TParams>, onUpdate: AgentToolUpdateCallback<TDetails> | undefined, ctx: CustomToolContext, signal?: AbortSignal): Promise<AgentToolResult<TDetails>>;
|
|
116
|
+
/** Called on session lifecycle events - use to reconstruct state or cleanup resources */
|
|
117
|
+
onSession?: (event: CustomToolSessionEvent, ctx: CustomToolContext) => void | Promise<void>;
|
|
91
118
|
/** Custom rendering for tool call display - return a Component */
|
|
92
119
|
renderCall?: (args: Static<TParams>, theme: Theme) => Component;
|
|
93
120
|
/** Custom rendering for tool result display - return a Component */
|
|
94
|
-
renderResult?: (result:
|
|
95
|
-
/** Called when session ends - cleanup resources */
|
|
96
|
-
dispose?: () => Promise<void> | void;
|
|
121
|
+
renderResult?: (result: CustomToolResult<TDetails>, options: RenderResultOptions, theme: Theme) => Component;
|
|
97
122
|
}
|
|
98
123
|
/** Factory function that creates a custom tool or array of tools */
|
|
99
|
-
export type CustomToolFactory = (pi:
|
|
100
|
-
/** Loaded custom tool with metadata */
|
|
124
|
+
export type CustomToolFactory = (pi: CustomToolAPI) => CustomTool<any, any> | CustomTool<any, any>[] | Promise<CustomTool<any, any> | CustomTool<any, any>[]>;
|
|
125
|
+
/** Loaded custom tool with metadata and wrapped AgentTool */
|
|
101
126
|
export interface LoadedCustomTool {
|
|
102
127
|
/** Original path (as specified) */
|
|
103
128
|
path: string;
|
|
104
129
|
/** Resolved absolute path */
|
|
105
130
|
resolvedPath: string;
|
|
106
|
-
/** The tool instance */
|
|
107
|
-
tool:
|
|
131
|
+
/** The original custom tool instance */
|
|
132
|
+
tool: CustomTool;
|
|
108
133
|
}
|
|
109
134
|
/** Result from loading custom tools */
|
|
110
135
|
export interface CustomToolsLoadResult {
|
|
@@ -114,6 +139,6 @@ export interface CustomToolsLoadResult {
|
|
|
114
139
|
error: string;
|
|
115
140
|
}>;
|
|
116
141
|
/** Update the UI context for all loaded tools. Call when mode initializes. */
|
|
117
|
-
setUIContext(uiContext:
|
|
142
|
+
setUIContext(uiContext: CustomToolUIContext, hasUI: boolean): void;
|
|
118
143
|
}
|
|
119
144
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/custom-tools/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/custom-tools/types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom tool types.\n *\n * Custom tools are TypeScript modules that define additional tools for the agent.\n * They can provide custom rendering for tool calls and results in the TUI.\n */\n\nimport type { AgentToolResult, AgentToolUpdateCallback } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { Component } from \"@mariozechner/pi-tui\";\nimport type { Static, TSchema } from \"@sinclair/typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ExecOptions, ExecResult } from \"../exec.js\";\nimport type { HookUIContext } from \"../hooks/types.js\";\nimport type { ModelRegistry } from \"../model-registry.js\";\nimport type { ReadonlySessionManager } from \"../session-manager.js\";\n\n/** Alias for clarity */\nexport type CustomToolUIContext = HookUIContext;\n\n/** Re-export for custom tools to use in execute signature */\nexport type { AgentToolResult, AgentToolUpdateCallback };\n\n// Re-export for backward compatibility\nexport type { ExecOptions, ExecResult } from \"../exec.js\";\n\n/** API passed to custom tool factory (stable across session changes) */\nexport interface CustomToolAPI {\n\t/** Current working directory */\n\tcwd: string;\n\t/** Execute a command */\n\texec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;\n\t/** UI methods for user interaction (select, confirm, input, notify, custom) */\n\tui: CustomToolUIContext;\n\t/** Whether UI is available (false in print/RPC mode) */\n\thasUI: boolean;\n}\n\n/**\n * Context passed to tool execute and onSession callbacks.\n * Provides access to session state and model information.\n */\nexport interface CustomToolContext {\n\t/** Session manager (read-only) */\n\tsessionManager: ReadonlySessionManager;\n\t/** Model registry - use for API key resolution and model retrieval */\n\tmodelRegistry: ModelRegistry;\n\t/** Current model (may be undefined if no model is selected yet) */\n\tmodel: Model<any> | undefined;\n\t/** Whether the agent is idle (not streaming) */\n\tisIdle(): boolean;\n\t/** Whether there are queued messages waiting to be processed */\n\thasQueuedMessages(): boolean;\n\t/** Abort the current agent operation (fire-and-forget, does not wait) */\n\tabort(): void;\n}\n\n/** Session event passed to onSession callback */\nexport interface CustomToolSessionEvent {\n\t/** Reason for the session event */\n\treason: \"start\" | \"switch\" | \"branch\" | \"tree\" | \"shutdown\";\n\t/** Previous session file path, or undefined for \"start\" and \"shutdown\" */\n\tpreviousSessionFile: string | undefined;\n}\n\n/** Rendering options passed to renderResult */\nexport interface RenderResultOptions {\n\t/** Whether the result view is expanded */\n\texpanded: boolean;\n\t/** Whether this is a partial/streaming result */\n\tisPartial: boolean;\n}\n\nexport type CustomToolResult<TDetails = any> = AgentToolResult<TDetails>;\n\n/**\n * Custom tool definition.\n *\n * Custom tools are standalone - they don't extend AgentTool directly.\n * When loaded, they are wrapped in an AgentTool for the agent to use.\n *\n * The execute callback receives a ToolContext with access to session state,\n * model registry, and current model.\n *\n * @example\n * ```typescript\n * const factory: CustomToolFactory = (pi) => ({\n * name: \"my_tool\",\n * label: \"My Tool\",\n * description: \"Does something useful\",\n * parameters: Type.Object({ input: Type.String() }),\n *\n * async execute(toolCallId, params, onUpdate, ctx, signal) {\n * // Access session state via ctx.sessionManager\n * // Access model registry via ctx.modelRegistry\n * // Current model via ctx.model\n * return { content: [{ type: \"text\", text: \"Done\" }] };\n * },\n *\n * onSession(event, ctx) {\n * if (event.reason === \"shutdown\") {\n * // Cleanup\n * }\n * // Reconstruct state from ctx.sessionManager.getEntries()\n * }\n * });\n * ```\n */\nexport interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {\n\t/** Tool name (used in LLM tool calls) */\n\tname: string;\n\t/** Human-readable label for UI */\n\tlabel: string;\n\t/** Description for LLM */\n\tdescription: string;\n\t/** Parameter schema (TypeBox) */\n\tparameters: TParams;\n\n\t/**\n\t * Execute the tool.\n\t * @param toolCallId - Unique ID for this tool call\n\t * @param params - Parsed parameters matching the schema\n\t * @param onUpdate - Callback for streaming partial results (for UI, not LLM)\n\t * @param ctx - Context with session manager, model registry, and current model\n\t * @param signal - Optional abort signal for cancellation\n\t */\n\texecute(\n\t\ttoolCallId: string,\n\t\tparams: Static<TParams>,\n\t\tonUpdate: AgentToolUpdateCallback<TDetails> | undefined,\n\t\tctx: CustomToolContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentToolResult<TDetails>>;\n\n\t/** Called on session lifecycle events - use to reconstruct state or cleanup resources */\n\tonSession?: (event: CustomToolSessionEvent, ctx: CustomToolContext) => void | Promise<void>;\n\t/** Custom rendering for tool call display - return a Component */\n\trenderCall?: (args: Static<TParams>, theme: Theme) => Component;\n\n\t/** Custom rendering for tool result display - return a Component */\n\trenderResult?: (result: CustomToolResult<TDetails>, options: RenderResultOptions, theme: Theme) => Component;\n}\n\n/** Factory function that creates a custom tool or array of tools */\nexport type CustomToolFactory = (\n\tpi: CustomToolAPI,\n) => CustomTool<any, any> | CustomTool<any, any>[] | Promise<CustomTool<any, any> | CustomTool<any, any>[]>;\n\n/** Loaded custom tool with metadata and wrapped AgentTool */\nexport interface LoadedCustomTool {\n\t/** Original path (as specified) */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** The original custom tool instance */\n\ttool: CustomTool;\n}\n\n/** Result from loading custom tools */\nexport interface CustomToolsLoadResult {\n\ttools: LoadedCustomTool[];\n\terrors: Array<{ path: string; error: string }>;\n\t/** Update the UI context for all loaded tools. Call when mode initializes. */\n\tsetUIContext(uiContext: CustomToolUIContext, hasUI: boolean): void;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/custom-tools/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * Custom tool types.\n *\n * Custom tools are TypeScript modules that define additional tools for the agent.\n * They can provide custom rendering for tool calls and results in the TUI.\n */\n\nimport type {
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/custom-tools/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * Custom tool types.\n *\n * Custom tools are TypeScript modules that define additional tools for the agent.\n * They can provide custom rendering for tool calls and results in the TUI.\n */\n\nimport type { AgentToolResult, AgentToolUpdateCallback } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { Component } from \"@mariozechner/pi-tui\";\nimport type { Static, TSchema } from \"@sinclair/typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ExecOptions, ExecResult } from \"../exec.js\";\nimport type { HookUIContext } from \"../hooks/types.js\";\nimport type { ModelRegistry } from \"../model-registry.js\";\nimport type { ReadonlySessionManager } from \"../session-manager.js\";\n\n/** Alias for clarity */\nexport type CustomToolUIContext = HookUIContext;\n\n/** Re-export for custom tools to use in execute signature */\nexport type { AgentToolResult, AgentToolUpdateCallback };\n\n// Re-export for backward compatibility\nexport type { ExecOptions, ExecResult } from \"../exec.js\";\n\n/** API passed to custom tool factory (stable across session changes) */\nexport interface CustomToolAPI {\n\t/** Current working directory */\n\tcwd: string;\n\t/** Execute a command */\n\texec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;\n\t/** UI methods for user interaction (select, confirm, input, notify, custom) */\n\tui: CustomToolUIContext;\n\t/** Whether UI is available (false in print/RPC mode) */\n\thasUI: boolean;\n}\n\n/**\n * Context passed to tool execute and onSession callbacks.\n * Provides access to session state and model information.\n */\nexport interface CustomToolContext {\n\t/** Session manager (read-only) */\n\tsessionManager: ReadonlySessionManager;\n\t/** Model registry - use for API key resolution and model retrieval */\n\tmodelRegistry: ModelRegistry;\n\t/** Current model (may be undefined if no model is selected yet) */\n\tmodel: Model<any> | undefined;\n\t/** Whether the agent is idle (not streaming) */\n\tisIdle(): boolean;\n\t/** Whether there are queued messages waiting to be processed */\n\thasQueuedMessages(): boolean;\n\t/** Abort the current agent operation (fire-and-forget, does not wait) */\n\tabort(): void;\n}\n\n/** Session event passed to onSession callback */\nexport interface CustomToolSessionEvent {\n\t/** Reason for the session event */\n\treason: \"start\" | \"switch\" | \"branch\" | \"tree\" | \"shutdown\";\n\t/** Previous session file path, or undefined for \"start\" and \"shutdown\" */\n\tpreviousSessionFile: string | undefined;\n}\n\n/** Rendering options passed to renderResult */\nexport interface RenderResultOptions {\n\t/** Whether the result view is expanded */\n\texpanded: boolean;\n\t/** Whether this is a partial/streaming result */\n\tisPartial: boolean;\n}\n\nexport type CustomToolResult<TDetails = any> = AgentToolResult<TDetails>;\n\n/**\n * Custom tool definition.\n *\n * Custom tools are standalone - they don't extend AgentTool directly.\n * When loaded, they are wrapped in an AgentTool for the agent to use.\n *\n * The execute callback receives a ToolContext with access to session state,\n * model registry, and current model.\n *\n * @example\n * ```typescript\n * const factory: CustomToolFactory = (pi) => ({\n * name: \"my_tool\",\n * label: \"My Tool\",\n * description: \"Does something useful\",\n * parameters: Type.Object({ input: Type.String() }),\n *\n * async execute(toolCallId, params, onUpdate, ctx, signal) {\n * // Access session state via ctx.sessionManager\n * // Access model registry via ctx.modelRegistry\n * // Current model via ctx.model\n * return { content: [{ type: \"text\", text: \"Done\" }] };\n * },\n *\n * onSession(event, ctx) {\n * if (event.reason === \"shutdown\") {\n * // Cleanup\n * }\n * // Reconstruct state from ctx.sessionManager.getEntries()\n * }\n * });\n * ```\n */\nexport interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {\n\t/** Tool name (used in LLM tool calls) */\n\tname: string;\n\t/** Human-readable label for UI */\n\tlabel: string;\n\t/** Description for LLM */\n\tdescription: string;\n\t/** Parameter schema (TypeBox) */\n\tparameters: TParams;\n\n\t/**\n\t * Execute the tool.\n\t * @param toolCallId - Unique ID for this tool call\n\t * @param params - Parsed parameters matching the schema\n\t * @param onUpdate - Callback for streaming partial results (for UI, not LLM)\n\t * @param ctx - Context with session manager, model registry, and current model\n\t * @param signal - Optional abort signal for cancellation\n\t */\n\texecute(\n\t\ttoolCallId: string,\n\t\tparams: Static<TParams>,\n\t\tonUpdate: AgentToolUpdateCallback<TDetails> | undefined,\n\t\tctx: CustomToolContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentToolResult<TDetails>>;\n\n\t/** Called on session lifecycle events - use to reconstruct state or cleanup resources */\n\tonSession?: (event: CustomToolSessionEvent, ctx: CustomToolContext) => void | Promise<void>;\n\t/** Custom rendering for tool call display - return a Component */\n\trenderCall?: (args: Static<TParams>, theme: Theme) => Component;\n\n\t/** Custom rendering for tool result display - return a Component */\n\trenderResult?: (result: CustomToolResult<TDetails>, options: RenderResultOptions, theme: Theme) => Component;\n}\n\n/** Factory function that creates a custom tool or array of tools */\nexport type CustomToolFactory = (\n\tpi: CustomToolAPI,\n) => CustomTool<any, any> | CustomTool<any, any>[] | Promise<CustomTool<any, any> | CustomTool<any, any>[]>;\n\n/** Loaded custom tool with metadata and wrapped AgentTool */\nexport interface LoadedCustomTool {\n\t/** Original path (as specified) */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** The original custom tool instance */\n\ttool: CustomTool;\n}\n\n/** Result from loading custom tools */\nexport interface CustomToolsLoadResult {\n\ttools: LoadedCustomTool[];\n\terrors: Array<{ path: string; error: string }>;\n\t/** Update the UI context for all loaded tools. Call when mode initializes. */\n\tsetUIContext(uiContext: CustomToolUIContext, hasUI: boolean): void;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps CustomTool instances into AgentTool for use with the agent.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
5
|
+
import type { CustomTool, CustomToolContext, LoadedCustomTool } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Wrap a CustomTool into an AgentTool.
|
|
8
|
+
* The wrapper injects the ToolContext into execute calls.
|
|
9
|
+
*/
|
|
10
|
+
export declare function wrapCustomTool(tool: CustomTool, getContext: () => CustomToolContext): AgentTool;
|
|
11
|
+
/**
|
|
12
|
+
* Wrap all loaded custom tools into AgentTools.
|
|
13
|
+
*/
|
|
14
|
+
export declare function wrapCustomTools(loadedTools: LoadedCustomTool[], getContext: () => CustomToolContext): AgentTool[];
|
|
15
|
+
//# sourceMappingURL=wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../../src/core/custom-tools/wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAS/F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,gBAAgB,EAAE,EAAE,UAAU,EAAE,MAAM,iBAAiB,GAAG,SAAS,EAAE,CAEjH","sourcesContent":["/**\n * Wraps CustomTool instances into AgentTool for use with the agent.\n */\n\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { CustomTool, CustomToolContext, LoadedCustomTool } from \"./types.js\";\n\n/**\n * Wrap a CustomTool into an AgentTool.\n * The wrapper injects the ToolContext into execute calls.\n */\nexport function wrapCustomTool(tool: CustomTool, getContext: () => CustomToolContext): AgentTool {\n\treturn {\n\t\tname: tool.name,\n\t\tlabel: tool.label,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters,\n\t\texecute: (toolCallId, params, signal, onUpdate) =>\n\t\t\ttool.execute(toolCallId, params, onUpdate, getContext(), signal),\n\t};\n}\n\n/**\n * Wrap all loaded custom tools into AgentTools.\n */\nexport function wrapCustomTools(loadedTools: LoadedCustomTool[], getContext: () => CustomToolContext): AgentTool[] {\n\treturn loadedTools.map((lt) => wrapCustomTool(lt.tool, getContext));\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps CustomTool instances into AgentTool for use with the agent.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Wrap a CustomTool into an AgentTool.
|
|
6
|
+
* The wrapper injects the ToolContext into execute calls.
|
|
7
|
+
*/
|
|
8
|
+
export function wrapCustomTool(tool, getContext) {
|
|
9
|
+
return {
|
|
10
|
+
name: tool.name,
|
|
11
|
+
label: tool.label,
|
|
12
|
+
description: tool.description,
|
|
13
|
+
parameters: tool.parameters,
|
|
14
|
+
execute: (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, onUpdate, getContext(), signal),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Wrap all loaded custom tools into AgentTools.
|
|
19
|
+
*/
|
|
20
|
+
export function wrapCustomTools(loadedTools, getContext) {
|
|
21
|
+
return loadedTools.map((lt) => wrapCustomTool(lt.tool, getContext));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../../src/core/custom-tools/wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,UAAmC,EAAa;IAChG,OAAO;QACN,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CACjD,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC;KACjE,CAAC;AAAA,CACF;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,WAA+B,EAAE,UAAmC,EAAe;IAClH,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AAAA,CACpE","sourcesContent":["/**\n * Wraps CustomTool instances into AgentTool for use with the agent.\n */\n\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { CustomTool, CustomToolContext, LoadedCustomTool } from \"./types.js\";\n\n/**\n * Wrap a CustomTool into an AgentTool.\n * The wrapper injects the ToolContext into execute calls.\n */\nexport function wrapCustomTool(tool: CustomTool, getContext: () => CustomToolContext): AgentTool {\n\treturn {\n\t\tname: tool.name,\n\t\tlabel: tool.label,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters,\n\t\texecute: (toolCallId, params, signal, onUpdate) =>\n\t\t\ttool.execute(toolCallId, params, onUpdate, getContext(), signal),\n\t};\n}\n\n/**\n * Wrap all loaded custom tools into AgentTools.\n */\nexport function wrapCustomTools(loadedTools: LoadedCustomTool[], getContext: () => CustomToolContext): AgentTool[] {\n\treturn loadedTools.map((lt) => wrapCustomTool(lt.tool, getContext));\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared command execution utilities for hooks and custom tools.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Options for executing shell commands.
|
|
6
|
+
*/
|
|
7
|
+
export interface ExecOptions {
|
|
8
|
+
/** AbortSignal to cancel the command */
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
/** Timeout in milliseconds */
|
|
11
|
+
timeout?: number;
|
|
12
|
+
/** Working directory */
|
|
13
|
+
cwd?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Result of executing a shell command.
|
|
17
|
+
*/
|
|
18
|
+
export interface ExecResult {
|
|
19
|
+
stdout: string;
|
|
20
|
+
stderr: string;
|
|
21
|
+
code: number;
|
|
22
|
+
killed: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Execute a shell command and return stdout/stderr/code.
|
|
26
|
+
* Supports timeout and abort signal.
|
|
27
|
+
*/
|
|
28
|
+
export declare function execCommand(command: string, args: string[], cwd: string, options?: ExecOptions): Promise<ExecResult>;
|
|
29
|
+
//# sourceMappingURL=exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,wCAAwC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAkErB","sourcesContent":["/**\n * Shared command execution utilities for hooks and custom tools.\n */\n\nimport { spawn } from \"node:child_process\";\n\n/**\n * Options for executing shell commands.\n */\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the command */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n\t/** Working directory */\n\tcwd?: string;\n}\n\n/**\n * Result of executing a shell command.\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\tkilled: boolean;\n}\n\n/**\n * Execute a shell command and return stdout/stderr/code.\n * Supports timeout and abort signal.\n */\nexport async function execCommand(\n\tcommand: string,\n\targs: string[],\n\tcwd: string,\n\toptions?: ExecOptions,\n): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tshell: false,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared command execution utilities for hooks and custom tools.
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from "node:child_process";
|
|
5
|
+
/**
|
|
6
|
+
* Execute a shell command and return stdout/stderr/code.
|
|
7
|
+
* Supports timeout and abort signal.
|
|
8
|
+
*/
|
|
9
|
+
export async function execCommand(command, args, cwd, options) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const proc = spawn(command, args, {
|
|
12
|
+
cwd,
|
|
13
|
+
shell: false,
|
|
14
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
15
|
+
});
|
|
16
|
+
let stdout = "";
|
|
17
|
+
let stderr = "";
|
|
18
|
+
let killed = false;
|
|
19
|
+
let timeoutId;
|
|
20
|
+
const killProcess = () => {
|
|
21
|
+
if (!killed) {
|
|
22
|
+
killed = true;
|
|
23
|
+
proc.kill("SIGTERM");
|
|
24
|
+
// Force kill after 5 seconds if SIGTERM doesn't work
|
|
25
|
+
setTimeout(() => {
|
|
26
|
+
if (!proc.killed) {
|
|
27
|
+
proc.kill("SIGKILL");
|
|
28
|
+
}
|
|
29
|
+
}, 5000);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
// Handle abort signal
|
|
33
|
+
if (options?.signal) {
|
|
34
|
+
if (options.signal.aborted) {
|
|
35
|
+
killProcess();
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
options.signal.addEventListener("abort", killProcess, { once: true });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Handle timeout
|
|
42
|
+
if (options?.timeout && options.timeout > 0) {
|
|
43
|
+
timeoutId = setTimeout(() => {
|
|
44
|
+
killProcess();
|
|
45
|
+
}, options.timeout);
|
|
46
|
+
}
|
|
47
|
+
proc.stdout?.on("data", (data) => {
|
|
48
|
+
stdout += data.toString();
|
|
49
|
+
});
|
|
50
|
+
proc.stderr?.on("data", (data) => {
|
|
51
|
+
stderr += data.toString();
|
|
52
|
+
});
|
|
53
|
+
proc.on("close", (code) => {
|
|
54
|
+
if (timeoutId)
|
|
55
|
+
clearTimeout(timeoutId);
|
|
56
|
+
if (options?.signal) {
|
|
57
|
+
options.signal.removeEventListener("abort", killProcess);
|
|
58
|
+
}
|
|
59
|
+
resolve({ stdout, stderr, code: code ?? 0, killed });
|
|
60
|
+
});
|
|
61
|
+
proc.on("error", (_err) => {
|
|
62
|
+
if (timeoutId)
|
|
63
|
+
clearTimeout(timeoutId);
|
|
64
|
+
if (options?.signal) {
|
|
65
|
+
options.signal.removeEventListener("abort", killProcess);
|
|
66
|
+
}
|
|
67
|
+
resolve({ stdout, stderr, code: 1, killed });
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared command execution utilities for hooks and custom tools.\n */\n\nimport { spawn } from \"node:child_process\";\n\n/**\n * Options for executing shell commands.\n */\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the command */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n\t/** Working directory */\n\tcwd?: string;\n}\n\n/**\n * Result of executing a shell command.\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\tkilled: boolean;\n}\n\n/**\n * Execute a shell command and return stdout/stderr/code.\n * Supports timeout and abort signal.\n */\nexport async function execCommand(\n\tcommand: string,\n\targs: string[],\n\tcwd: string,\n\toptions?: ExecOptions,\n): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tshell: false,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentState } from "@mariozechner/pi-agent-core";
|
|
2
|
+
import { SessionManager } from "../session-manager.js";
|
|
3
|
+
export interface ExportOptions {
|
|
4
|
+
outputPath?: string;
|
|
5
|
+
themeName?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Export session to HTML using SessionManager and AgentState.
|
|
9
|
+
* Used by TUI's /export command.
|
|
10
|
+
*/
|
|
11
|
+
export declare function exportSessionToHtml(sm: SessionManager, state?: AgentState, options?: ExportOptions | string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Export session file to HTML (standalone, without AgentState).
|
|
14
|
+
* Used by CLI for exporting arbitrary session files.
|
|
15
|
+
*/
|
|
16
|
+
export declare function exportFromFile(inputPath: string, options?: ExportOptions | string): string;
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/export-html/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAK9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAsID;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,MAAM,CA6BpH;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,MAAM,CA2B1F","sourcesContent":["import type { AgentState } from \"@mariozechner/pi-agent-core\";\nimport { existsSync, readFileSync, writeFileSync } from \"fs\";\nimport { basename, join } from \"path\";\nimport { APP_NAME, getExportTemplateDir } from \"../../config.js\";\nimport { getResolvedThemeColors, getThemeExportColors } from \"../../modes/interactive/theme/theme.js\";\nimport { SessionManager } from \"../session-manager.js\";\n\nexport interface ExportOptions {\n\toutputPath?: string;\n\tthemeName?: string;\n}\n\n/** Parse a color string to RGB values. Supports hex (#RRGGBB) and rgb(r,g,b) formats. */\nfunction parseColor(color: string): { r: number; g: number; b: number } | undefined {\n\tconst hexMatch = color.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);\n\tif (hexMatch) {\n\t\treturn {\n\t\t\tr: Number.parseInt(hexMatch[1], 16),\n\t\t\tg: Number.parseInt(hexMatch[2], 16),\n\t\t\tb: Number.parseInt(hexMatch[3], 16),\n\t\t};\n\t}\n\tconst rgbMatch = color.match(/^rgb\\s*\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/);\n\tif (rgbMatch) {\n\t\treturn {\n\t\t\tr: Number.parseInt(rgbMatch[1], 10),\n\t\t\tg: Number.parseInt(rgbMatch[2], 10),\n\t\t\tb: Number.parseInt(rgbMatch[3], 10),\n\t\t};\n\t}\n\treturn undefined;\n}\n\n/** Calculate relative luminance of a color (0-1, higher = lighter). */\nfunction getLuminance(r: number, g: number, b: number): number {\n\tconst toLinear = (c: number) => {\n\t\tconst s = c / 255;\n\t\treturn s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n\t};\n\treturn 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n}\n\n/** Adjust color brightness. Factor > 1 lightens, < 1 darkens. */\nfunction adjustBrightness(color: string, factor: number): string {\n\tconst parsed = parseColor(color);\n\tif (!parsed) return color;\n\tconst adjust = (c: number) => Math.min(255, Math.max(0, Math.round(c * factor)));\n\treturn `rgb(${adjust(parsed.r)}, ${adjust(parsed.g)}, ${adjust(parsed.b)})`;\n}\n\n/** Derive export background colors from a base color (e.g., userMessageBg). */\nfunction deriveExportColors(baseColor: string): { pageBg: string; cardBg: string; infoBg: string } {\n\tconst parsed = parseColor(baseColor);\n\tif (!parsed) {\n\t\treturn {\n\t\t\tpageBg: \"rgb(24, 24, 30)\",\n\t\t\tcardBg: \"rgb(30, 30, 36)\",\n\t\t\tinfoBg: \"rgb(60, 55, 40)\",\n\t\t};\n\t}\n\n\tconst luminance = getLuminance(parsed.r, parsed.g, parsed.b);\n\tconst isLight = luminance > 0.5;\n\n\tif (isLight) {\n\t\treturn {\n\t\t\tpageBg: adjustBrightness(baseColor, 0.96),\n\t\t\tcardBg: baseColor,\n\t\t\tinfoBg: `rgb(${Math.min(255, parsed.r + 10)}, ${Math.min(255, parsed.g + 5)}, ${Math.max(0, parsed.b - 20)})`,\n\t\t};\n\t}\n\treturn {\n\t\tpageBg: adjustBrightness(baseColor, 0.7),\n\t\tcardBg: adjustBrightness(baseColor, 0.85),\n\t\tinfoBg: `rgb(${Math.min(255, parsed.r + 20)}, ${Math.min(255, parsed.g + 15)}, ${parsed.b})`,\n\t};\n}\n\n/**\n * Generate CSS custom property declarations from theme colors.\n */\nfunction generateThemeVars(themeName?: string): string {\n\tconst colors = getResolvedThemeColors(themeName);\n\tconst lines: string[] = [];\n\tfor (const [key, value] of Object.entries(colors)) {\n\t\tlines.push(`--${key}: ${value};`);\n\t}\n\n\t// Use explicit theme export colors if available, otherwise derive from userMessageBg\n\tconst themeExport = getThemeExportColors(themeName);\n\tconst userMessageBg = colors.userMessageBg || \"#343541\";\n\tconst derivedColors = deriveExportColors(userMessageBg);\n\n\tlines.push(`--exportPageBg: ${themeExport.pageBg ?? derivedColors.pageBg};`);\n\tlines.push(`--exportCardBg: ${themeExport.cardBg ?? derivedColors.cardBg};`);\n\tlines.push(`--exportInfoBg: ${themeExport.infoBg ?? derivedColors.infoBg};`);\n\n\treturn lines.join(\"\\n \");\n}\n\ninterface SessionData {\n\theader: ReturnType<SessionManager[\"getHeader\"]>;\n\tentries: ReturnType<SessionManager[\"getEntries\"]>;\n\tleafId: string | null;\n\tsystemPrompt?: string;\n\ttools?: { name: string; description: string }[];\n}\n\n/**\n * Core HTML generation logic shared by both export functions.\n */\nfunction generateHtml(sessionData: SessionData, themeName?: string): string {\n\tconst templateDir = getExportTemplateDir();\n\tconst template = readFileSync(join(templateDir, \"template.html\"), \"utf-8\");\n\tconst templateCss = readFileSync(join(templateDir, \"template.css\"), \"utf-8\");\n\tconst templateJs = readFileSync(join(templateDir, \"template.js\"), \"utf-8\");\n\tconst markedJs = readFileSync(join(templateDir, \"vendor\", \"marked.min.js\"), \"utf-8\");\n\tconst hljsJs = readFileSync(join(templateDir, \"vendor\", \"highlight.min.js\"), \"utf-8\");\n\n\tconst themeVars = generateThemeVars(themeName);\n\tconst colors = getResolvedThemeColors(themeName);\n\tconst exportColors = deriveExportColors(colors.userMessageBg || \"#343541\");\n\tconst bodyBg = exportColors.pageBg;\n\tconst containerBg = exportColors.cardBg;\n\tconst infoBg = exportColors.infoBg;\n\n\t// Base64 encode session data to avoid escaping issues\n\tconst sessionDataBase64 = Buffer.from(JSON.stringify(sessionData)).toString(\"base64\");\n\n\t// Build the CSS with theme variables injected\n\tconst css = templateCss\n\t\t.replace(\"{{THEME_VARS}}\", themeVars)\n\t\t.replace(\"{{BODY_BG}}\", bodyBg)\n\t\t.replace(\"{{CONTAINER_BG}}\", containerBg)\n\t\t.replace(\"{{INFO_BG}}\", infoBg);\n\n\treturn template\n\t\t.replace(\"{{CSS}}\", css)\n\t\t.replace(\"{{JS}}\", templateJs)\n\t\t.replace(\"{{SESSION_DATA}}\", sessionDataBase64)\n\t\t.replace(\"{{MARKED_JS}}\", markedJs)\n\t\t.replace(\"{{HIGHLIGHT_JS}}\", hljsJs);\n}\n\n/**\n * Export session to HTML using SessionManager and AgentState.\n * Used by TUI's /export command.\n */\nexport function exportSessionToHtml(sm: SessionManager, state?: AgentState, options?: ExportOptions | string): string {\n\tconst opts: ExportOptions = typeof options === \"string\" ? { outputPath: options } : options || {};\n\n\tconst sessionFile = sm.getSessionFile();\n\tif (!sessionFile) {\n\t\tthrow new Error(\"Cannot export in-memory session to HTML\");\n\t}\n\tif (!existsSync(sessionFile)) {\n\t\tthrow new Error(\"Nothing to export yet - start a conversation first\");\n\t}\n\n\tconst sessionData: SessionData = {\n\t\theader: sm.getHeader(),\n\t\tentries: sm.getEntries(),\n\t\tleafId: sm.getLeafId(),\n\t\tsystemPrompt: state?.systemPrompt,\n\t\ttools: state?.tools?.map((t) => ({ name: t.name, description: t.description })),\n\t};\n\n\tconst html = generateHtml(sessionData, opts.themeName);\n\n\tlet outputPath = opts.outputPath;\n\tif (!outputPath) {\n\t\tconst sessionBasename = basename(sessionFile, \".jsonl\");\n\t\toutputPath = `${APP_NAME}-session-${sessionBasename}.html`;\n\t}\n\n\twriteFileSync(outputPath, html, \"utf8\");\n\treturn outputPath;\n}\n\n/**\n * Export session file to HTML (standalone, without AgentState).\n * Used by CLI for exporting arbitrary session files.\n */\nexport function exportFromFile(inputPath: string, options?: ExportOptions | string): string {\n\tconst opts: ExportOptions = typeof options === \"string\" ? { outputPath: options } : options || {};\n\n\tif (!existsSync(inputPath)) {\n\t\tthrow new Error(`File not found: ${inputPath}`);\n\t}\n\n\tconst sm = SessionManager.open(inputPath);\n\n\tconst sessionData: SessionData = {\n\t\theader: sm.getHeader(),\n\t\tentries: sm.getEntries(),\n\t\tleafId: sm.getLeafId(),\n\t\tsystemPrompt: undefined,\n\t\ttools: undefined,\n\t};\n\n\tconst html = generateHtml(sessionData, opts.themeName);\n\n\tlet outputPath = opts.outputPath;\n\tif (!outputPath) {\n\t\tconst inputBasename = basename(inputPath, \".jsonl\");\n\t\toutputPath = `${APP_NAME}-session-${inputBasename}.html`;\n\t}\n\n\twriteFileSync(outputPath, html, \"utf8\");\n\treturn outputPath;\n}\n"]}
|