@ai-ecoverse/slicc-agent 4.3.4 → 5.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 (61) hide show
  1. package/README.md +8 -9
  2. package/dist/browser/guard.js +1 -1
  3. package/dist/browser/guard.js.map +2 -2
  4. package/dist/client.js +89 -84
  5. package/dist/client.js.map +3 -3
  6. package/dist/codemode/index.js +8 -12
  7. package/dist/codemode/index.js.map +2 -2
  8. package/dist/host.js +69 -117
  9. package/dist/host.js.map +3 -3
  10. package/dist/images/index.js +2 -2
  11. package/dist/images/index.js.map +2 -2
  12. package/dist/index.js +4 -13
  13. package/dist/index.js.map +2 -2
  14. package/dist/licks/extension.js +2 -2
  15. package/dist/licks/extension.js.map +2 -2
  16. package/dist/mcp/tools.js +3 -3
  17. package/dist/mcp/tools.js.map +2 -2
  18. package/dist/memory/extract.js +3 -1
  19. package/dist/memory/extract.js.map +2 -2
  20. package/dist/memory/prompt.js +2 -2
  21. package/dist/memory/prompt.js.map +2 -2
  22. package/dist/mismatch.js +9 -4
  23. package/dist/mismatch.js.map +2 -2
  24. package/dist/patches.js +1 -22
  25. package/dist/patches.js.map +2 -2
  26. package/dist/readonly.js +12 -38
  27. package/dist/readonly.js.map +2 -2
  28. package/dist/scoops/extension.js +1 -1
  29. package/dist/scoops/extension.js.map +2 -2
  30. package/dist/secrets/extension.js +13 -5
  31. package/dist/secrets/extension.js.map +2 -2
  32. package/dist/services.js +111 -13
  33. package/dist/services.js.map +2 -2
  34. package/dist/serving.js +174 -0
  35. package/dist/serving.js.map +7 -0
  36. package/dist/settings.js +4 -18
  37. package/dist/settings.js.map +2 -2
  38. package/dist/spectrum/agent-port.js +5 -1
  39. package/dist/spectrum/agent-port.js.map +2 -2
  40. package/dist/spectrum/index.js +11 -2
  41. package/dist/spectrum/index.js.map +2 -2
  42. package/dist/spectrum/notices-port.js +17 -2
  43. package/dist/spectrum/notices-port.js.map +2 -2
  44. package/dist/types/host.d.ts +15 -3
  45. package/dist/types/index.d.ts +2 -4
  46. package/dist/types/mismatch.d.ts +2 -2
  47. package/dist/types/patches.d.ts +0 -10
  48. package/dist/types/readonly.d.ts +6 -4
  49. package/dist/types/services.d.ts +13 -13
  50. package/dist/types/serving.d.ts +37 -0
  51. package/dist/types/settings.d.ts +0 -1
  52. package/dist/types/spectrum/agent-port.d.ts +2 -0
  53. package/dist/types/spectrum/index.d.ts +1 -1
  54. package/dist/types/spectrum/notices-port.d.ts +3 -1
  55. package/dist/types/wire.d.ts +10 -8
  56. package/dist/wire.js +70 -77
  57. package/dist/wire.js.map +2 -2
  58. package/package.json +13 -14
  59. package/dist/listener.js +0 -73
  60. package/dist/listener.js.map +0 -7
  61. package/dist/types/listener.d.ts +0 -11
@@ -1,11 +1 @@
1
- declare const applied: unique symbol;
2
1
  export declare const MCP_SSE_PATCH = "pi-mcp-sse-buffer";
3
- interface Patchable {
4
- prototype: {
5
- accept: (...args: unknown[]) => unknown;
6
- };
7
- [applied]?: true;
8
- }
9
- export declare function patchServerAccept(target: Patchable): void;
10
- export declare function applyPatches(): void;
11
- export {};
@@ -1,9 +1,11 @@
1
1
  import type { AgentRemote } from './remote/host.ts';
2
2
  import type { AgentPages } from './remote/pages.ts';
3
- import type { AgentControl, AgentSettings } from './services.ts';
4
3
  import { VIEW_ONLY } from './view-only.ts';
5
4
  export { VIEW_ONLY };
6
- export declare function viewControl(control: AgentControl): AgentControl;
7
- export declare function viewSettings(settings: AgentSettings): AgentSettings;
5
+ type Answer = (...args: unknown[]) => Promise<unknown>;
6
+ export declare const controlAnswer: (name: string) => Answer;
7
+ export declare const settingsAnswer: () => Answer;
8
+ export declare const remoteAnswer: (name: string) => Answer;
8
9
  export declare function viewPages(): AgentPages;
9
- export declare function viewRemote(remote: AgentRemote): AgentRemote;
10
+ export declare const pageAnswer: (name: string) => Answer;
11
+ export declare function viewRemote(remote: AgentRemote): Pick<AgentRemote, 'watch' | 'next' | 'close'>;
@@ -1,11 +1,10 @@
1
- import { type Context, type JsonValue, type ReplicatedState } from '@earendil-works/chord';
1
+ import type { Context, JsonValue, RemoteContract, ReplicatedState } from '@earendil-works/chord';
2
2
  import type { ConversationView } from '@earendil-works/pi-durable';
3
3
  import type { SendAttachment, ShownAttachment } from './attachments.ts';
4
4
  import type { ChangesView } from './changes/git.ts';
5
5
  import type { FrozenCone } from './freezer/index.ts';
6
6
  import type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';
7
7
  import type { AgentRemote } from './remote/host.ts';
8
- import type { AgentPages } from './remote/pages.ts';
9
8
  import type { VaultState } from './secrets/vault.ts';
10
9
  import type { Sprinkle } from './sprinkles/kind.ts';
11
10
  export type SendMode = 'steer' | 'followUp' | 'reject';
@@ -232,7 +231,9 @@ export interface AgentSettingsChange {
232
231
  thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;
233
232
  agentId?: string | null;
234
233
  }
235
- export declare const AgentControl: import("@earendil-works/chord").Service<AgentControl>;
234
+ export declare const CONTROL_METHODS: ("abort" | "agentCommands" | "changeAccept" | "changeRevert" | "changesOpen" | "compact" | "compactAgent" | "configure" | "createCone" | "createScoop" | "discard" | "drop" | "freeze" | "image" | "memoryRemove" | "memorySave" | "monitorClose" | "monitorOpen" | "newChat" | "reset" | "resolveAgentLick" | "resolveLick" | "rewind" | "rewindAgent" | "selectCone" | "send" | "sprinkleCall" | "sprinkleSend" | "stopAgent" | "thaw" | "toolLabel" | "unqueue" | "wait" | "webhook" | "withdraw")[];
235
+ export declare const CONTROL_READS: readonly (keyof AgentControl & string)[];
236
+ export declare const AgentControl: RemoteContract;
236
237
  export type Delivered = 'run' | 'steer' | 'follow-up';
237
238
  export interface AgentTranscript {
238
239
  readonly state: ReplicatedState<ConversationView>;
@@ -258,15 +259,13 @@ export interface Command {
258
259
  description: string;
259
260
  kind: 'prompt' | 'skill' | 'action';
260
261
  }
261
- export declare const AgentTranscript: import("@earendil-works/chord").Service<AgentTranscript>;
262
- export interface AgentSessions {
263
- attach(sessionId: string, context: Context): Promise<void>;
264
- detach(context: Context): Promise<void>;
265
- }
266
- export declare const AgentSessions: import("@earendil-works/chord").Service<AgentSessions>;
267
- export declare const AgentRemoteService: import("@earendil-works/chord").Service<AgentRemote>;
268
- export declare const AgentPagesService: import("@earendil-works/chord").Service<AgentPages>;
269
- export declare const AGENT_SESSION = "agent";
262
+ export declare const TRANSCRIPT_STATES: ("agents" | "changes" | "commands" | "deliveries" | "frozen" | "labels" | "memories" | "memoryScopes" | "monitor" | "privateRevision" | "sprinkles" | "state" | "vault" | "views")[];
263
+ export declare const AgentTranscript: RemoteContract;
264
+ export declare const REMOTE_METHODS: ("abort" | "close" | "next" | "prompt" | "watch")[];
265
+ export declare const REMOTE_READS: readonly (keyof AgentRemote & string)[];
266
+ export declare const AgentRemoteService: RemoteContract;
267
+ export declare const PAGE_METHODS: ("answer" | "close" | "next" | "open" | "report")[];
268
+ export declare const AgentPagesService: RemoteContract;
270
269
  export interface ModelChoice {
271
270
  id: string;
272
271
  label: string;
@@ -325,4 +324,5 @@ export interface AgentSettings {
325
324
  signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;
326
325
  dismissMoved(context: Context): Promise<void>;
327
326
  }
328
- export declare const AgentSettings: import("@earendil-works/chord").Service<AgentSettings>;
327
+ export declare const SETTINGS_METHODS: ("connect" | "disconnect" | "dismissMoved" | "signIn")[];
328
+ export declare const AgentSettings: RemoteContract;
@@ -0,0 +1,37 @@
1
+ import { type Ctx, type Principal, type Readable, type RemoteContract, type ReplicatedState } from '@earendil-works/chord';
2
+ import { type Context } from '@earendil-works/chord/context';
3
+ export declare const AGENT_HOST = "agent";
4
+ export type Seat = 'owner' | 'control' | 'view';
5
+ export interface AgentPrincipal {
6
+ seat: Seat;
7
+ link: number;
8
+ }
9
+ export declare const seatOf: (principal: Principal) => Seat;
10
+ export declare const principalKey: (principal: Principal) => string;
11
+ export interface Members {
12
+ methods?: readonly string[];
13
+ state?: readonly string[];
14
+ }
15
+ export declare function contract(name: string, variants: Record<string, Members>): RemoteContract;
16
+ export type Callable = (...args: unknown[]) => Promise<unknown>;
17
+ export declare const contextOf: (ctx: Ctx) => Context;
18
+ export declare function served(impl: () => object, names: readonly string[]): Record<string, (args: unknown[], ctx: Ctx) => Promise<unknown>>;
19
+ export declare function readable<T>(state: ReplicatedState<T>): Readable<T>;
20
+ export declare function readablesOf(states: Record<string, ReplicatedState<unknown>>): Record<string, Readable<unknown>>;
21
+ export interface Remote {
22
+ readonly kind: string | undefined;
23
+ readonly ready: Promise<void>;
24
+ release(): void;
25
+ [member: string]: unknown;
26
+ }
27
+ export declare function replicated<T>(member: Readable<T | undefined>): ReplicatedState<T>;
28
+ export declare function kept(member: Readable<unknown>): {
29
+ ready: Promise<void>;
30
+ stop(): void;
31
+ };
32
+ export declare const CLOSED = "the connection to the agent is closed";
33
+ export declare function plain(error: unknown): unknown;
34
+ export type Root = <R>(run: (ctx: Ctx) => Promise<R>, options: {
35
+ signal?: AbortSignal;
36
+ }) => Promise<R>;
37
+ export declare function bound<T extends object>(handle: Remote, root: Root, names: readonly string[], absent: (name: string) => Callable): T;
@@ -28,7 +28,6 @@ export interface ProviderFields {
28
28
  set(providerId: string, fields: Record<string, string> | undefined): Promise<void>;
29
29
  }
30
30
  export declare function providerFields(store: PlainStore, providers: readonly Provider[]): Promise<ProviderFields>;
31
- export declare function shown<T>(run: () => Promise<T>): Promise<T>;
32
31
  export type UsageReader = (token: string) => Promise<Budget | null>;
33
32
  export interface SettingsSources {
34
33
  records: VaultRecords;
@@ -5,6 +5,7 @@ import type { Command } from '../services.ts';
5
5
  import { Emitter } from './emitter.ts';
6
6
  export declare const CONE = "cone";
7
7
  export declare function slashCommand({ kind, ...command }: Command): SlashCommand;
8
+ export declare const WATCH_ONLY = "Watch only.";
8
9
  export type AgentHold = VaultHold;
9
10
  export type AgentAdapterEvents = AgentEvents & {
10
11
  hold: AgentHold | null;
@@ -15,6 +16,7 @@ export declare class AgentAdapter extends Emitter<AgentAdapterEvents> implements
15
16
  notify(text: string, agentId?: string): void;
16
17
  ready(): Promise<void>;
17
18
  hold(): AgentHold | null;
19
+ readOnly(): string | null;
18
20
  list(): readonly Agent[];
19
21
  active(): string;
20
22
  select(id: string): void;
@@ -14,7 +14,7 @@ export { ChangesAdapter, type ChangesEvents } from './changes-port.ts';
14
14
  export { MemoryAdapter } from './memory-port.ts';
15
15
  export { assistant, errorAction, errorPart, isBusy, queued, textOf, toMessages, } from './messages.ts';
16
16
  export { MonitorAdapter, type MonitorAdapterOptions, type MonitorInput, monitorSnapshot, } from './monitor-port.ts';
17
- export { KEYS_MOVED, movedList, movedNotice, NoticesAdapter } from './notices-port.ts';
17
+ export { KEYS_MOVED, MISMATCH, mismatchBanner, movedList, movedNotice, NoticesAdapter, } from './notices-port.ts';
18
18
  export { PageAdapter, type PageDocument, type PageOptions, type PageRun, type PageTarget, } from './page-port.ts';
19
19
  export { type Login, SETTINGS_KEY, SettingsAdapter } from './settings-port.ts';
20
20
  export { SprinkleAdapter } from './sprinkle-port.ts';
@@ -4,13 +4,15 @@ import type { AgentSettings } from '../services.ts';
4
4
  import { type Report } from './attempt.ts';
5
5
  import { Emitter } from './emitter.ts';
6
6
  export declare const KEYS_MOVED = "keys-moved";
7
+ export declare const MISMATCH = "agent-mismatch";
8
+ export declare function mismatchBanner(text: string): Notice;
7
9
  export declare function movedList(accounts: readonly MovedName[]): string;
8
10
  export declare function movedNotice(accounts: readonly MovedName[]): Notice;
9
11
  export declare class NoticesAdapter extends Emitter<{
10
12
  notices: readonly Notice[];
11
13
  }> implements NoticesPort {
12
14
  #private;
13
- constructor(settings: AgentSettings, report: Report);
15
+ constructor(settings: AgentSettings, report: Report, mismatch?: string);
14
16
  list(): readonly Notice[];
15
17
  act(): Promise<void>;
16
18
  dismiss(id: string): void;
@@ -1,4 +1,4 @@
1
- import type { ByteTransportFactory } from '@earendil-works/pi-client';
1
+ import type { Frame as ChordFrame, Link } from '@earendil-works/chord';
2
2
  export interface PortEndpoint {
3
3
  postMessage(message: unknown, transfer?: Transferable[]): void;
4
4
  addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
@@ -11,20 +11,22 @@ export type Frame = {
11
11
  } | {
12
12
  close: true;
13
13
  } | Uint8Array;
14
- export declare const LINK_PROTOCOL = 1;
14
+ export declare const LINK_PROTOCOL = 2;
15
15
  export interface Greeting {
16
16
  protocol: number;
17
17
  serverId: string;
18
18
  }
19
+ export declare const greeting: (serverId: string) => string;
19
20
  export declare function greeted(hello: string): Greeting;
20
- export declare function post(endpoint: PortEndpoint, chunk: Uint8Array): void;
21
- export declare function withUnrefTimers<T>(run: () => T, scope?: {
22
- setTimeout: typeof setTimeout;
23
- }): T;
24
- export declare class PortChannel {
21
+ export declare class PortLink implements Link {
25
22
  #private;
26
23
  readonly hello: Promise<string>;
27
24
  readonly ended: Promise<Error | undefined>;
28
25
  constructor(endpoint: PortEndpoint);
29
- readonly transport: ByteTransportFactory;
26
+ get closed(): boolean;
27
+ greet(serverId: string): void;
28
+ send(frame: ChordFrame): void;
29
+ receive(handler: (frame: ChordFrame) => void): void;
30
+ onClose(handler: (reason: string) => void): void;
31
+ close(reason?: string): void;
30
32
  }
package/dist/wire.js CHANGED
@@ -1,43 +1,26 @@
1
- const LINK_PROTOCOL = 1;
1
+ const LINK_PROTOCOL = 2;
2
2
  const GREETING = /^slicc-agent-link\/(\d+) (.+)$/;
3
+ const greeting = (serverId) => `slicc-agent-link/${LINK_PROTOCOL} ${serverId}`;
3
4
  function greeted(hello) {
4
5
  const found = GREETING.exec(hello);
5
- return found ? { protocol: Number(found[1]), serverId: found[2] } : { protocol: LINK_PROTOCOL, serverId: hello };
6
+ return found ? { protocol: Number(found[1]), serverId: found[2] } : { protocol: 1, serverId: hello };
6
7
  }
7
- function post(endpoint, chunk) {
8
- const copy = chunk.slice();
9
- endpoint.postMessage(copy, [copy.buffer]);
8
+ const encoder = new TextEncoder();
9
+ const decoder = new TextDecoder();
10
+ function parse(chunk) {
11
+ const frame = JSON.parse(decoder.decode(chunk));
12
+ if (frame === null || typeof frame !== "object" || typeof frame.t !== "string")
13
+ throw new TypeError("not a chord frame");
14
+ return frame;
10
15
  }
11
- function unrefable(id) {
12
- return {
13
- unref() {
14
- return this;
15
- },
16
- ref() {
17
- return this;
18
- },
19
- [Symbol.toPrimitive]: () => id
20
- };
21
- }
22
- function withUnrefTimers(run, scope = globalThis) {
23
- const original = scope.setTimeout;
24
- scope.setTimeout = ((...args) => {
25
- const id = original(...args);
26
- return typeof id === "number" ? unrefable(id) : id;
27
- });
28
- try {
29
- return run();
30
- } finally {
31
- scope.setTimeout = original;
32
- }
33
- }
34
- class PortChannel {
16
+ class PortLink {
35
17
  hello;
36
18
  ended;
37
19
  #endpoint;
38
20
  #queue = [];
39
- #handlers;
40
- #ended;
21
+ #closers = /* @__PURE__ */ new Set();
22
+ #handler;
23
+ #closed = false;
41
24
  #greet;
42
25
  #refuse;
43
26
  #finish;
@@ -47,67 +30,77 @@ class PortChannel {
47
30
  this.#greet = greet;
48
31
  this.#refuse = refuse;
49
32
  });
33
+ this.hello.catch(() => void 0);
50
34
  this.ended = new Promise((finish) => {
51
35
  this.#finish = finish;
52
36
  });
53
37
  endpoint.addEventListener("message", ({ data }) => this.#receive(data));
54
- endpoint.addEventListener(
55
- "messageerror",
56
- (event) => this.#end(new Error(`agent port ${event.type}`))
57
- );
58
- endpoint.addEventListener("error", (event) => this.#end(new Error(`agent port ${event.type}`)));
59
- endpoint.addEventListener("close", () => this.#end("close"));
38
+ const failed = (event) => this.#end(`agent port ${event.type}`, true);
39
+ endpoint.addEventListener("messageerror", failed);
40
+ endpoint.addEventListener("error", failed);
41
+ endpoint.addEventListener("close", () => this.#end("peer closed", false));
60
42
  endpoint.start?.();
61
43
  }
62
- transport = (handlers) => {
63
- this.#handlers = handlers;
64
- for (const chunk of this.#queue.splice(0)) handlers.onData(chunk);
65
- if (this.#ended) this.#deliver(this.#ended);
66
- return {
67
- send: async (chunk) => {
68
- if (this.#ended) throw new Error("agent port is closed");
69
- post(this.#endpoint, chunk);
70
- },
71
- close: () => {
72
- if (this.#ended) return;
73
- this.#ended = "close";
74
- this.#refuse(new Error("agent port closed before hello"));
75
- this.#finish(void 0);
76
- this.#endpoint.postMessage({ close: true });
77
- this.#endpoint.close?.();
78
- }
79
- };
80
- };
44
+ get closed() {
45
+ return this.#closed;
46
+ }
47
+ greet(serverId) {
48
+ this.#endpoint.postMessage({ hello: greeting(serverId) });
49
+ }
50
+ send(frame) {
51
+ if (this.#closed) return;
52
+ const bytes = encoder.encode(JSON.stringify(frame));
53
+ this.#endpoint.postMessage(bytes, [bytes.buffer]);
54
+ }
55
+ receive(handler) {
56
+ this.#handler = handler;
57
+ for (const chunk of this.#queue.splice(0)) this.#deliver(chunk);
58
+ }
59
+ onClose(handler) {
60
+ if (this.#closed) handler("closed");
61
+ else this.#closers.add(handler);
62
+ }
63
+ close(reason = "closed") {
64
+ if (this.#closed) return;
65
+ this.send({ t: "bye", reason });
66
+ this.#endpoint.postMessage({ close: true });
67
+ this.#end(reason, false);
68
+ }
81
69
  #receive(frame) {
70
+ if (this.#closed) return;
82
71
  if (frame instanceof Uint8Array) {
83
- if (this.#handlers) this.#handlers.onData(frame);
72
+ if (this.#handler) this.#deliver(frame);
84
73
  else this.#queue.push(frame);
85
- } else if ("hello" in frame) {
86
- this.#greet(frame.hello);
87
- } else {
88
- this.#end("close");
89
- }
74
+ } else if ("hello" in frame) this.#greet(frame.hello);
75
+ else this.#end("peer closed", false);
90
76
  }
91
- #end(reason) {
92
- if (this.#ended) return;
93
- this.#ended = reason;
94
- this.#refuse(reason === "close" ? new Error("agent port closed before hello") : reason);
95
- this.#finish(reason === "close" ? void 0 : reason);
96
- this.#deliver(reason);
77
+ #deliver(chunk) {
78
+ let frame;
79
+ try {
80
+ frame = parse(chunk);
81
+ } catch {
82
+ this.close("protocol error");
83
+ return;
84
+ }
85
+ if (frame.t === "bye") this.#end(frame.reason ?? "peer closed", false);
86
+ else this.#handler?.(frame);
97
87
  }
98
- #deliver(reason) {
99
- const handlers = this.#handlers;
100
- if (!handlers) return;
101
- this.#handlers = void 0;
102
- if (reason === "close") handlers.onClose();
103
- else handlers.onError(reason);
88
+ #end(reason, failed) {
89
+ if (this.#closed) return;
90
+ this.#closed = true;
91
+ this.#queue.length = 0;
92
+ this.#endpoint.close?.();
93
+ const error = new Error(reason);
94
+ this.#refuse(new Error(`agent port closed before hello: ${reason}`));
95
+ this.#finish(failed ? error : void 0);
96
+ for (const handler of [...this.#closers]) handler(reason);
97
+ this.#closers.clear();
104
98
  }
105
99
  }
106
100
  export {
107
101
  LINK_PROTOCOL,
108
- PortChannel,
102
+ PortLink,
109
103
  greeted,
110
- post,
111
- withUnrefTimers
104
+ greeting
112
105
  };
113
106
  //# sourceMappingURL=wire.js.map
package/dist/wire.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/wire.ts"],
4
- "sourcesContent": ["import type { ByteTransportFactory, ByteTransportHandlers } from '@earendil-works/pi-client';\n\nexport interface PortEndpoint {\n postMessage(message: unknown, transfer?: Transferable[]): void;\n addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;\n addEventListener(\n type: 'close' | 'messageerror' | 'error',\n listener: (event: Event) => void\n ): void;\n start?(): void;\n close?(): void;\n}\n\nexport type Frame = { hello: string } | { close: true } | Uint8Array;\n\nexport const LINK_PROTOCOL = 1;\n\nconst GREETING = /^slicc-agent-link\\/(\\d+) (.+)$/;\n\nexport interface Greeting {\n protocol: number;\n serverId: string;\n}\n\nexport function greeted(hello: string): Greeting {\n const found = GREETING.exec(hello);\n return found\n ? { protocol: Number(found[1]), serverId: found[2] as string }\n : { protocol: LINK_PROTOCOL, serverId: hello };\n}\n\nexport function post(endpoint: PortEndpoint, chunk: Uint8Array): void {\n const copy = chunk.slice();\n endpoint.postMessage(copy, [copy.buffer]);\n}\n\nfunction unrefable(id: number): object {\n return {\n unref() {\n return this;\n },\n ref() {\n return this;\n },\n [Symbol.toPrimitive]: () => id,\n };\n}\n\nexport function withUnrefTimers<T>(\n run: () => T,\n scope: { setTimeout: typeof setTimeout } = globalThis\n): T {\n const original = scope.setTimeout;\n scope.setTimeout = ((...args: Parameters<typeof setTimeout>) => {\n const id: unknown = original(...args);\n return typeof id === 'number' ? unrefable(id) : id;\n }) as typeof setTimeout;\n try {\n return run();\n } finally {\n scope.setTimeout = original;\n }\n}\n\nexport class PortChannel {\n readonly hello: Promise<string>;\n readonly ended: Promise<Error | undefined>;\n readonly #endpoint: PortEndpoint;\n readonly #queue: Uint8Array[] = [];\n #handlers: ByteTransportHandlers | undefined;\n #ended: 'close' | Error | undefined;\n #greet!: (serverId: string) => void;\n #refuse!: (error: Error) => void;\n #finish!: (reason: Error | undefined) => void;\n\n constructor(endpoint: PortEndpoint) {\n this.#endpoint = endpoint;\n this.hello = new Promise((greet, refuse) => {\n this.#greet = greet;\n this.#refuse = refuse;\n });\n this.ended = new Promise((finish) => {\n this.#finish = finish;\n });\n endpoint.addEventListener('message', ({ data }) => this.#receive(data as Frame));\n endpoint.addEventListener('messageerror', (event) =>\n this.#end(new Error(`agent port ${event.type}`))\n );\n endpoint.addEventListener('error', (event) => this.#end(new Error(`agent port ${event.type}`)));\n endpoint.addEventListener('close', () => this.#end('close'));\n endpoint.start?.();\n }\n\n readonly transport: ByteTransportFactory = (handlers) => {\n this.#handlers = handlers;\n for (const chunk of this.#queue.splice(0)) handlers.onData(chunk);\n if (this.#ended) this.#deliver(this.#ended);\n return {\n send: async (chunk) => {\n if (this.#ended) throw new Error('agent port is closed');\n post(this.#endpoint, chunk);\n },\n close: () => {\n if (this.#ended) return;\n this.#ended = 'close';\n this.#refuse(new Error('agent port closed before hello'));\n this.#finish(undefined);\n this.#endpoint.postMessage({ close: true } satisfies Frame);\n this.#endpoint.close?.();\n },\n };\n };\n\n #receive(frame: Frame): void {\n if (frame instanceof Uint8Array) {\n if (this.#handlers) this.#handlers.onData(frame);\n else this.#queue.push(frame);\n } else if ('hello' in frame) {\n this.#greet(frame.hello);\n } else {\n this.#end('close');\n }\n }\n\n #end(reason: 'close' | Error): void {\n if (this.#ended) return;\n this.#ended = reason;\n this.#refuse(reason === 'close' ? new Error('agent port closed before hello') : reason);\n this.#finish(reason === 'close' ? undefined : reason);\n this.#deliver(reason);\n }\n\n #deliver(reason: 'close' | Error): void {\n const handlers = this.#handlers;\n if (!handlers) return;\n this.#handlers = undefined;\n if (reason === 'close') handlers.onClose();\n else handlers.onError(reason);\n }\n}\n"],
5
- "mappings": "AAeO,MAAM,gBAAgB;AAE7B,MAAM,WAAW;AAOV,SAAS,QAAQ,OAAyB;AAC/C,QAAM,QAAQ,SAAS,KAAK,KAAK;AACjC,SAAO,QACH,EAAE,UAAU,OAAO,MAAM,CAAC,CAAC,GAAG,UAAU,MAAM,CAAC,EAAY,IAC3D,EAAE,UAAU,eAAe,UAAU,MAAM;AACjD;AAEO,SAAS,KAAK,UAAwB,OAAyB;AACpE,QAAM,OAAO,MAAM,MAAM;AACzB,WAAS,YAAY,MAAM,CAAC,KAAK,MAAM,CAAC;AAC1C;AAEA,SAAS,UAAU,IAAoB;AACrC,SAAO;AAAA,IACL,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,IACA,MAAM;AACJ,aAAO;AAAA,IACT;AAAA,IACA,CAAC,OAAO,WAAW,GAAG,MAAM;AAAA,EAC9B;AACF;AAEO,SAAS,gBACd,KACA,QAA2C,YACxC;AACH,QAAM,WAAW,MAAM;AACvB,QAAM,cAAc,IAAI,SAAwC;AAC9D,UAAM,KAAc,SAAS,GAAG,IAAI;AACpC,WAAO,OAAO,OAAO,WAAW,UAAU,EAAE,IAAI;AAAA,EAClD;AACA,MAAI;AACF,WAAO,IAAI;AAAA,EACb,UAAE;AACA,UAAM,aAAa;AAAA,EACrB;AACF;AAEO,MAAM,YAAY;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAuB,CAAC;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,UAAwB;AAClC,SAAK,YAAY;AACjB,SAAK,QAAQ,IAAI,QAAQ,CAAC,OAAO,WAAW;AAC1C,WAAK,SAAS;AACd,WAAK,UAAU;AAAA,IACjB,CAAC;AACD,SAAK,QAAQ,IAAI,QAAQ,CAAC,WAAW;AACnC,WAAK,UAAU;AAAA,IACjB,CAAC;AACD,aAAS,iBAAiB,WAAW,CAAC,EAAE,KAAK,MAAM,KAAK,SAAS,IAAa,CAAC;AAC/E,aAAS;AAAA,MAAiB;AAAA,MAAgB,CAAC,UACzC,KAAK,KAAK,IAAI,MAAM,cAAc,MAAM,IAAI,EAAE,CAAC;AAAA,IACjD;AACA,aAAS,iBAAiB,SAAS,CAAC,UAAU,KAAK,KAAK,IAAI,MAAM,cAAc,MAAM,IAAI,EAAE,CAAC,CAAC;AAC9F,aAAS,iBAAiB,SAAS,MAAM,KAAK,KAAK,OAAO,CAAC;AAC3D,aAAS,QAAQ;AAAA,EACnB;AAAA,EAES,YAAkC,CAAC,aAAa;AACvD,SAAK,YAAY;AACjB,eAAW,SAAS,KAAK,OAAO,OAAO,CAAC,EAAG,UAAS,OAAO,KAAK;AAChE,QAAI,KAAK,OAAQ,MAAK,SAAS,KAAK,MAAM;AAC1C,WAAO;AAAA,MACL,MAAM,OAAO,UAAU;AACrB,YAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,sBAAsB;AACvD,aAAK,KAAK,WAAW,KAAK;AAAA,MAC5B;AAAA,MACA,OAAO,MAAM;AACX,YAAI,KAAK,OAAQ;AACjB,aAAK,SAAS;AACd,aAAK,QAAQ,IAAI,MAAM,gCAAgC,CAAC;AACxD,aAAK,QAAQ,MAAS;AACtB,aAAK,UAAU,YAAY,EAAE,OAAO,KAAK,CAAiB;AAC1D,aAAK,UAAU,QAAQ;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,SAAS,OAAoB;AAC3B,QAAI,iBAAiB,YAAY;AAC/B,UAAI,KAAK,UAAW,MAAK,UAAU,OAAO,KAAK;AAAA,UAC1C,MAAK,OAAO,KAAK,KAAK;AAAA,IAC7B,WAAW,WAAW,OAAO;AAC3B,WAAK,OAAO,MAAM,KAAK;AAAA,IACzB,OAAO;AACL,WAAK,KAAK,OAAO;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,KAAK,QAA+B;AAClC,QAAI,KAAK,OAAQ;AACjB,SAAK,SAAS;AACd,SAAK,QAAQ,WAAW,UAAU,IAAI,MAAM,gCAAgC,IAAI,MAAM;AACtF,SAAK,QAAQ,WAAW,UAAU,SAAY,MAAM;AACpD,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA,EAEA,SAAS,QAA+B;AACtC,UAAM,WAAW,KAAK;AACtB,QAAI,CAAC,SAAU;AACf,SAAK,YAAY;AACjB,QAAI,WAAW,QAAS,UAAS,QAAQ;AAAA,QACpC,UAAS,QAAQ,MAAM;AAAA,EAC9B;AACF;",
4
+ "sourcesContent": ["import type { Frame as ChordFrame, Link } from '@earendil-works/chord';\n\nexport interface PortEndpoint {\n postMessage(message: unknown, transfer?: Transferable[]): void;\n addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;\n addEventListener(\n type: 'close' | 'messageerror' | 'error',\n listener: (event: Event) => void\n ): void;\n start?(): void;\n close?(): void;\n}\n\nexport type Frame = { hello: string } | { close: true } | Uint8Array;\n\nexport const LINK_PROTOCOL = 2;\n\nconst GREETING = /^slicc-agent-link\\/(\\d+) (.+)$/;\n\nexport interface Greeting {\n protocol: number;\n serverId: string;\n}\n\nexport const greeting = (serverId: string): string =>\n `slicc-agent-link/${LINK_PROTOCOL} ${serverId}`;\n\nexport function greeted(hello: string): Greeting {\n const found = GREETING.exec(hello);\n return found\n ? { protocol: Number(found[1]), serverId: found[2] as string }\n : { protocol: 1, serverId: hello };\n}\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\nfunction parse(chunk: Uint8Array): ChordFrame {\n const frame = JSON.parse(decoder.decode(chunk)) as { t?: unknown } | null;\n if (frame === null || typeof frame !== 'object' || typeof frame.t !== 'string')\n throw new TypeError('not a chord frame');\n return frame as ChordFrame;\n}\n\nexport class PortLink implements Link {\n readonly hello: Promise<string>;\n readonly ended: Promise<Error | undefined>;\n readonly #endpoint: PortEndpoint;\n readonly #queue: Uint8Array[] = [];\n readonly #closers = new Set<(reason: string) => void>();\n #handler: ((frame: ChordFrame) => void) | undefined;\n #closed = false;\n #greet!: (hello: string) => void;\n #refuse!: (error: Error) => void;\n #finish!: (reason: Error | undefined) => void;\n\n constructor(endpoint: PortEndpoint) {\n this.#endpoint = endpoint;\n this.hello = new Promise((greet, refuse) => {\n this.#greet = greet;\n this.#refuse = refuse;\n });\n this.hello.catch(() => undefined);\n this.ended = new Promise((finish) => {\n this.#finish = finish;\n });\n endpoint.addEventListener('message', ({ data }) => this.#receive(data as Frame));\n const failed = (event: Event) => this.#end(`agent port ${event.type}`, true);\n endpoint.addEventListener('messageerror', failed);\n endpoint.addEventListener('error', failed);\n endpoint.addEventListener('close', () => this.#end('peer closed', false));\n endpoint.start?.();\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n\n greet(serverId: string): void {\n this.#endpoint.postMessage({ hello: greeting(serverId) } satisfies Frame);\n }\n\n send(frame: ChordFrame): void {\n if (this.#closed) return;\n const bytes = encoder.encode(JSON.stringify(frame));\n this.#endpoint.postMessage(bytes, [bytes.buffer]);\n }\n\n receive(handler: (frame: ChordFrame) => void): void {\n this.#handler = handler;\n for (const chunk of this.#queue.splice(0)) this.#deliver(chunk);\n }\n\n onClose(handler: (reason: string) => void): void {\n if (this.#closed) handler('closed');\n else this.#closers.add(handler);\n }\n\n close(reason = 'closed'): void {\n if (this.#closed) return;\n this.send({ t: 'bye', reason });\n this.#endpoint.postMessage({ close: true } satisfies Frame);\n this.#end(reason, false);\n }\n\n #receive(frame: Frame): void {\n if (this.#closed) return;\n if (frame instanceof Uint8Array) {\n if (this.#handler) this.#deliver(frame);\n else this.#queue.push(frame);\n } else if ('hello' in frame) this.#greet(frame.hello);\n else this.#end('peer closed', false);\n }\n\n #deliver(chunk: Uint8Array): void {\n let frame: ChordFrame;\n try {\n frame = parse(chunk);\n } catch {\n this.close('protocol error');\n return;\n }\n if (frame.t === 'bye') this.#end(frame.reason ?? 'peer closed', false);\n else this.#handler?.(frame);\n }\n\n #end(reason: string, failed: boolean): void {\n if (this.#closed) return;\n this.#closed = true;\n this.#queue.length = 0;\n this.#endpoint.close?.();\n const error = new Error(reason);\n this.#refuse(new Error(`agent port closed before hello: ${reason}`));\n this.#finish(failed ? error : undefined);\n for (const handler of [...this.#closers]) handler(reason);\n this.#closers.clear();\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-agent",
3
- "version": "4.3.4",
3
+ "version": "5.0.0",
4
4
  "description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -63,8 +63,8 @@
63
63
  "devDependencies": {
64
64
  "@ai-ecoverse/slicc-kernel": "1.94.0",
65
65
  "@ai-ecoverse/slicc-scrub": "1.0.0",
66
- "@ai-ecoverse/slicc-shared-web": "1.18.1",
67
- "@ai-ecoverse/slicc-spectrum": "1.73.2",
66
+ "@ai-ecoverse/slicc-shared-web": "1.20.0",
67
+ "@ai-ecoverse/slicc-spectrum": "1.76.0",
68
68
  "@ai-ecoverse/wasm-bash": "5.3.0-18",
69
69
  "@ai-ecoverse/wasm-coreutils": "9.12.0-6",
70
70
  "@ai-ecoverse/wasm-git": "2.55.0-15",
@@ -76,24 +76,23 @@
76
76
  "monocart-coverage-reports": "2.13.2",
77
77
  "playwright-core": "1.64.0",
78
78
  "semantic-release": "25.0.9",
79
+ "slicc-agent-4": "npm:@ai-ecoverse/slicc-agent@4.3.2",
79
80
  "typescript": "7.0.2"
80
81
  },
81
82
  "dependencies": {
82
- "@ai-ecoverse/slicc-browsers": "1.7.0",
83
+ "@ai-ecoverse/slicc-browsers": "1.7.1",
83
84
  "@ai-ecoverse/slicc-vault": "1.9.1",
84
- "@earendil-works/chord": "1.0.4",
85
- "@earendil-works/pi-ai": "1.0.4",
86
- "@earendil-works/pi-client": "1.0.4",
87
- "@earendil-works/pi-codemode": "1.1.0",
88
- "@earendil-works/pi-durable": "1.0.4",
89
- "@earendil-works/pi-mcp": "1.1.0",
90
- "@earendil-works/pi-protocol": "1.0.4",
91
- "@earendil-works/pi-server": "1.0.4",
92
- "@sqlite.org/sqlite-wasm": "3.53.4-build2"
85
+ "@earendil-works/chord": "1.2.0",
86
+ "@earendil-works/pi-ai": "1.2.0",
87
+ "@earendil-works/pi-codemode": "1.2.0",
88
+ "@earendil-works/pi-durable": "1.2.0",
89
+ "@earendil-works/pi-mcp": "1.2.0",
90
+ "@sqlite.org/sqlite-wasm": "3.53.4-build2",
91
+ "typebox": "1.3.27"
93
92
  },
94
93
  "peerDependencies": {
95
94
  "@ai-ecoverse/slicc-kernel": ">=1.81.0 <2",
96
- "@ai-ecoverse/slicc-spectrum": "^1.59.0"
95
+ "@ai-ecoverse/slicc-spectrum": "^1.75.0"
97
96
  },
98
97
  "peerDependenciesMeta": {
99
98
  "@ai-ecoverse/slicc-spectrum": {
package/dist/listener.js DELETED
@@ -1,73 +0,0 @@
1
- import { applyPatches } from "./patches.js";
2
- import { post } from "./wire.js";
3
- class PortConnection {
4
- closed = false;
5
- #endpoint;
6
- #ended;
7
- constructor(endpoint, ended) {
8
- this.#endpoint = endpoint;
9
- this.#ended = ended;
10
- }
11
- async send(chunk) {
12
- if (this.closed) throw new Error("connection is closed");
13
- post(this.#endpoint, chunk);
14
- }
15
- close(finalChunk) {
16
- if (this.closed) return;
17
- if (finalChunk) post(this.#endpoint, finalChunk);
18
- this.closed = true;
19
- this.#endpoint.postMessage({ close: true });
20
- this.#endpoint.close?.();
21
- this.#ended();
22
- }
23
- end() {
24
- this.closed = true;
25
- this.#ended();
26
- }
27
- }
28
- class PortListener {
29
- #serverId;
30
- #connections = /* @__PURE__ */ new Set();
31
- #accept;
32
- constructor(serverId) {
33
- this.#serverId = serverId;
34
- }
35
- async start(accept) {
36
- applyPatches();
37
- this.#accept = accept;
38
- }
39
- async close() {
40
- for (const connection of [...this.#connections]) connection.close();
41
- this.#accept = void 0;
42
- }
43
- connect(endpoint) {
44
- const accept = this.#accept;
45
- if (!accept) throw new Error("agent host is not listening");
46
- const connection = new PortConnection(endpoint, () => this.#connections.delete(connection));
47
- this.#connections.add(connection);
48
- const handler = accept(connection);
49
- endpoint.addEventListener("message", ({ data }) => {
50
- if (data instanceof Uint8Array) handler.onData(data);
51
- else if (data?.close) {
52
- connection.end();
53
- handler.onClose();
54
- }
55
- });
56
- const failed = (event) => {
57
- connection.end();
58
- handler.onError(new Error(`agent port ${event.type}`));
59
- };
60
- endpoint.addEventListener("messageerror", failed);
61
- endpoint.addEventListener("close", () => {
62
- if (connection.closed) return;
63
- connection.end();
64
- handler.onClose();
65
- });
66
- endpoint.start?.();
67
- endpoint.postMessage({ hello: this.#serverId });
68
- }
69
- }
70
- export {
71
- PortListener
72
- };
73
- //# sourceMappingURL=listener.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/listener.ts"],
4
- "sourcesContent": ["import type { ServerListener } from '@earendil-works/pi-server';\nimport { applyPatches } from './patches.ts';\nimport { type Frame, type PortEndpoint, post } from './wire.ts';\n\ntype ByteConnectionAcceptor = Parameters<ServerListener['start']>[0];\ntype ByteConnection = Parameters<ByteConnectionAcceptor>[0];\ntype ByteConnectionHandler = ReturnType<ByteConnectionAcceptor>;\n\nclass PortConnection implements ByteConnection {\n closed = false;\n readonly #endpoint: PortEndpoint;\n readonly #ended: () => void;\n\n constructor(endpoint: PortEndpoint, ended: () => void) {\n this.#endpoint = endpoint;\n this.#ended = ended;\n }\n\n async send(chunk: Uint8Array): Promise<void> {\n if (this.closed) throw new Error('connection is closed');\n post(this.#endpoint, chunk);\n }\n\n close(finalChunk?: Uint8Array): void {\n if (this.closed) return;\n if (finalChunk) post(this.#endpoint, finalChunk);\n this.closed = true;\n this.#endpoint.postMessage({ close: true } satisfies Frame);\n this.#endpoint.close?.();\n this.#ended();\n }\n\n end(): void {\n this.closed = true;\n this.#ended();\n }\n}\n\nexport class PortListener implements ServerListener {\n readonly #serverId: string;\n readonly #connections = new Set<PortConnection>();\n #accept: ByteConnectionAcceptor | undefined;\n\n constructor(serverId: string) {\n this.#serverId = serverId;\n }\n\n async start(accept: ByteConnectionAcceptor): Promise<void> {\n applyPatches();\n this.#accept = accept;\n }\n\n async close(): Promise<void> {\n for (const connection of [...this.#connections]) connection.close();\n this.#accept = undefined;\n }\n\n connect(endpoint: PortEndpoint): void {\n const accept = this.#accept;\n if (!accept) throw new Error('agent host is not listening');\n const connection = new PortConnection(endpoint, () => this.#connections.delete(connection));\n this.#connections.add(connection);\n const handler: ByteConnectionHandler = accept(connection);\n endpoint.addEventListener('message', ({ data }) => {\n if (data instanceof Uint8Array) handler.onData(data);\n else if ((data as { close?: boolean } | null)?.close) {\n connection.end();\n handler.onClose();\n }\n });\n const failed = (event: Event) => {\n connection.end();\n handler.onError(new Error(`agent port ${event.type}`));\n };\n endpoint.addEventListener('messageerror', failed);\n endpoint.addEventListener('close', () => {\n if (connection.closed) return;\n connection.end();\n handler.onClose();\n });\n endpoint.start?.();\n endpoint.postMessage({ hello: this.#serverId } satisfies Frame);\n }\n}\n"],
5
- "mappings": "AACA,SAAS,oBAAoB;AAC7B,SAAwC,YAAY;AAMpD,MAAM,eAAyC;AAAA,EAC7C,SAAS;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,UAAwB,OAAmB;AACrD,SAAK,YAAY;AACjB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,KAAK,OAAkC;AAC3C,QAAI,KAAK,OAAQ,OAAM,IAAI,MAAM,sBAAsB;AACvD,SAAK,KAAK,WAAW,KAAK;AAAA,EAC5B;AAAA,EAEA,MAAM,YAA+B;AACnC,QAAI,KAAK,OAAQ;AACjB,QAAI,WAAY,MAAK,KAAK,WAAW,UAAU;AAC/C,SAAK,SAAS;AACd,SAAK,UAAU,YAAY,EAAE,OAAO,KAAK,CAAiB;AAC1D,SAAK,UAAU,QAAQ;AACvB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAY;AACV,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAEO,MAAM,aAAuC;AAAA,EACzC;AAAA,EACA,eAAe,oBAAI,IAAoB;AAAA,EAChD;AAAA,EAEA,YAAY,UAAkB;AAC5B,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,MAAM,QAA+C;AACzD,iBAAa;AACb,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,QAAuB;AAC3B,eAAW,cAAc,CAAC,GAAG,KAAK,YAAY,EAAG,YAAW,MAAM;AAClE,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,QAAQ,UAA8B;AACpC,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,6BAA6B;AAC1D,UAAM,aAAa,IAAI,eAAe,UAAU,MAAM,KAAK,aAAa,OAAO,UAAU,CAAC;AAC1F,SAAK,aAAa,IAAI,UAAU;AAChC,UAAM,UAAiC,OAAO,UAAU;AACxD,aAAS,iBAAiB,WAAW,CAAC,EAAE,KAAK,MAAM;AACjD,UAAI,gBAAgB,WAAY,SAAQ,OAAO,IAAI;AAAA,eACzC,MAAqC,OAAO;AACpD,mBAAW,IAAI;AACf,gBAAQ,QAAQ;AAAA,MAClB;AAAA,IACF,CAAC;AACD,UAAM,SAAS,CAAC,UAAiB;AAC/B,iBAAW,IAAI;AACf,cAAQ,QAAQ,IAAI,MAAM,cAAc,MAAM,IAAI,EAAE,CAAC;AAAA,IACvD;AACA,aAAS,iBAAiB,gBAAgB,MAAM;AAChD,aAAS,iBAAiB,SAAS,MAAM;AACvC,UAAI,WAAW,OAAQ;AACvB,iBAAW,IAAI;AACf,cAAQ,QAAQ;AAAA,IAClB,CAAC;AACD,aAAS,QAAQ;AACjB,aAAS,YAAY,EAAE,OAAO,KAAK,UAAU,CAAiB;AAAA,EAChE;AACF;",
6
- "names": []
7
- }
@@ -1,11 +0,0 @@
1
- import type { ServerListener } from '@earendil-works/pi-server';
2
- import { type PortEndpoint } from './wire.ts';
3
- type ByteConnectionAcceptor = Parameters<ServerListener['start']>[0];
4
- export declare class PortListener implements ServerListener {
5
- #private;
6
- constructor(serverId: string);
7
- start(accept: ByteConnectionAcceptor): Promise<void>;
8
- close(): Promise<void>;
9
- connect(endpoint: PortEndpoint): void;
10
- }
11
- export {};