@chances-ai/wire 24.3.0 → 25.0.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.
Files changed (38) hide show
  1. package/dist/rpc/acp/engine-driver.d.ts +43 -1
  2. package/dist/rpc/acp/engine-driver.d.ts.map +1 -1
  3. package/dist/rpc/acp/engine-driver.js +94 -10
  4. package/dist/rpc/acp/engine-driver.js.map +1 -1
  5. package/dist/rpc/acp/event-map.d.ts +20 -0
  6. package/dist/rpc/acp/event-map.d.ts.map +1 -1
  7. package/dist/rpc/acp/event-map.js +41 -0
  8. package/dist/rpc/acp/event-map.js.map +1 -1
  9. package/dist/rpc/acp/terminal.d.ts +37 -0
  10. package/dist/rpc/acp/terminal.d.ts.map +1 -0
  11. package/dist/rpc/acp/terminal.js +46 -0
  12. package/dist/rpc/acp/terminal.js.map +1 -0
  13. package/dist/rpc/acp/workspace-edits.d.ts +41 -0
  14. package/dist/rpc/acp/workspace-edits.d.ts.map +1 -0
  15. package/dist/rpc/acp/workspace-edits.js +75 -0
  16. package/dist/rpc/acp/workspace-edits.js.map +1 -0
  17. package/dist/rpc/driver.d.ts +56 -1
  18. package/dist/rpc/driver.d.ts.map +1 -1
  19. package/dist/rpc/index.d.ts +5 -1
  20. package/dist/rpc/index.d.ts.map +1 -1
  21. package/dist/rpc/index.js +2 -0
  22. package/dist/rpc/index.js.map +1 -1
  23. package/dist/serve/acp-session-host.d.ts +127 -72
  24. package/dist/serve/acp-session-host.d.ts.map +1 -1
  25. package/dist/serve/acp-session-host.js +534 -140
  26. package/dist/serve/acp-session-host.js.map +1 -1
  27. package/dist/serve/relay-frames.d.ts +7 -0
  28. package/dist/serve/relay-frames.d.ts.map +1 -1
  29. package/dist/serve/relay-frames.js +15 -0
  30. package/dist/serve/relay-frames.js.map +1 -1
  31. package/dist/serve/relay.d.ts +12 -0
  32. package/dist/serve/relay.d.ts.map +1 -1
  33. package/dist/serve/relay.js +43 -2
  34. package/dist/serve/relay.js.map +1 -1
  35. package/dist/serve/ws-transport.d.ts.map +1 -1
  36. package/dist/serve/ws-transport.js +7 -0
  37. package/dist/serve/ws-transport.js.map +1 -1
  38. package/package.json +4 -4
@@ -0,0 +1,75 @@
1
+ /**
2
+ * (7.5 W1) The wire contract for `apply_edit` — the CLIENT-initiated workspace
3
+ * write that backs the Monaco editor's save. Mirrors the read-only
4
+ * `workspace-query.ts` shape (a method-name constant + one shared dispatcher the
5
+ * relay reuses), with two deliberate differences:
6
+ *
7
+ * 1. **Privileged.** Unlike the read-only queries (any lease viewer may browse),
8
+ * a write is privileged: the relay must check the controller lease BEFORE
9
+ * dispatching (`AcpSessionHost.requireController`), so a viewer cannot write.
10
+ * 2. **Fail-closed containment.** The host implementation (`applyWorkspaceEdit`)
11
+ * routes through the native fs_guard realpath jail + protected-path floor —
12
+ * a remote client can never write outside the workspace.
13
+ *
14
+ * Like the queries, the `AcpEngineDriver` does NOT handle this (stays turn-pure);
15
+ * it only advertises the `workspaceEdits` capability when its host implements
16
+ * `applyEdit`. stdio transports never advertise it, so a conformant client won't
17
+ * send it and a rogue send falls to `methodNotFound` (relay-only, decision 9.7).
18
+ */
19
+ import { WorkspaceEscapeError } from "@chances-ai/engine/core";
20
+ /** `_chances/unstable/apply_edit` (mirrors the `_chances/unstable/*` query set). */
21
+ export const APPLY_EDIT_METHOD = "_chances/unstable/apply_edit";
22
+ /** True for the single apply_edit write method. */
23
+ export function isWorkspaceEditMethod(method) {
24
+ return method === APPLY_EDIT_METHOD;
25
+ }
26
+ /** True when a host exposes the write primitive (⇒ advertise + intercept). */
27
+ export function hostSupportsWorkspaceEdits(host) {
28
+ return typeof host.applyEdit === "function";
29
+ }
30
+ /** JSON-RPC standard error codes (a subset; mirrors workspace-query). */
31
+ const ERR = { methodNotFound: -32601, invalidParams: -32602, serverError: -32000 };
32
+ function asEditParams(params) {
33
+ if (!params || typeof params !== "object")
34
+ return undefined;
35
+ const o = params;
36
+ if (typeof o.path !== "string")
37
+ return undefined;
38
+ const content = typeof o.content === "string" ? o.content : undefined;
39
+ const edits = Array.isArray(o.edits)
40
+ ? o.edits.flatMap((e) => e && typeof e === "object" && typeof e.oldText === "string" && typeof e.newText === "string"
41
+ ? [
42
+ {
43
+ oldText: e.oldText,
44
+ newText: e.newText,
45
+ replaceAll: e.replaceAll === true,
46
+ },
47
+ ]
48
+ : [])
49
+ : undefined;
50
+ return { path: o.path, content, edits };
51
+ }
52
+ /**
53
+ * Validate params, call `host.applyEdit`, and shape a JSON-RPC result/error. A
54
+ * {@link WorkspaceEscapeError} (containment / protected-path) maps to
55
+ * `invalidParams`; a missing primitive to `methodNotFound`; any other throw
56
+ * (e.g. a hunk that didn't match) to `serverError`. The caller (relay) writes the
57
+ * response via a targeted off-ring `replyTo`. The `signal` bounds a hung write.
58
+ */
59
+ export async function dispatchWorkspaceEdit(host, params, signal) {
60
+ if (!host.applyEdit)
61
+ return { error: { code: ERR.methodNotFound, message: "apply_edit unsupported" } };
62
+ const p = asEditParams(params);
63
+ if (!p)
64
+ return { error: { code: ERR.invalidParams, message: "apply_edit requires a string `path` (+ `content` or `edits`)" } };
65
+ try {
66
+ return { result: await host.applyEdit(p, signal) };
67
+ }
68
+ catch (e) {
69
+ if (e instanceof WorkspaceEscapeError) {
70
+ return { error: { code: ERR.invalidParams, message: e.message } };
71
+ }
72
+ return { error: { code: ERR.serverError, message: e.message ?? String(e) } };
73
+ }
74
+ }
75
+ //# sourceMappingURL=workspace-edits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-edits.js","sourceRoot":"","sources":["../../../src/rpc/acp/workspace-edits.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { AgentResult, GitDiffResult, GitStatusResult, ListFilesResult, ReadFileResult } from "@chances-ai/engine/core";
1
+ import type { ApplyEditParams, ApplyEditResult, AgentResult, GitDiffResult, GitStatusResult, ListFilesResult, ReadFileResult } from "@chances-ai/engine/core";
2
2
  import type { ApprovalState, CancellationToken, EventBus, ModelSelection } from "@chances-ai/runtime";
3
3
  import type { PermissionResolver } from "@chances-ai/engine/tools";
4
4
  import type { ModelInfo } from "./protocol.js";
@@ -19,6 +19,12 @@ export interface BuiltEngine {
19
19
  approval?: ApprovalState;
20
20
  /** Stable session id surfaced in the `ready` handshake + `turn_start`. */
21
21
  sessionId: string;
22
+ /** (7.5 §14.2) Per-session teardown for the TRUE-concurrent SessionRouter:
23
+ * disposes this session's OWN isolated services (e.g. its per-session
24
+ * `AsyncTaskRegistry`) when the unit is evicted/shut down. Absent for the
25
+ * shared single-engine path (the runtime owns those services). The router
26
+ * awaits it when tearing a unit down; idempotent + best-effort. */
27
+ dispose?: () => Promise<void>;
22
28
  }
23
29
  /** Implemented by apps/cli. The server owns the permission round-trip, so it
24
30
  * constructs the resolver and hands it here at build time. */
@@ -38,5 +44,54 @@ export interface EngineHost {
38
44
  queryGitStatus?(signal: AbortSignal): Promise<GitStatusResult>;
39
45
  /** `git diff [path]` (capped) + shortstat totals. */
40
46
  queryGitDiff?(path: string | undefined, signal: AbortSignal): Promise<GitDiffResult>;
47
+ /** Apply a client-initiated workspace edit (whole-file or hunks), atomically. */
48
+ applyEdit?(params: ApplyEditParams, signal: AbortSignal): Promise<ApplyEditResult>;
49
+ /** Open a PTY. `onOutput` streams decoded output; resolves with a live handle. */
50
+ openTerminal?(opts: TerminalOpenOptions, onOutput: (data: string) => void): Promise<TerminalHandle>;
51
+ /** Persisted sessions for the sidebar (host orders them; newest first). */
52
+ listSessions?(): SessionSummary[];
53
+ /** Rebuild the engine for an existing session (resume from store) WITHOUT
54
+ * tearing down the shared runtime; returns the rebuilt engine + its message
55
+ * history for replay, or undefined when the id is unknown. */
56
+ loadSession?(id: string, resolver: PermissionResolver): {
57
+ engine: BuiltEngine;
58
+ history: SessionHistoryMessage[];
59
+ } | undefined;
60
+ }
61
+ /** (7.5 W4) A persisted session, summarised for the cross-surface sidebar
62
+ * ("same sessions everywhere", decision [12.14]). ui-core + client-core mirror
63
+ * this shape for the view model. */
64
+ export interface SessionSummary {
65
+ id: string;
66
+ title: string;
67
+ /** ISO timestamp of the last update (for newest-first ordering). */
68
+ updatedAt: string;
69
+ /** (7.5 §14) Overlaid by the relay's SessionRouter: true for a live session
70
+ * with a turn in flight (so the sidebar can flag a busy background session). */
71
+ busy?: boolean;
72
+ }
73
+ /** (7.5 W4) A flattened history message for `session/load` replay (structural;
74
+ * matches engine `Message`). */
75
+ export interface SessionHistoryMessage {
76
+ role: string;
77
+ content?: Array<{
78
+ type: string;
79
+ [k: string]: unknown;
80
+ }>;
81
+ }
82
+ /** (7.5 W3) Options for {@link EngineHost.openTerminal}. */
83
+ export interface TerminalOpenOptions {
84
+ cols: number;
85
+ rows: number;
86
+ /** Defaults to the workspace root. */
87
+ cwd?: string;
88
+ /** Defaults to the user's login shell. */
89
+ command?: string;
90
+ }
91
+ /** (7.5 W3) A live PTY the relay drives for one terminal session. */
92
+ export interface TerminalHandle {
93
+ write(data: string): void;
94
+ resize(cols: number, rows: number): void;
95
+ close(): void;
41
96
  }
42
97
  //# sourceMappingURL=driver.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/rpc/driver.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC5H,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACtG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B;+DAC2D;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxE,4DAA4D;IAC5D,GAAG,EAAE,QAAQ,CAAC;IACd,6EAA6E;IAC7E,SAAS,EAAE,cAAc,CAAC;IAC1B;;;;sEAIkE;IAClE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;8DAC8D;AAC9D,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,KAAK,CAAC,QAAQ,EAAE,kBAAkB,GAAG,WAAW,CAAC;IACjD,mEAAmE;IACnE,UAAU,IAAI,SAAS,EAAE,CAAC;IAC1B;gFAC4E;IAC5E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IASzB,0EAA0E;IAC1E,cAAc,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5E,kFAAkF;IAClF,aAAa,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3E,iFAAiF;IACjF,cAAc,CAAC,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/D,qDAAqD;IACrD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACtF"}
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/rpc/driver.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9J,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACtG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,oEAAoE;AACpE,MAAM,WAAW,WAAW;IAC1B;+DAC2D;IAC3D,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACxE,4DAA4D;IAC5D,GAAG,EAAE,QAAQ,CAAC;IACd,6EAA6E;IAC7E,SAAS,EAAE,cAAc,CAAC;IAC1B;;;;sEAIkE;IAClE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,0EAA0E;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB;;;;wEAIoE;IACpE,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED;8DAC8D;AAC9D,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,KAAK,CAAC,QAAQ,EAAE,kBAAkB,GAAG,WAAW,CAAC;IACjD,mEAAmE;IACnE,UAAU,IAAI,SAAS,EAAE,CAAC;IAC1B;gFAC4E;IAC5E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IASzB,0EAA0E;IAC1E,cAAc,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5E,kFAAkF;IAClF,aAAa,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3E,iFAAiF;IACjF,cAAc,CAAC,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/D,qDAAqD;IACrD,YAAY,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAQrF,iFAAiF;IACjF,SAAS,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IAOnF,kFAAkF;IAClF,YAAY,CAAC,CAAC,IAAI,EAAE,mBAAmB,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAQpG,2EAA2E;IAC3E,YAAY,CAAC,IAAI,cAAc,EAAE,CAAC;IAClC;;mEAE+D;IAC/D,WAAW,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG;QAAE,MAAM,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,qBAAqB,EAAE,CAAA;KAAE,GAAG,SAAS,CAAC;CAC/H;AAED;;qCAEqC;AACrC,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB;qFACiF;IACjF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;iCACiC;AACjC,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAC;CACzD;AAED,4DAA4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,KAAK,IAAI,IAAI,CAAC;CACf"}
@@ -1,5 +1,6 @@
1
1
  export { PROTOCOL_NAME, PROTOCOL_VERSION, CommandSchema, RSEQ_KEY, stampSeq, readRseq, type Command, type CommandType, type ModelInfo, type ServerFrame, type EventFrame, type ReadyFrame, type ResponseFrame, type RequestPermissionFrame, type RelayFrame, type RelayWelcomeFrame, type ResetFrame, type ClientInboundFrame, type RpcError, type RpcErrorCode, type StopReason, } from "./protocol.js";
2
- export type { BuiltEngine, EngineHost } from "./driver.js";
2
+ export type { BuiltEngine, EngineHost, SessionHistoryMessage, SessionSummary } from "./driver.js";
3
+ export type { PermissionResolver } from "@chances-ai/engine/tools";
3
4
  export { BoundedNdjsonWriter, type ByteSink, type WriterOptions } from "./writer.js";
4
5
  export { installStdoutGuard, type StdoutGuard } from "./stdout-guard.js";
5
6
  export { mapEvent, type EventMapOptions } from "./event-map.js";
@@ -10,4 +11,7 @@ export { mapEventToAcp, type AcpMapOptions } from "./acp/event-map.js";
10
11
  export { AcpEngineDriver, ACP_PROTOCOL_VERSION, type AcpEngineDriverOptions } from "./acp/engine-driver.js";
11
12
  export { loadAcpSdk, type AcpSdk } from "./acp/load-sdk.js";
12
13
  export { WORKSPACE_QUERY_METHODS, dispatchWorkspaceQuery, hostSupportsWorkspaceQueries, isWorkspaceQueryMethod, type QueryOutcome, } from "./acp/workspace-query.js";
14
+ export { APPLY_EDIT_METHOD, dispatchWorkspaceEdit, hostSupportsWorkspaceEdits, isWorkspaceEditMethod, type EditOutcome, } from "./acp/workspace-edits.js";
15
+ export { TERMINAL_METHODS, hostSupportsTerminal, isTerminalMethod } from "./acp/terminal.js";
16
+ export type { TerminalHandle, TerminalOpenOptions } from "./driver.js";
13
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,UAAU,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAC5G,OAAO,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,sBAAsB,EACtB,KAAK,YAAY,GAClB,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,KAAK,OAAO,EACZ,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,UAAU,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClG,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,KAAK,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAC5G,OAAO,EAAE,UAAU,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,sBAAsB,EACtB,KAAK,YAAY,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,EACrB,KAAK,WAAW,GACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC7F,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
package/dist/rpc/index.js CHANGED
@@ -15,4 +15,6 @@ export { mapEventToAcp } from "./acp/event-map.js";
15
15
  export { AcpEngineDriver, ACP_PROTOCOL_VERSION } from "./acp/engine-driver.js";
16
16
  export { loadAcpSdk } from "./acp/load-sdk.js";
17
17
  export { WORKSPACE_QUERY_METHODS, dispatchWorkspaceQuery, hostSupportsWorkspaceQueries, isWorkspaceQueryMethod, } from "./acp/workspace-query.js";
18
+ export { APPLY_EDIT_METHOD, dispatchWorkspaceEdit, hostSupportsWorkspaceEdits, isWorkspaceEditMethod, } from "./acp/workspace-edits.js";
19
+ export { TERMINAL_METHODS, hostSupportsTerminal, isTerminalMethod } from "./acp/terminal.js";
18
20
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,8EAA8E;AAC9E,oEAAoE;AAEpE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,QAAQ,GAgBT,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,mBAAmB,EAAqC,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAwB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAyB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAsB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAsB,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAA+B,MAAM,wBAAwB,CAAC;AAC5G,OAAO,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,sBAAsB,GAEvB,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rpc/index.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,8EAA8E;AAC9E,oEAAoE;AAEpE,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,QAAQ,EACR,QAAQ,EACR,QAAQ,GAgBT,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,mBAAmB,EAAqC,MAAM,aAAa,CAAC;AACrF,OAAO,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAwB,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAyB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAsB,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,aAAa,EAAsB,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAA+B,MAAM,wBAAwB,CAAC;AAC5G,OAAO,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,4BAA4B,EAC5B,sBAAsB,GAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,qBAAqB,GAEtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,43 +1,55 @@
1
1
  /**
2
- * (v20 M3 / docs/6.4a §3; v21 M4 lease / docs/6.5 §5) `AcpSessionHost` — the ACP
3
- * twin of the bespoke session host. ONE persistent engine session per process,
4
- * sockets attach/detach over a seq-stamping `ReplayHub` fan-out; the inner engine
5
- * is the `AcpEngineDriver` (ACP JSON-RPC wire).
2
+ * (v20 M3 / docs/6.4a §3; v21 M4 lease; **7.5 §14 TRUE-concurrent SessionRouter**)
3
+ * `AcpSessionHost` the ACP relay's connection-level host. Originally ONE engine
4
+ * session per process; as of 7.5 §14 it is a **SessionRouter** that owns N live
5
+ * `SessionUnit`s (each = its own `ReplayHub` ring + `AcpEngineDriver` turn-runner +
6
+ * `MessageQueue` + isolated engine), so several sessions run concurrent turns
7
+ * without cross-talk. The class name is kept (the relay imports it) — it IS the
8
+ * session host, now multi-session.
6
9
  *
7
- * Two deliberate differences from the M2 design:
8
- * 1. **State source.** The reconnect snapshot (`busy` / `pendingPermissionIds`)
9
- * is read straight off the driver (authoritative). The `ReplayHub` stays a
10
- * pure payload-agnostic seq/replay/fan-out layer it does NOT parse the
11
- * outbound bytes for session state (a byte-snoop lived there in the
12
- * chances-rpc era; removed with the M3 hard cutover, since ACP frames' first
13
- * key is `jsonrpc`/`rseq`, never `type`).
14
- * 2. **No `ready` re-send.** ACP is client-initiated: a fresh client sends
15
- * `initialize`/`session/new` and the driver replies; a cold-reloaded client
16
- * re-initializes (client-core, c4).
10
+ * **Layering (the split that makes concurrency safe):**
11
+ * - *Connection-level* (this object): the controller lease, the per-socket socket
12
+ * map, the interactive terminals (workspace-level, not chat-session-bound), the
13
+ * off-ring read queries / `apply_edit`, `take_control`, and the session
14
+ * lifecycle (`session/new` / `session/load` / `list_sessions`). It also tracks
15
+ * each client's ACTIVE session (which unit's stream that device sees).
16
+ * - *Session-level* (a `SessionUnit`): the turn loop — `session/prompt`
17
+ * `engine.runTurn` that session's bus `session/update` that unit's
18
+ * `ReplayHub` fanned ONLY to sockets whose active session is this unit.
17
19
  *
18
- * **Controller lease (v21 M4 §5).** Disabled by default fan-out: any paired
19
- * device drives, the engine serializes turns via `AGENT_BUSY` (the M2 model).
20
- * When enabled, this host gates every inbound command by its source clientId —
21
- * only the lease HOLDER may drive (`session/prompt`/`cancel`), answer a
22
- * permission, or change the model; everyone else is a read-only VIEWER and gets a
23
- * typed `not_controller`. `_chances/unstable/take_control` hands control over
24
- * (any authed client may claim it — single-user multi-device) and bumps
25
- * `controlEpoch`; the new holder + epoch are broadcast as a
26
- * `_chances/unstable/control` notification. The gate lives HERE (it needs the
27
- * socket→clientId map) so the driver stays a protocol-pure turn runner.
20
+ * **Per-session ring (decision §6.1 / §14, codex R3 Q4).** Each unit has its own
21
+ * `ReplayHub` (rseq/session): a device attaches to its active session's hub, so it
22
+ * receives only that session's stream and reconnect-replays only that session's
23
+ * gap. Connection-level broadcasts (lease state, `workspace_changed`) are written
24
+ * to EVERY unit's hub ({@link broadcastToAllUnits}) so they reach every socket
25
+ * and for the N=1 degenerate (one unit) that is byte-identical to the pre-§14
26
+ * single-hub behaviour.
28
27
  *
29
- * **Threat model (codex M4-review).** The lease is COORDINATION among one user's
30
- * equally-authed devices, NOT an authorization boundary. The security boundary is
31
- * the pairing token (every connection is already token-authed); `clientId` is a
32
- * self-reported coordination tag, not a trusted identity. A device could spoof
33
- * another's clientId to "impersonate" the holder but it gains nothing
34
- * `take_control` doesn't already grant (any authed client may claim control), so
35
- * there is no privilege escalation among your own devices. A truly-restricted
36
- * viewer (read-only access shared with a THIRD party) needs server-issued identity
37
- * and belongs to the multi-tenant Team era — out of scope here.
28
+ * **N=1 byte-identical (hard condition, codex R3 Q2).** The eagerly-built DEFAULT
29
+ * unit + the unchanged `AcpEngineDriver` per-session handlers mean a single-session
30
+ * connection (one `session/new`, prompts, reconnect) emits exactly the same bytes
31
+ * as before: initialize / session-new / prompt responses are produced by the SAME
32
+ * driver code, stamped through the (one) hub; the attach order (relay_welcome →
33
+ * replayed gap re-sent open permissions live socket) is preserved.
38
34
  *
39
- * The seq/replay layer (`ReplayHub`) is reused UNCHANGED it stamps `rseq` on
40
- * the serialized ACP JSON-RPC bytes (payload-agnostic, docs/6.2 §3.2).
35
+ * **Active session is keyed by `clientId` (codex R3 Q3 note).** `clientId` is
36
+ * minted per `RpcClient` INSTANCE (it doubles as the JSON-RPC id-correlation
37
+ * prefix, so the wire already requires it unique per client). Two browser tabs are
38
+ * two `RpcClient`s ⇒ two clientIds; a reconnect reuses its clientId to resume its
39
+ * lease / terminals / active session — exactly what we want. The "two live sockets
40
+ * share one clientId" case codex flagged needs a non-conformant client (id
41
+ * correlation would already break), so per-client active-session is consistent with
42
+ * the existing trust model and avoids a redundant per-socket token.
43
+ *
44
+ * **Controller lease (v21 M4 §5).** Disabled by default ⇒ fan-out (any paired
45
+ * device drives; the engine serializes turns via `AGENT_BUSY`). When enabled, only
46
+ * the HOLDER may drive (prompt/cancel/new/load/set_model) or answer a permission;
47
+ * others are read-only VIEWERs (`not_controller`). The lease is COORDINATION among
48
+ * one user's equally-authed devices, NOT an authorization boundary (the pairing
49
+ * token is the security boundary; `clientId` is a self-reported coordination tag).
50
+ *
51
+ * The seq/replay layer (`ReplayHub`) is reused UNCHANGED — payload-agnostic rseq
52
+ * stamping on the serialized ACP JSON-RPC bytes.
41
53
  */
42
54
  import { type EngineHost } from "../rpc/index.js";
43
55
  import { type ReplayHubOptions } from "./replay-hub.js";
@@ -48,73 +60,116 @@ export interface AcpSessionHostOptions {
48
60
  name: string;
49
61
  version: string;
50
62
  };
51
- /** Auto-approve every tool permission (trusted automation). Default false. */
52
63
  autoApprove?: boolean;
53
- /** stderr-style sink for routed `log` events + writer diagnostics. */
54
64
  logSink?: (line: string) => void;
55
- /** Replay ring depth (frames). Default {@link ReplayHub}'s. */
56
65
  ring?: ReplayHubOptions;
57
- /** (v21 M4 §5) Enable the single-controller lease. Default false ⇒ fan-out
58
- * (any paired device drives; the engine serializes turns via AGENT_BUSY). */
59
66
  controllerLease?: boolean;
67
+ terminalEnabled?: boolean;
60
68
  }
61
69
  export interface AcpAttachment {
62
- /** Per-attach fencing token (forward-compat; not enforced on the M3 WS — the
63
- * fan-out has no exclusive lock to fence). */
64
70
  epoch: number;
65
- /** Remove this socket from the fan-out. Idempotent; does NOT end the session. */
71
+ /** Remove this socket from the fan-out. Idempotent; does NOT end any session. */
66
72
  detach(): void;
67
73
  }
68
74
  export declare class AcpSessionHost {
69
- private readonly hub;
70
- private readonly queue;
71
- private readonly driver;
72
75
  private readonly host;
73
- private readonly done;
76
+ private readonly opts;
77
+ private readonly ringOpts?;
78
+ private readonly driverCaps;
74
79
  private epochCounter;
75
80
  private shuttingDown;
81
+ private readonly units;
82
+ private readonly defaultSessionId;
83
+ /** The FIRST `session/new` claims the eagerly-built default unit (N=1 byte
84
+ * identical); subsequent `session/new`s mint fresh units. */
85
+ private defaultClaimed;
86
+ private sessionSeq;
76
87
  private readonly leaseEnabled;
77
88
  private holder;
78
89
  private controlEpoch;
79
- /** clientId → socket, for TARGETED lease replies (not_controller / ack). */
80
- private readonly socketsByClient;
90
+ /** clientId → its connection (socket + active session). */
91
+ private readonly conns;
92
+ private readonly terminalEnabled;
93
+ private terminalSeq;
94
+ private readonly terminals;
81
95
  constructor(opts: AcpSessionHostOptions);
96
+ /** (§14) Spin up a new live session: its own hub + queue + driver. The driver's
97
+ * `run()` builds the engine through `loader` (its own resolver) in its
98
+ * synchronous prefix, so `driver.sessionId` is set by the time `run()` returns
99
+ * the promise — we can key the unit immediately. */
100
+ private createUnit;
101
+ /** Evict the OLDEST idle unit when over the cap — so `session/new` spam can't
102
+ * leak. A victim must be non-default, non-busy, AND not currently VIEWED by any
103
+ * connection (codex R4 M2 — evicting a viewed session would orphan its conns,
104
+ * whose later messages would silently route to the default unit). Logs what was
105
+ * dropped (no silent truncation); if every over-cap unit is protected, we keep
106
+ * them (better a bounded overshoot than killing a live/viewed session). */
107
+ private evictIfOverCap;
108
+ private unitFor;
82
109
  /**
83
- * Attach a socket, synchronously replaying everything since `lastSeq` then
84
- * going live (same disjoint-and-ordered guarantee as the M2 host). `clientId`
85
- * (from the `?client_id=` connect query) attributes this socket for the lease.
86
- * Wire order: `relay_welcome` → replayed gap → re-sent open permissions → [live].
110
+ * Attach a socket, replaying everything since `lastSeq` from its active session's
111
+ * ring then going live. `sessionId` (the `?session_id=` connect query) selects
112
+ * which unit to view (defaults to the client's last active, else the default
113
+ * unit — N=1 byte-identical). Wire order: `relay_welcome` → replayed gap →
114
+ * re-sent open permissions → [live].
87
115
  */
88
- attach(socket: ServerSocket, lastSeq: number, clientId?: string): AcpAttachment;
116
+ attach(socket: ServerSocket, lastSeq: number, clientId?: string, sessionId?: string): AcpAttachment;
89
117
  /**
90
- * One inbound text message (ACP JSON-RPC). Split LF-batched lines; each line
91
- * passes the lease {@link gate} (a no-op when the lease is disabled) before
92
- * reaching the ONE persistent queue. `fromClientId` (the attach's clientId)
93
- * attributes the command to a client for the lease.
118
+ * One inbound text message (ACP JSON-RPC). Connection-level methods (off-ring
119
+ * queries/edit/terminal, the lease, the session lifecycle) are handled here;
120
+ * everything else is routed to the client's ACTIVE session unit's queue.
94
121
  */
95
122
  onMessage(text: string, fromClientId?: string): void;
96
- /** Answer one read-only workspace query: dispatch to the host's query
97
- * primitives and `replyTo` the originating socket only (off-ring). Needs an id
98
- * (to respond) and a clientId (to target); a query missing either is dropped
99
- * (a conformant client always sends both). */
123
+ /** Route a session-level line (prompt, cancel, permission answer, set_model,
124
+ * set_options, initialize, get_state, get_models, ping) to the client's active
125
+ * session unit. A `params.sessionId`, when present, addresses a specific unit
126
+ * (prompt/cancel carry it codex R3 Q3); a JSON-RPC RESPONSE (no method, has id
127
+ * — a permission answer) is broadcast to ALL units so the owning driver resolves
128
+ * it and the rest ignore the foreign id. */
129
+ private routeToActive;
130
+ /** (§14) `session/new`: the FIRST claims the default unit (N=1 byte-identical);
131
+ * later ones mint a fresh unit. Switch the requesting client's view to it, then
132
+ * push the `session/new` line to that unit's driver so IT responds (eager
133
+ * sessionId) — reusing the driver's exact response bytes. */
134
+ private handleNewSession;
135
+ /** (§14) `session/load`: rejoin a live unit, or resume one from the store into a
136
+ * fresh unit, then switch the client's view (replaying that unit's ring) and
137
+ * ack. Unknown id → invalidParams. */
138
+ private handleLoadSession;
139
+ /** (§14) `list_sessions`: read-only, merge live + persisted, off-ring reply. */
140
+ private handleListSessions;
141
+ /** Move a client's view to `unit`: detach its socket from the old unit's hub,
142
+ * attach to the new one (optionally replaying the new unit's ring so a
143
+ * session/load device sees the rehydrated transcript), update active session. */
144
+ private switchClientTo;
100
145
  private handleQuery;
101
- /**
102
- * Controller-lease gate. Returns true ⇒ the line may proceed to the driver;
103
- * false ⇒ the host handled it (a handoff) or rejected it (a viewer's privileged
104
- * command — a `not_controller` reply was sent to the source). A no-op (always
105
- * true) when the lease is disabled.
106
- */
146
+ private handleEdit;
147
+ private handleTerminal;
148
+ private onTerminalOutput;
149
+ private closeTerminal;
150
+ private detachTerminals;
151
+ private resubscribeTerminals;
152
+ /** Lease gate for QUEUED commands (prompt, cancel, set_model, set_options,
153
+ * permission answers). True ⇒ proceed; false ⇒ host-handled (handoff) or
154
+ * rejected (`not_controller`). */
107
155
  private gate;
108
- /** Broadcast the current lease state to every socket (stamped + fanned out). */
156
+ /** Controller check for a PRIVILEGED command. True allowed; false rejected
157
+ * (`not_controller` sent). Shared by {@link gate} AND the privileged off-ring
158
+ * intercepts (apply_edit / terminal / session new+load) so none bypass the lease. */
159
+ private requireController;
160
+ /** Connection-level broadcast: write `frame` to EVERY unit's hub (so it reaches
161
+ * every socket regardless of active session). N=1 ⇒ the single hub ⇒ byte
162
+ * identical to the pre-§14 single-hub `hub.write`. */
163
+ private broadcastToAllUnits;
109
164
  private broadcastControlState;
110
- /** Send a single frame to ONE client (targeted; not fanned out, not stamped). */
165
+ /** Send a single frame to ONE client's socket (targeted; not fanned, not stamped). */
111
166
  private replyTo;
112
167
  get headSeq(): number;
113
168
  get socketCount(): number;
114
169
  get busy(): boolean;
115
- /** Current lease holder (clientId) or null. Exposed for tests/diagnostics. */
116
170
  get controllerHolder(): string | null;
117
- /** End the persistent queue → `run` returns → graceful driver shutdown. */
171
+ /** Number of live sessions (diagnostics/tests). */
172
+ get sessionCount(): number;
118
173
  shutdown(): Promise<number>;
119
174
  }
120
175
  //# sourceMappingURL=acp-session-host.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"acp-session-host.d.ts","sourceRoot":"","sources":["../../src/serve/acp-session-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAWpE,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,sEAAsE;IACtE,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,+DAA+D;IAC/D,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB;kFAC8E;IAC9E,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B;mDAC+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkB;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAK;IACzB,4EAA4E;IAC5E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmC;gBAEvD,IAAI,EAAE,qBAAqB;IAoBvC;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa;IAwC/E;;;;;OAKG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAkBpD;;;mDAG+C;YACjC,WAAW;IASzB;;;;;OAKG;IACH,OAAO,CAAC,IAAI;IAuCZ,gFAAgF;IAChF,OAAO,CAAC,qBAAqB;IAK7B,iFAAiF;IACjF,OAAO,CAAC,OAAO;IAKf,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,WAAW,IAAI,MAAM,CAExB;IACD,IAAI,IAAI,IAAI,OAAO,CAElB;IACD,8EAA8E;IAC9E,IAAI,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEpC;IAED,2EAA2E;IACrE,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAOlC"}
1
+ {"version":3,"file":"acp-session-host.d.ts","sourceRoot":"","sources":["../../src/serve/acp-session-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,EAWL,KAAK,UAAU,EAMhB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAsDpE,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,MAAM,IAAI,IAAI,CAAC;CAChB;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4E;IACvG,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,YAAY,CAAS;IAG7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C;kEAC8D;IAC9D,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,UAAU,CAAK;IAGvB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IACvC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,YAAY,CAAK;IACzB,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IAGtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAU;IAC1C,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;gBAE9C,IAAI,EAAE,qBAAqB;IAoBvC;;;yDAGqD;IACrD,OAAO,CAAC,UAAU;IA2ClB;;;;;gFAK4E;IAC5E,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,OAAO;IAIf;;;;;;OAMG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa;IAsCnG;;;;OAIG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IAyCpD;;;;;iDAK6C;IAC7C,OAAO,CAAC,aAAa;IAarB;;;kEAG8D;IAC9D,OAAO,CAAC,gBAAgB;IAkBxB;;2CAEuC;IACvC,OAAO,CAAC,iBAAiB;IAiCzB,gFAAgF;IAChF,OAAO,CAAC,kBAAkB;IAe1B;;sFAEkF;IAClF,OAAO,CAAC,cAAc;YAsBR,WAAW;YAMX,UAAU;YAaV,cAAc;IA+C5B,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,oBAAoB;IAY5B;;uCAEmC;IACnC,OAAO,CAAC,IAAI;IAiBZ;;0FAEsF;IACtF,OAAO,CAAC,iBAAiB;IAezB;;2DAEuD;IACvD,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,qBAAqB;IAM7B,sFAAsF;IACtF,OAAO,CAAC,OAAO;IAQf,IAAI,OAAO,IAAI,MAAM,CAEpB;IACD,IAAI,WAAW,IAAI,MAAM,CAIxB;IACD,IAAI,IAAI,IAAI,OAAO,CAGlB;IACD,IAAI,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEpC;IACD,mDAAmD;IACnD,IAAI,YAAY,IAAI,MAAM,CAEzB;IAEK,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;CAclC"}