@oh-my-pi/pi-utils 17.2.9 → 17.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/types/acp/connection.d.ts +118 -0
  3. package/dist/types/acp/protocol.d.ts +526 -0
  4. package/dist/types/acp/schema.d.ts +41 -0
  5. package/dist/types/acp/stream.d.ts +8 -0
  6. package/dist/types/acp/transport.d.ts +81 -0
  7. package/dist/types/acp.d.ts +6 -0
  8. package/dist/types/browsers.d.ts +68 -0
  9. package/dist/types/chalk.d.ts +125 -0
  10. package/dist/types/dates.d.ts +7 -0
  11. package/dist/types/docx/converter.d.ts +46 -0
  12. package/dist/types/docx/xml.d.ts +26 -0
  13. package/dist/types/docx/zip.d.ts +6 -0
  14. package/dist/types/docx.d.ts +11 -0
  15. package/dist/types/dom/core.d.ts +431 -0
  16. package/dist/types/dom/parser.d.ts +7 -0
  17. package/dist/types/dom/selector.d.ts +5 -0
  18. package/dist/types/dom.d.ts +5 -0
  19. package/dist/types/headers.d.ts +34 -0
  20. package/dist/types/logger/rotating-file.d.ts +18 -0
  21. package/dist/types/lru.d.ts +46 -0
  22. package/dist/types/marked/core.d.ts +445 -0
  23. package/dist/types/marked.d.ts +2 -0
  24. package/dist/types/postmortem.d.ts +14 -0
  25. package/dist/types/procmgr.d.ts +16 -0
  26. package/dist/types/prompt.d.ts +2 -2
  27. package/dist/types/readability/readability.d.ts +9 -0
  28. package/dist/types/readability/readerable.d.ts +10 -0
  29. package/dist/types/readability/types.d.ts +70 -0
  30. package/dist/types/readability.d.ts +4 -0
  31. package/dist/types/template.d.ts +62 -0
  32. package/dist/types/turndown/gfm.d.ts +11 -0
  33. package/dist/types/turndown/html.d.ts +5 -0
  34. package/dist/types/turndown/service.d.ts +21 -0
  35. package/dist/types/turndown/types.d.ts +70 -0
  36. package/dist/types/turndown.d.ts +4 -0
  37. package/dist/types/vterm/buffer.d.ts +99 -0
  38. package/dist/types/vterm/terminal.d.ts +44 -0
  39. package/dist/types/vterm.d.ts +8 -0
  40. package/dist/types/xml.d.ts +31 -0
  41. package/package.json +2 -5
  42. package/src/acp/connection.ts +344 -0
  43. package/src/acp/protocol.ts +466 -0
  44. package/src/acp/schema.ts +160 -0
  45. package/src/acp/stream.ts +82 -0
  46. package/src/acp/transport.ts +213 -0
  47. package/src/acp.ts +6 -0
  48. package/src/browsers.ts +501 -0
  49. package/src/chalk.ts +312 -0
  50. package/src/dates.ts +194 -0
  51. package/src/docx/converter.ts +681 -0
  52. package/src/docx/xml.ts +166 -0
  53. package/src/docx/zip.ts +87 -0
  54. package/src/docx.ts +20 -0
  55. package/src/dom/core.ts +1254 -0
  56. package/src/dom/parser.ts +370 -0
  57. package/src/dom/selector.ts +290 -0
  58. package/src/dom.ts +33 -0
  59. package/src/headers.ts +167 -0
  60. package/src/logger/rotating-file.ts +149 -0
  61. package/src/logger.ts +12 -28
  62. package/src/lru.ts +185 -0
  63. package/src/marked/core.ts +1576 -0
  64. package/src/marked.ts +2 -0
  65. package/src/postmortem.ts +44 -1
  66. package/src/procmgr.ts +21 -4
  67. package/src/prompt.ts +5 -22
  68. package/src/readability/readability.ts +533 -0
  69. package/src/readability/readerable.ts +51 -0
  70. package/src/readability/types.ts +72 -0
  71. package/src/readability.ts +11 -0
  72. package/src/template.ts +586 -0
  73. package/src/turndown/gfm.ts +106 -0
  74. package/src/turndown/html.ts +257 -0
  75. package/src/turndown/service.ts +334 -0
  76. package/src/turndown/types.ts +81 -0
  77. package/src/turndown.ts +5 -0
  78. package/src/vterm/buffer.ts +218 -0
  79. package/src/vterm/terminal.ts +773 -0
  80. package/src/vterm.ts +8 -0
  81. package/src/xml.ts +313 -0
  82. package/src/winston-daily-rotate-file.d.ts +0 -6
@@ -0,0 +1,11 @@
1
+ import type { TurndownPlugin } from "./types.js";
2
+ /** Install GitHub fenced code blocks selected by `highlight-source-*` wrappers. */
3
+ export declare const highlightedCodeBlock: TurndownPlugin;
4
+ /** Install GFM strikethrough conversion. */
5
+ export declare const strikethrough: TurndownPlugin;
6
+ /** Install GFM task-list checkbox conversion. */
7
+ export declare const taskListItems: TurndownPlugin;
8
+ /** Install GFM table conversion for tables with a heading row. */
9
+ export declare const tables: TurndownPlugin;
10
+ /** Install every GFM rule used by the coding agent. */
11
+ export declare const gfm: TurndownPlugin;
@@ -0,0 +1,5 @@
1
+ import type { TurndownNode } from "./types.js";
2
+ /** Parse an HTML fragment into the small DOM subset needed by Turndown. */
3
+ export declare function parseHtmlFragment(html: string): TurndownNode;
4
+ /** Serialize a standards-shaped or internal HTML node. */
5
+ export declare function serializeNode(node: TurndownNode): string;
@@ -0,0 +1,21 @@
1
+ import type { ResolvedTurndownOptions, RuleFilter, TurndownNode, TurndownOptions, TurndownPlugin, TurndownRule } from "./types.js";
2
+ /** Convert HTML fragments to Markdown with extensible Turndown-compatible rules. */
3
+ export default class TurndownService {
4
+ #private;
5
+ readonly options: ResolvedTurndownOptions;
6
+ constructor(options?: TurndownOptions);
7
+ /** Install a highest-priority named conversion rule. */
8
+ addRule(key: string, rule: TurndownRule): this;
9
+ /** Preserve matching elements as HTML when no custom rule handles them. */
10
+ keep(filter: RuleFilter): this;
11
+ /** Drop matching elements and all of their converted content. */
12
+ remove(filter: RuleFilter): this;
13
+ /** Install one plugin or an ordered list of plugins. */
14
+ use(plugin: TurndownPlugin | readonly TurndownPlugin[]): this;
15
+ /** Escape Markdown punctuation using Turndown's public escaping rules. */
16
+ escape(text: string): string;
17
+ /** Convert an HTML string or standards-shaped DOM node to Markdown. */
18
+ turndown(input: string | TurndownNode): string;
19
+ /** Convert only a node's children within the active conversion. */
20
+ convertChildren(node: TurndownNode): string;
21
+ }
@@ -0,0 +1,70 @@
1
+ /** Behavior-compatible reimplementation of turndown's used surface. */
2
+ /** A DOM-shaped node accepted by conversion rules. */
3
+ export interface TurndownNode {
4
+ readonly nodeType: number;
5
+ readonly nodeName: string;
6
+ readonly parentNode: TurndownNode | null;
7
+ readonly childNodes: ArrayLike<TurndownNode>;
8
+ readonly children: ArrayLike<TurndownNode>;
9
+ readonly firstChild: TurndownNode | null;
10
+ readonly lastChild: TurndownNode | null;
11
+ readonly nextSibling: TurndownNode | null;
12
+ readonly previousSibling: TurndownNode | null;
13
+ readonly textContent: string | null;
14
+ readonly outerHTML?: string;
15
+ getAttribute(name: string): string | null;
16
+ hasAttribute(name: string): boolean;
17
+ }
18
+ /** Options supported by the HTML-to-Markdown converter. */
19
+ export interface TurndownOptions {
20
+ headingStyle?: "setext" | "atx";
21
+ hr?: string;
22
+ bulletListMarker?: "*" | "-" | "+";
23
+ codeBlockStyle?: "indented" | "fenced";
24
+ fence?: string;
25
+ emDelimiter?: "_" | "*";
26
+ strongDelimiter?: "**" | "__";
27
+ linkStyle?: "inlined" | "referenced";
28
+ linkReferenceStyle?: "full" | "collapsed" | "shortcut";
29
+ preformattedCode?: boolean;
30
+ blankReplacement?: ReplacementFunction;
31
+ keepReplacement?: ReplacementFunction;
32
+ defaultReplacement?: ReplacementFunction;
33
+ }
34
+ /** Fully resolved options passed to replacement callbacks. */
35
+ export interface ResolvedTurndownOptions {
36
+ headingStyle: "setext" | "atx";
37
+ hr: string;
38
+ bulletListMarker: "*" | "-" | "+";
39
+ codeBlockStyle: "indented" | "fenced";
40
+ fence: string;
41
+ emDelimiter: "_" | "*";
42
+ strongDelimiter: "**" | "__";
43
+ linkStyle: "inlined" | "referenced";
44
+ linkReferenceStyle: "full" | "collapsed" | "shortcut";
45
+ preformattedCode: boolean;
46
+ blankReplacement?: ReplacementFunction;
47
+ keepReplacement?: ReplacementFunction;
48
+ defaultReplacement?: ReplacementFunction;
49
+ }
50
+ /** A tag name, list of tag names, or predicate selecting nodes for a rule. */
51
+ export type RuleFilter = string | readonly string[] | ((node: TurndownNode, options: ResolvedTurndownOptions) => boolean);
52
+ /** Produces Markdown for a matched node and its already-converted children. */
53
+ export type ReplacementFunction = (content: string, node: TurndownNode, options: ResolvedTurndownOptions) => string;
54
+ /** A named conversion rule accepted by `addRule`. */
55
+ export interface TurndownRule {
56
+ filter: RuleFilter;
57
+ replacement: ReplacementFunction;
58
+ }
59
+ /** A plugin that installs one or more conversion rules. */
60
+ export type TurndownPlugin = (service: TurndownServiceLike) => void;
61
+ /** Structural service surface available to plugins. */
62
+ export interface TurndownServiceLike {
63
+ readonly options: ResolvedTurndownOptions;
64
+ addRule(key: string, rule: TurndownRule): this;
65
+ convertChildren(node: TurndownNode): string;
66
+ keep(filter: RuleFilter): this;
67
+ remove(filter: RuleFilter): this;
68
+ turndown(input: string | TurndownNode): string;
69
+ escape(text: string): string;
70
+ }
@@ -0,0 +1,4 @@
1
+ /** Behavior-compatible reimplementation of turndown's used surface. */
2
+ export * from "./turndown/gfm.js";
3
+ export { default, default as TurndownService } from "./turndown/service.js";
4
+ export * from "./turndown/types.js";
@@ -0,0 +1,99 @@
1
+ /** Cell rendition tracked by the virtual terminal. */
2
+ export interface CellAttributes {
3
+ bold: boolean;
4
+ dim: boolean;
5
+ italic: boolean;
6
+ underline: boolean;
7
+ inverse: boolean;
8
+ strikethrough: boolean;
9
+ overline: boolean;
10
+ fgMode: 0 | 1 | 2;
11
+ fg: number;
12
+ bgMode: 0 | 1 | 2;
13
+ bg: number;
14
+ }
15
+ /** A mutable terminal grid cell. */
16
+ export interface CellData {
17
+ chars: string;
18
+ width: number;
19
+ attrs: CellAttributes;
20
+ }
21
+ /** Creates the default rendition. */
22
+ export declare function defaultAttributes(): CellAttributes;
23
+ /** Creates an empty cell with the supplied rendition. */
24
+ export declare function blankCell(attrs?: CellAttributes): CellData;
25
+ /** Proposed xterm-compatible cell readback object. */
26
+ export declare class BufferCell {
27
+ #private;
28
+ /** Reuses this object for another grid cell. */
29
+ setFrom(cell: CellData): this;
30
+ /** Returns the grapheme stored in this cell. */
31
+ getChars(): string;
32
+ /** Returns the cell width, with zero denoting a wide-cell continuation. */
33
+ getWidth(): number;
34
+ /** Returns the packed foreground palette index or RGB value. */
35
+ getFgColor(): number;
36
+ /** Returns the packed background palette index or RGB value. */
37
+ getBgColor(): number;
38
+ /** Reports bold rendition. */
39
+ isBold(): number;
40
+ /** Reports dim rendition. */
41
+ isDim(): number;
42
+ /** Reports italic rendition. */
43
+ isItalic(): number;
44
+ /** Reports underline rendition. */
45
+ isUnderline(): number;
46
+ /** Reports inverse rendition. */
47
+ isInverse(): number;
48
+ /** Reports strikethrough rendition. */
49
+ isStrikethrough(): number;
50
+ /** Reports overline rendition. */
51
+ isOverline(): number;
52
+ /** Reports a true-color foreground. */
53
+ isFgRGB(): boolean;
54
+ /** Reports a true-color background. */
55
+ isBgRGB(): boolean;
56
+ /** Reports a palette foreground. */
57
+ isFgPalette(): boolean;
58
+ /** Reports a palette background. */
59
+ isBgPalette(): boolean;
60
+ }
61
+ /** One physical row in a terminal buffer. */
62
+ export declare class BufferLine {
63
+ cells: CellData[];
64
+ isWrapped: boolean;
65
+ constructor(columns: number, attrs?: CellAttributes);
66
+ /** Number of grid columns in the line. */
67
+ get length(): number;
68
+ /** Reads a cell, optionally reusing the caller's object. */
69
+ getCell(column: number, cell?: BufferCell): BufferCell | undefined;
70
+ /** Converts a column range to text. */
71
+ translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string;
72
+ }
73
+ /** Storage backing one terminal screen and its history. */
74
+ export interface BufferState {
75
+ lines: BufferLine[];
76
+ baseY: number;
77
+ viewportY: number;
78
+ cursorX: number;
79
+ cursorY: number;
80
+ }
81
+ /** Public xterm-compatible view over a buffer state. */
82
+ export declare class BufferView {
83
+ private readonly state;
84
+ constructor(state: () => BufferState);
85
+ /** Number of physical lines, including scrollback. */
86
+ get length(): number;
87
+ /** First row of the live screen in the full buffer. */
88
+ get baseY(): number;
89
+ /** First row currently exposed by the viewport. */
90
+ get viewportY(): number;
91
+ /** Cursor column in the live screen. */
92
+ get cursorX(): number;
93
+ /** Cursor row in the live screen. */
94
+ get cursorY(): number;
95
+ /** Reads a physical buffer line. */
96
+ getLine(row: number): BufferLine | undefined;
97
+ /** Creates a reusable empty cell readback object. */
98
+ getNullCell(): BufferCell;
99
+ }
@@ -0,0 +1,44 @@
1
+ import { BufferView } from "./buffer.js";
2
+ /** Construction options supported by the headless virtual terminal. */
3
+ export interface TerminalOptions {
4
+ cols?: number;
5
+ rows?: number;
6
+ scrollback?: number;
7
+ allowProposedApi?: boolean;
8
+ disableStdin?: boolean;
9
+ }
10
+ /** Disposable event subscription. */
11
+ export interface Disposable {
12
+ dispose(): void;
13
+ }
14
+ /** Observable terminal modes used by interactive input normalization. */
15
+ export interface TerminalModes {
16
+ applicationCursorKeysMode: boolean;
17
+ }
18
+ /** Buffer collection exposed by the virtual terminal. */
19
+ export interface TerminalBuffers {
20
+ readonly active: BufferView;
21
+ readonly normal: BufferView;
22
+ readonly alternate: BufferView;
23
+ }
24
+ /** Behavior-compatible reimplementation of @xterm/headless's used surface. */
25
+ export declare class Terminal {
26
+ #private;
27
+ /** Current terminal column count. */
28
+ cols: number;
29
+ /** Current terminal row count. */
30
+ rows: number;
31
+ /** Normal, alternate, and active buffer views. */
32
+ readonly buffer: TerminalBuffers;
33
+ /** Currently active input modes. */
34
+ readonly modes: TerminalModes;
35
+ constructor(options?: TerminalOptions);
36
+ /** Parses terminal output and invokes the callback after the write is committed. */
37
+ write(data: string | Uint8Array, callback?: () => void): void;
38
+ /** Changes the terminal grid and reflows wrapped normal-buffer lines. */
39
+ resize(columns: number, rows: number): void;
40
+ /** Subscribes to terminal-generated input replies. */
41
+ onData(listener: (data: string) => void): Disposable;
42
+ /** Releases parser state and event listeners. */
43
+ dispose(): void;
44
+ }
@@ -0,0 +1,8 @@
1
+ /** Behavior-compatible reimplementation of @xterm/headless's used surface. */
2
+ export * from "./vterm/buffer.js";
3
+ export * from "./vterm/terminal.js";
4
+ import { Terminal } from "./vterm/terminal.js";
5
+ declare const vterm: {
6
+ Terminal: typeof Terminal;
7
+ };
8
+ export default vterm;
@@ -0,0 +1,31 @@
1
+ /** Behavior-compatible reimplementation of fast-xml-parser's used surface. */
2
+ /** Context supplied to an array-selection callback. */
3
+ export type XMLArraySelector = (tagName: string, jPath: string, isLeafNode: boolean, isAttribute: boolean | null) => boolean;
4
+ /** Options supported by {@link XMLParser}. */
5
+ export interface XMLParserOptions {
6
+ /** Omits attributes when true (default). */
7
+ ignoreAttributes?: boolean;
8
+ /** Prefix applied to attribute property names. */
9
+ attributeNamePrefix?: string;
10
+ /** Property used for text alongside children or attributes. */
11
+ textNodeName?: string;
12
+ /** Trims ordinary text and attribute values. */
13
+ trimValues?: boolean;
14
+ /** Coerces numeric and boolean element text. */
15
+ parseTagValue?: boolean;
16
+ /** Coerces numeric and boolean attribute values. */
17
+ parseAttributeValue?: boolean;
18
+ /** Controls entity processing and its expansion ceiling. */
19
+ processEntities?: boolean | {
20
+ maxTotalExpansions?: number;
21
+ };
22
+ /** Selects element or attribute properties that must always be arrays. */
23
+ isArray?: XMLArraySelector;
24
+ }
25
+ /** Parses XML into the object shape used by the document converters. */
26
+ export declare class XMLParser {
27
+ #private;
28
+ constructor(options?: XMLParserOptions);
29
+ /** Parses one XML document. */
30
+ parse(xml: string): unknown;
31
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-utils",
4
- "version": "17.2.9",
4
+ "version": "17.2.10",
5
5
  "description": "Shared utilities for pi packages",
6
6
  "homepage": "https://omp.sh",
7
7
  "author": "Can Boluk",
@@ -31,10 +31,7 @@
31
31
  "fmt": "biome format --write ."
32
32
  },
33
33
  "dependencies": {
34
- "@oh-my-pi/pi-natives": "17.2.9",
35
- "handlebars": "^4.7.9",
36
- "winston": "^3.19.0",
37
- "winston-daily-rotate-file": "5.0.0"
34
+ "@oh-my-pi/pi-natives": "17.2.10"
38
35
  },
39
36
  "devDependencies": {
40
37
  "@types/bun": "^1.3.14"
@@ -0,0 +1,344 @@
1
+ import type {
2
+ Agent,
3
+ AuthenticateRequest,
4
+ AuthenticateResponse,
5
+ CloseSessionRequest,
6
+ CloseSessionResponse,
7
+ CompleteElicitationNotification,
8
+ CreateElicitationRequest,
9
+ CreateElicitationResponse,
10
+ CreateTerminalRequest,
11
+ ForkSessionRequest,
12
+ ForkSessionResponse,
13
+ InitializeRequest,
14
+ InitializeResponse,
15
+ ListSessionsRequest,
16
+ ListSessionsResponse,
17
+ LoadSessionRequest,
18
+ LoadSessionResponse,
19
+ MaybePromise,
20
+ NewSessionRequest,
21
+ NewSessionResponse,
22
+ PromptRequest,
23
+ PromptResponse,
24
+ ReadTextFileRequest,
25
+ ReadTextFileResponse,
26
+ RequestPermissionRequest,
27
+ RequestPermissionResponse,
28
+ ResumeSessionRequest,
29
+ ResumeSessionResponse,
30
+ SessionNotification,
31
+ SetSessionConfigOptionRequest,
32
+ SetSessionConfigOptionResponse,
33
+ SetSessionModeRequest,
34
+ SetSessionModeResponse,
35
+ TerminalActionResponse,
36
+ TerminalOutputResponse,
37
+ WaitForTerminalExitResponse,
38
+ WriteTextFileRequest,
39
+ WriteTextFileResponse,
40
+ } from "./protocol";
41
+ import type { Stream } from "./stream";
42
+ import { RequestError, RpcConnection } from "./transport";
43
+
44
+ /** Terminal creation response returned by a client. */
45
+ export interface CreateTerminalResponse {
46
+ terminalId: string;
47
+ }
48
+ /** Client callbacks handled by a client-side connection. */
49
+ export interface Client {
50
+ requestPermission(params: RequestPermissionRequest): MaybePromise<RequestPermissionResponse>;
51
+ sessionUpdate(params: SessionNotification): MaybePromise<void>;
52
+ readTextFile?(params: ReadTextFileRequest): MaybePromise<ReadTextFileResponse>;
53
+ writeTextFile?(params: WriteTextFileRequest): MaybePromise<WriteTextFileResponse | void>;
54
+ createTerminal?(params: CreateTerminalRequest): MaybePromise<CreateTerminalResponse>;
55
+ terminalOutput?(params: { sessionId: string; terminalId: string }): MaybePromise<TerminalOutputResponse>;
56
+ waitForTerminalExit?(params: { sessionId: string; terminalId: string }): MaybePromise<WaitForTerminalExitResponse>;
57
+ killTerminal?(params: { sessionId: string; terminalId: string }): MaybePromise<TerminalActionResponse | void>;
58
+ releaseTerminal?(params: { sessionId: string; terminalId: string }): MaybePromise<TerminalActionResponse | void>;
59
+ unstable_createElicitation?(params: CreateElicitationRequest): MaybePromise<CreateElicitationResponse>;
60
+ unstable_completeElicitation?(params: CompleteElicitationNotification): MaybePromise<void>;
61
+ extMethod?(method: string, params: Record<string, unknown>): MaybePromise<Record<string, unknown>>;
62
+ extNotification?(method: string, params: Record<string, unknown>): MaybePromise<void>;
63
+ }
64
+
65
+ /** Agent-side ACP connection. */
66
+ export class AgentSideConnection {
67
+ #connection: RpcConnection;
68
+
69
+ constructor(toAgent: (connection: AgentSideConnection) => Agent, stream: Stream) {
70
+ let agent: Agent | undefined;
71
+ this.#connection = new RpcConnection(stream, async (method, params, notification) => {
72
+ const target = agent;
73
+ if (!target) throw RequestError.internalError(undefined, "Agent is not initialized");
74
+ return dispatchAgent(target, method, params, notification);
75
+ });
76
+ agent = toAgent(this);
77
+ }
78
+
79
+ /** Signal aborted when the transport closes. */
80
+ get signal(): AbortSignal {
81
+ return this.#connection.signal;
82
+ }
83
+ /** Promise resolved when the transport closes. */
84
+ get closed(): Promise<void> {
85
+ return this.#connection.closed;
86
+ }
87
+ /** Sends a session update notification. */
88
+ sessionUpdate(params: SessionNotification): Promise<void> {
89
+ return this.#connection.notify("session/update", params);
90
+ }
91
+ /** Requests permission from the client. */
92
+ requestPermission(params: RequestPermissionRequest): Promise<RequestPermissionResponse> {
93
+ return this.#connection.request("session/request_permission", params);
94
+ }
95
+ /** Reads a client-side text file. */
96
+ readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {
97
+ return this.#connection.request("fs/read_text_file", params);
98
+ }
99
+ /** Writes a client-side text file. */
100
+ writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {
101
+ return this.#connection.request("fs/write_text_file", params);
102
+ }
103
+ /** Creates a client terminal and returns its control handle. */
104
+ async createTerminal(params: CreateTerminalRequest): Promise<TerminalHandle> {
105
+ const response = await this.#connection.request<CreateTerminalResponse>("terminal/create", params);
106
+ return new TerminalHandle(response.terminalId, params.sessionId, this.#connection);
107
+ }
108
+ /** Creates an interactive elicitation on the client. */
109
+ unstable_createElicitation(params: CreateElicitationRequest): Promise<CreateElicitationResponse> {
110
+ return this.#connection.request("elicitation/create", params);
111
+ }
112
+ /** Notifies a client that URL elicitation completed. */
113
+ unstable_completeElicitation(params: CompleteElicitationNotification): Promise<void> {
114
+ return this.#connection.notify("elicitation/complete", params);
115
+ }
116
+ /** Sends a custom request. */
117
+ request<Response = unknown, Params = unknown>(method: string, params?: Params): Promise<Response> {
118
+ return this.#connection.request(method, params);
119
+ }
120
+ /** Sends a custom notification. */
121
+ notify<Params = unknown>(method: string, params?: Params): Promise<void> {
122
+ return this.#connection.notify(method, params);
123
+ }
124
+ /** Sends a legacy extension request. */
125
+ extMethod(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {
126
+ return this.request(method, params);
127
+ }
128
+ /** Sends a legacy extension notification. */
129
+ extNotification(method: string, params: Record<string, unknown>): Promise<void> {
130
+ return this.notify(method, params);
131
+ }
132
+ }
133
+
134
+ /** Handle for controlling a client-owned terminal. */
135
+ export class TerminalHandle {
136
+ /** Client terminal identifier. */
137
+ readonly id: string;
138
+ #sessionId: string;
139
+ #connection: RpcConnection;
140
+
141
+ constructor(id: string, sessionId: string, connection: RpcConnection) {
142
+ this.id = id;
143
+ this.#sessionId = sessionId;
144
+ this.#connection = connection;
145
+ }
146
+ /** Gets current terminal output. */
147
+ currentOutput(): Promise<TerminalOutputResponse> {
148
+ return this.#connection.request("terminal/output", { sessionId: this.#sessionId, terminalId: this.id });
149
+ }
150
+ /** Waits for terminal exit. */
151
+ waitForExit(): Promise<WaitForTerminalExitResponse> {
152
+ return this.#connection.request("terminal/wait_for_exit", { sessionId: this.#sessionId, terminalId: this.id });
153
+ }
154
+ /** Kills the terminal. */
155
+ kill(): Promise<TerminalActionResponse> {
156
+ return this.#connection.request("terminal/kill", { sessionId: this.#sessionId, terminalId: this.id });
157
+ }
158
+ /** Releases the terminal. */
159
+ release(): Promise<TerminalActionResponse | void> {
160
+ return this.#connection.request("terminal/release", { sessionId: this.#sessionId, terminalId: this.id });
161
+ }
162
+ /** Releases the terminal during async disposal. */
163
+ async [Symbol.asyncDispose](): Promise<void> {
164
+ await this.release();
165
+ }
166
+ }
167
+
168
+ /** Client-side ACP connection used to call an agent. */
169
+ export class ClientSideConnection {
170
+ #connection: RpcConnection;
171
+
172
+ constructor(toClient: (connection: ClientSideConnection) => Client, stream: Stream) {
173
+ let client: Client | undefined;
174
+ this.#connection = new RpcConnection(stream, async (method, params, notification) => {
175
+ const target = client;
176
+ if (!target) throw RequestError.internalError(undefined, "Client is not initialized");
177
+ return dispatchClient(target, method, params, notification);
178
+ });
179
+ client = toClient(this);
180
+ }
181
+ /** Signal aborted when the transport closes. */
182
+ get signal(): AbortSignal {
183
+ return this.#connection.signal;
184
+ }
185
+ /** Promise resolved when the transport closes. */
186
+ get closed(): Promise<void> {
187
+ return this.#connection.closed;
188
+ }
189
+ /** Initializes protocol capabilities. */
190
+ initialize(params: InitializeRequest): Promise<InitializeResponse> {
191
+ return this.#connection.request("initialize", params);
192
+ }
193
+ /** Authenticates with an agent. */
194
+ authenticate(params: AuthenticateRequest): Promise<AuthenticateResponse> {
195
+ return this.#connection.request("authenticate", params);
196
+ }
197
+ /** Creates a session. */
198
+ newSession(params: NewSessionRequest): Promise<NewSessionResponse> {
199
+ return this.#connection.request("session/new", params);
200
+ }
201
+ /** Loads a session. */
202
+ loadSession(params: LoadSessionRequest): Promise<LoadSessionResponse> {
203
+ return this.#connection.request("session/load", params);
204
+ }
205
+ /** Lists sessions. */
206
+ listSessions(params: ListSessionsRequest): Promise<ListSessionsResponse> {
207
+ return this.#connection.request("session/list", params);
208
+ }
209
+ /** Resumes a session. */
210
+ resumeSession(params: ResumeSessionRequest): Promise<ResumeSessionResponse> {
211
+ return this.#connection.request("session/resume", params);
212
+ }
213
+ /** Forks a session. */
214
+ unstable_forkSession(params: ForkSessionRequest): Promise<ForkSessionResponse> {
215
+ return this.#connection.request("session/fork", params);
216
+ }
217
+ /** Closes a session. */
218
+ closeSession(params: CloseSessionRequest): Promise<CloseSessionResponse> {
219
+ return this.#connection.request("session/close", params);
220
+ }
221
+ /** Sets a session mode. */
222
+ setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse> {
223
+ return this.#connection.request("session/set_mode", params);
224
+ }
225
+ /** Sets a session config option. */
226
+ setSessionConfigOption(params: SetSessionConfigOptionRequest): Promise<SetSessionConfigOptionResponse> {
227
+ return this.#connection.request("session/set_config_option", params);
228
+ }
229
+ /** Sends a prompt. */
230
+ prompt(params: PromptRequest): Promise<PromptResponse> {
231
+ return this.#connection.request("session/prompt", params);
232
+ }
233
+ /** Cancels an active prompt. */
234
+ cancel(params: { sessionId: string }): Promise<void> {
235
+ return this.#connection.notify("session/cancel", params);
236
+ }
237
+ }
238
+
239
+ async function dispatchAgent(agent: Agent, method: string, params: unknown, notification: boolean): Promise<unknown> {
240
+ switch (method) {
241
+ case "initialize":
242
+ return agent.initialize(params as InitializeRequest);
243
+ case "authenticate":
244
+ return invokeRequired(agent, agent.authenticate, method, params as AuthenticateRequest);
245
+ case "session/new":
246
+ return agent.newSession(params as NewSessionRequest);
247
+ case "session/load":
248
+ return invokeRequired(agent, agent.loadSession, method, params as LoadSessionRequest);
249
+ case "session/list":
250
+ return invokeRequired(agent, agent.listSessions, method, params as ListSessionsRequest);
251
+ case "session/resume":
252
+ return invokeRequired(agent, agent.resumeSession, method, params as ResumeSessionRequest);
253
+ case "session/fork":
254
+ return invokeRequired(agent, agent.unstable_forkSession, method, params as ForkSessionRequest);
255
+ case "session/close":
256
+ return invokeRequired(agent, agent.closeSession, method, params as CloseSessionRequest);
257
+ case "session/set_mode":
258
+ return invokeRequired(agent, agent.setSessionMode, method, params as SetSessionModeRequest);
259
+ case "session/set_config_option":
260
+ return invokeRequired(agent, agent.setSessionConfigOption, method, params as SetSessionConfigOptionRequest);
261
+ case "session/prompt":
262
+ return agent.prompt(params as PromptRequest);
263
+ case "session/cancel":
264
+ return agent.cancel(params as { sessionId: string });
265
+ default:
266
+ if (method === "$/cancel_request") return;
267
+ if (notification && agent.extNotification)
268
+ return agent.extNotification(method, params as Record<string, unknown>);
269
+ if (!notification && agent.extMethod) return agent.extMethod(method, params as Record<string, unknown>);
270
+ throw RequestError.methodNotFound(method);
271
+ }
272
+ }
273
+
274
+ async function dispatchClient(
275
+ client: Client,
276
+ method: string,
277
+ params: unknown,
278
+ notification: boolean,
279
+ ): Promise<unknown> {
280
+ switch (method) {
281
+ case "session/request_permission":
282
+ return client.requestPermission(params as RequestPermissionRequest);
283
+ case "session/update":
284
+ return client.sessionUpdate(params as SessionNotification);
285
+ case "fs/read_text_file":
286
+ return invokeRequired(client, client.readTextFile, method, params as ReadTextFileRequest);
287
+ case "fs/write_text_file":
288
+ return invokeRequired(client, client.writeTextFile, method, params as WriteTextFileRequest);
289
+ case "terminal/create":
290
+ return invokeRequired(client, client.createTerminal, method, params as CreateTerminalRequest);
291
+ case "terminal/output":
292
+ return invokeRequired(
293
+ client,
294
+ client.terminalOutput,
295
+ method,
296
+ params as { sessionId: string; terminalId: string },
297
+ );
298
+ case "terminal/wait_for_exit":
299
+ return invokeRequired(
300
+ client,
301
+ client.waitForTerminalExit,
302
+ method,
303
+ params as { sessionId: string; terminalId: string },
304
+ );
305
+ case "terminal/kill":
306
+ return invokeRequired(
307
+ client,
308
+ client.killTerminal,
309
+ method,
310
+ params as { sessionId: string; terminalId: string },
311
+ );
312
+ case "terminal/release":
313
+ return invokeRequired(
314
+ client,
315
+ client.releaseTerminal,
316
+ method,
317
+ params as { sessionId: string; terminalId: string },
318
+ );
319
+ case "elicitation/create":
320
+ return invokeRequired(client, client.unstable_createElicitation, method, params as CreateElicitationRequest);
321
+ case "elicitation/complete":
322
+ return invokeRequired(
323
+ client,
324
+ client.unstable_completeElicitation,
325
+ method,
326
+ params as CompleteElicitationNotification,
327
+ );
328
+ default:
329
+ if (notification && client.extNotification)
330
+ return client.extNotification(method, params as Record<string, unknown>);
331
+ if (!notification && client.extMethod) return client.extMethod(method, params as Record<string, unknown>);
332
+ throw RequestError.methodNotFound(method);
333
+ }
334
+ }
335
+
336
+ function invokeRequired<Params, Response>(
337
+ receiver: Agent | Client,
338
+ handler: ((params: Params) => MaybePromise<Response>) | undefined,
339
+ method: string,
340
+ params: Params,
341
+ ): MaybePromise<Response> {
342
+ if (!handler) throw RequestError.methodNotFound(method);
343
+ return handler.call(receiver, params);
344
+ }