@llui/agent 0.0.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +210 -0
- package/dist/client/agentConfirm.d.ts +60 -0
- package/dist/client/agentConfirm.d.ts.map +1 -0
- package/dist/client/agentConfirm.js +66 -0
- package/dist/client/agentConfirm.js.map +1 -0
- package/dist/client/agentConnect.d.ts +125 -0
- package/dist/client/agentConnect.d.ts.map +1 -0
- package/dist/client/agentConnect.js +114 -0
- package/dist/client/agentConnect.js.map +1 -0
- package/dist/client/agentLog.d.ts +51 -0
- package/dist/client/agentLog.d.ts.map +1 -0
- package/dist/client/agentLog.js +53 -0
- package/dist/client/agentLog.js.map +1 -0
- package/dist/client/effect-handler.d.ts +15 -0
- package/dist/client/effect-handler.d.ts.map +1 -0
- package/dist/client/effect-handler.js +146 -0
- package/dist/client/effect-handler.js.map +1 -0
- package/dist/client/effects.d.ts +27 -0
- package/dist/client/effects.d.ts.map +1 -0
- package/dist/client/effects.js +2 -0
- package/dist/client/effects.js.map +1 -0
- package/dist/client/factory.d.ts +47 -0
- package/dist/client/factory.d.ts.map +1 -0
- package/dist/client/factory.js +105 -0
- package/dist/client/factory.js.map +1 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/rpc/describe-context.d.ts +10 -0
- package/dist/client/rpc/describe-context.d.ts.map +1 -0
- package/dist/client/rpc/describe-context.js +8 -0
- package/dist/client/rpc/describe-context.js.map +1 -0
- package/dist/client/rpc/describe-visible-content.d.ts +22 -0
- package/dist/client/rpc/describe-visible-content.d.ts.map +1 -0
- package/dist/client/rpc/describe-visible-content.js +66 -0
- package/dist/client/rpc/describe-visible-content.js.map +1 -0
- package/dist/client/rpc/get-state.d.ts +15 -0
- package/dist/client/rpc/get-state.d.ts.map +1 -0
- package/dist/client/rpc/get-state.js +37 -0
- package/dist/client/rpc/get-state.js.map +1 -0
- package/dist/client/rpc/list-actions.d.ts +27 -0
- package/dist/client/rpc/list-actions.d.ts.map +1 -0
- package/dist/client/rpc/list-actions.js +38 -0
- package/dist/client/rpc/list-actions.js.map +1 -0
- package/dist/client/rpc/query-dom.d.ts +20 -0
- package/dist/client/rpc/query-dom.d.ts.map +1 -0
- package/dist/client/rpc/query-dom.js +37 -0
- package/dist/client/rpc/query-dom.js.map +1 -0
- package/dist/client/rpc/send-message.d.ts +28 -0
- package/dist/client/rpc/send-message.d.ts.map +1 -0
- package/dist/client/rpc/send-message.js +40 -0
- package/dist/client/rpc/send-message.js.map +1 -0
- package/dist/client/uuid.d.ts +2 -0
- package/dist/client/uuid.d.ts.map +1 -0
- package/dist/client/uuid.js +24 -0
- package/dist/client/uuid.js.map +1 -0
- package/dist/client/ws-client.d.ts +44 -0
- package/dist/client/ws-client.d.ts.map +1 -0
- package/dist/client/ws-client.js +176 -0
- package/dist/client/ws-client.js.map +1 -0
- package/dist/protocol.d.ts +319 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +6 -0
- package/dist/protocol.js.map +1 -0
- package/dist/server/audit.d.ts +6 -0
- package/dist/server/audit.d.ts.map +1 -0
- package/dist/server/audit.js +6 -0
- package/dist/server/audit.js.map +1 -0
- package/dist/server/factory.d.ts +10 -0
- package/dist/server/factory.d.ts.map +1 -0
- package/dist/server/factory.js +69 -0
- package/dist/server/factory.js.map +1 -0
- package/dist/server/http/mint.d.ts +23 -0
- package/dist/server/http/mint.d.ts.map +1 -0
- package/dist/server/http/mint.js +63 -0
- package/dist/server/http/mint.js.map +1 -0
- package/dist/server/http/resume.d.ts +14 -0
- package/dist/server/http/resume.d.ts.map +1 -0
- package/dist/server/http/resume.js +89 -0
- package/dist/server/http/resume.js.map +1 -0
- package/dist/server/http/revoke.d.ts +11 -0
- package/dist/server/http/revoke.d.ts.map +1 -0
- package/dist/server/http/revoke.js +24 -0
- package/dist/server/http/revoke.js.map +1 -0
- package/dist/server/http/router.d.ts +13 -0
- package/dist/server/http/router.d.ts.map +1 -0
- package/dist/server/http/router.js +28 -0
- package/dist/server/http/router.js.map +1 -0
- package/dist/server/http/sessions.d.ts +8 -0
- package/dist/server/http/sessions.d.ts.map +1 -0
- package/dist/server/http/sessions.js +27 -0
- package/dist/server/http/sessions.js.map +1 -0
- package/dist/server/identity.d.ts +8 -0
- package/dist/server/identity.d.ts.map +1 -0
- package/dist/server/identity.js +41 -0
- package/dist/server/identity.js.map +1 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lap/confirm-result.d.ts +14 -0
- package/dist/server/lap/confirm-result.d.ts.map +1 -0
- package/dist/server/lap/confirm-result.js +60 -0
- package/dist/server/lap/confirm-result.js.map +1 -0
- package/dist/server/lap/describe.d.ts +22 -0
- package/dist/server/lap/describe.d.ts.map +1 -0
- package/dist/server/lap/describe.js +67 -0
- package/dist/server/lap/describe.js.map +1 -0
- package/dist/server/lap/forward.d.ts +24 -0
- package/dist/server/lap/forward.d.ts.map +1 -0
- package/dist/server/lap/forward.js +68 -0
- package/dist/server/lap/forward.js.map +1 -0
- package/dist/server/lap/message.d.ts +14 -0
- package/dist/server/lap/message.d.ts.map +1 -0
- package/dist/server/lap/message.js +97 -0
- package/dist/server/lap/message.js.map +1 -0
- package/dist/server/lap/router.d.ts +4 -0
- package/dist/server/lap/router.d.ts.map +1 -0
- package/dist/server/lap/router.js +37 -0
- package/dist/server/lap/router.js.map +1 -0
- package/dist/server/lap/wait.d.ts +14 -0
- package/dist/server/lap/wait.d.ts.map +1 -0
- package/dist/server/lap/wait.js +35 -0
- package/dist/server/lap/wait.js.map +1 -0
- package/dist/server/options.d.ts +41 -0
- package/dist/server/options.d.ts.map +1 -0
- package/dist/server/options.js +2 -0
- package/dist/server/options.js.map +1 -0
- package/dist/server/rate-limit.d.ts +14 -0
- package/dist/server/rate-limit.d.ts.map +1 -0
- package/dist/server/rate-limit.js +43 -0
- package/dist/server/rate-limit.js.map +1 -0
- package/dist/server/token-store.d.ts +27 -0
- package/dist/server/token-store.d.ts.map +1 -0
- package/dist/server/token-store.js +55 -0
- package/dist/server/token-store.js.map +1 -0
- package/dist/server/token.d.ts +24 -0
- package/dist/server/token.d.ts.map +1 -0
- package/dist/server/token.js +77 -0
- package/dist/server/token.js.map +1 -0
- package/dist/server/ws/pairing-registry.d.ts +53 -0
- package/dist/server/ws/pairing-registry.d.ts.map +1 -0
- package/dist/server/ws/pairing-registry.js +205 -0
- package/dist/server/ws/pairing-registry.js.map +1 -0
- package/dist/server/ws/upgrade.d.ts +23 -0
- package/dist/server/ws/upgrade.d.ts.map +1 -0
- package/dist/server/ws/upgrade.js +81 -0
- package/dist/server/ws/upgrade.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AgentEffect } from './effects.js';
|
|
2
|
+
import type { LogEntry, LogKind } from '../protocol.js';
|
|
3
|
+
export type AgentLogFilter = {
|
|
4
|
+
kinds?: LogKind[];
|
|
5
|
+
since?: number;
|
|
6
|
+
};
|
|
7
|
+
export type AgentLogState = {
|
|
8
|
+
entries: LogEntry[];
|
|
9
|
+
filter: AgentLogFilter;
|
|
10
|
+
};
|
|
11
|
+
export type AgentLogInitOpts = {
|
|
12
|
+
maxEntries?: number;
|
|
13
|
+
};
|
|
14
|
+
export type AgentLogMsg = {
|
|
15
|
+
type: 'Append';
|
|
16
|
+
entry: LogEntry;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'Clear';
|
|
19
|
+
} | {
|
|
20
|
+
type: 'SetFilter';
|
|
21
|
+
filter: AgentLogFilter;
|
|
22
|
+
};
|
|
23
|
+
export declare function init(_opts?: AgentLogInitOpts): [AgentLogState, AgentEffect[]];
|
|
24
|
+
export declare function update(state: AgentLogState, msg: AgentLogMsg, opts?: AgentLogInitOpts): [AgentLogState, AgentEffect[]];
|
|
25
|
+
import { type Send } from '@llui/dom';
|
|
26
|
+
type ConnectBag = {
|
|
27
|
+
root: {
|
|
28
|
+
'data-scope': string;
|
|
29
|
+
};
|
|
30
|
+
list: {
|
|
31
|
+
'data-part': string;
|
|
32
|
+
'data-count': number;
|
|
33
|
+
};
|
|
34
|
+
entryItem: (id: string) => {
|
|
35
|
+
'data-part': string;
|
|
36
|
+
'data-id': string;
|
|
37
|
+
'data-kind': string;
|
|
38
|
+
} | null;
|
|
39
|
+
filterControls: {
|
|
40
|
+
clearButton: {
|
|
41
|
+
onClick: () => void;
|
|
42
|
+
disabled: boolean;
|
|
43
|
+
};
|
|
44
|
+
setFilter: (filter: AgentLogFilter) => void;
|
|
45
|
+
};
|
|
46
|
+
/** Filtered view of entries — respects state.filter. */
|
|
47
|
+
visibleEntries: LogEntry[];
|
|
48
|
+
};
|
|
49
|
+
export declare function connect<S>(get: (s: S) => AgentLogState, send: Send<AgentLogMsg>): (state: S) => ConnectBag;
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=agentLog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentLog.d.ts","sourceRoot":"","sources":["../../src/client/agentLog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAEvD,MAAM,MAAM,cAAc,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAElE,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,QAAQ,EAAE,CAAA;IACnB,MAAM,EAAE,cAAc,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtD,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,CAAA;AAIjD,wBAAgB,IAAI,CAAC,KAAK,GAAE,gBAAqB,GAAG,CAAC,aAAa,EAAE,WAAW,EAAE,CAAC,CAEjF;AAED,wBAAgB,MAAM,CACpB,KAAK,EAAE,aAAa,EACpB,GAAG,EAAE,WAAW,EAChB,IAAI,GAAE,gBAAqB,GAC1B,CAAC,aAAa,EAAE,WAAW,EAAE,CAAC,CAchC;AAGD,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9B,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAA;IACnD,SAAS,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACjG,cAAc,EAAE;QACd,WAAW,EAAE;YAAE,OAAO,EAAE,MAAM,IAAI,CAAC;YAAC,QAAQ,EAAE,OAAO,CAAA;SAAE,CAAA;QACvD,SAAS,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAA;KAC5C,CAAA;IACD,wDAAwD;IACxD,cAAc,EAAE,QAAQ,EAAE,CAAA;CAC3B,CAAA;AAED,wBAAgB,OAAO,CAAC,CAAC,EACvB,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,aAAa,EAC5B,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,GACtB,CAAC,KAAK,EAAE,CAAC,KAAK,UAAU,CA0B1B"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const DEFAULT_MAX = 100;
|
|
2
|
+
export function init(_opts = {}) {
|
|
3
|
+
return [{ entries: [], filter: {} }, []];
|
|
4
|
+
}
|
|
5
|
+
export function update(state, msg, opts = {}) {
|
|
6
|
+
const max = opts.maxEntries ?? DEFAULT_MAX;
|
|
7
|
+
switch (msg.type) {
|
|
8
|
+
case 'Append': {
|
|
9
|
+
const next = [...state.entries, msg.entry];
|
|
10
|
+
// Ring-buffer cap
|
|
11
|
+
if (next.length > max)
|
|
12
|
+
next.splice(0, next.length - max);
|
|
13
|
+
return [{ ...state, entries: next }, []];
|
|
14
|
+
}
|
|
15
|
+
case 'Clear':
|
|
16
|
+
return [{ ...state, entries: [] }, []];
|
|
17
|
+
case 'SetFilter':
|
|
18
|
+
return [{ ...state, filter: msg.filter }, []];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Connect bag:
|
|
22
|
+
import {} from '@llui/dom';
|
|
23
|
+
export function connect(get, send) {
|
|
24
|
+
return (state) => {
|
|
25
|
+
const s = get(state);
|
|
26
|
+
const visible = s.entries.filter((e) => {
|
|
27
|
+
if (s.filter.kinds && !s.filter.kinds.includes(e.kind))
|
|
28
|
+
return false;
|
|
29
|
+
if (s.filter.since !== undefined && e.at < s.filter.since)
|
|
30
|
+
return false;
|
|
31
|
+
return true;
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
root: { 'data-scope': 'agent-log' },
|
|
35
|
+
list: { 'data-part': 'list', 'data-count': visible.length },
|
|
36
|
+
entryItem: (id) => {
|
|
37
|
+
const e = visible.find((x) => x.id === id);
|
|
38
|
+
if (!e)
|
|
39
|
+
return null;
|
|
40
|
+
return { 'data-part': 'entry', 'data-id': e.id, 'data-kind': e.kind };
|
|
41
|
+
},
|
|
42
|
+
filterControls: {
|
|
43
|
+
clearButton: {
|
|
44
|
+
onClick: () => send({ type: 'Clear' }),
|
|
45
|
+
disabled: s.entries.length === 0,
|
|
46
|
+
},
|
|
47
|
+
setFilter: (filter) => send({ type: 'SetFilter', filter }),
|
|
48
|
+
},
|
|
49
|
+
visibleEntries: visible,
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=agentLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentLog.js","sourceRoot":"","sources":["../../src/client/agentLog.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentEffect } from './effects.js'\nimport type { LogEntry, LogKind } from '../protocol.js'\n\nexport type AgentLogFilter = { kinds?: LogKind[]; since?: number }\n\nexport type AgentLogState = {\n entries: LogEntry[]\n filter: AgentLogFilter\n}\n\nexport type AgentLogInitOpts = { maxEntries?: number } // default 100\n\nexport type AgentLogMsg =\n | { type: 'Append'; entry: LogEntry }\n | { type: 'Clear' }\n | { type: 'SetFilter'; filter: AgentLogFilter }\n\nconst DEFAULT_MAX = 100\n\nexport function init(_opts: AgentLogInitOpts = {}): [AgentLogState, AgentEffect[]] {\n return [{ entries: [], filter: {} }, []]\n}\n\nexport function update(\n state: AgentLogState,\n msg: AgentLogMsg,\n opts: AgentLogInitOpts = {},\n): [AgentLogState, AgentEffect[]] {\n const max = opts.maxEntries ?? DEFAULT_MAX\n switch (msg.type) {\n case 'Append': {\n const next = [...state.entries, msg.entry]\n // Ring-buffer cap\n if (next.length > max) next.splice(0, next.length - max)\n return [{ ...state, entries: next }, []]\n }\n case 'Clear':\n return [{ ...state, entries: [] }, []]\n case 'SetFilter':\n return [{ ...state, filter: msg.filter }, []]\n }\n}\n\n// Connect bag:\nimport { type Send } from '@llui/dom'\n\ntype ConnectBag = {\n root: { 'data-scope': string }\n list: { 'data-part': string; 'data-count': number }\n entryItem: (id: string) => { 'data-part': string; 'data-id': string; 'data-kind': string } | null\n filterControls: {\n clearButton: { onClick: () => void; disabled: boolean }\n setFilter: (filter: AgentLogFilter) => void\n }\n /** Filtered view of entries — respects state.filter. */\n visibleEntries: LogEntry[]\n}\n\nexport function connect<S>(\n get: (s: S) => AgentLogState,\n send: Send<AgentLogMsg>,\n): (state: S) => ConnectBag {\n return (state) => {\n const s = get(state)\n const visible = s.entries.filter((e) => {\n if (s.filter.kinds && !s.filter.kinds.includes(e.kind)) return false\n if (s.filter.since !== undefined && e.at < s.filter.since) return false\n return true\n })\n return {\n root: { 'data-scope': 'agent-log' },\n list: { 'data-part': 'list', 'data-count': visible.length },\n entryItem: (id) => {\n const e = visible.find((x) => x.id === id)\n if (!e) return null\n return { 'data-part': 'entry', 'data-id': e.id, 'data-kind': e.kind }\n },\n filterControls: {\n clearButton: {\n onClick: () => send({ type: 'Clear' }),\n disabled: s.entries.length === 0,\n },\n setFilter: (filter) => send({ type: 'SetFilter', filter }),\n },\n visibleEntries: visible,\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AgentEffect } from './effects.js';
|
|
2
|
+
export type EffectHandlerHost = {
|
|
3
|
+
send(msg: unknown): void;
|
|
4
|
+
/** Wraps an agentConnect msg into an app-Msg. */
|
|
5
|
+
wrapAgentConnect(m: unknown): unknown;
|
|
6
|
+
/** Called for AgentForwardMsg — the payload is re-dispatched via send. */
|
|
7
|
+
forward(payload: unknown): void;
|
|
8
|
+
/** fetch for HTTP effects; override in tests. */
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
/** Called before opening WS / on WS lifecycle events. */
|
|
11
|
+
openWs(token: string, wsUrl: string): void;
|
|
12
|
+
closeWs(): void;
|
|
13
|
+
};
|
|
14
|
+
export declare function createEffectHandler(host: EffectHandlerHost): (effect: AgentEffect) => Promise<void>;
|
|
15
|
+
//# sourceMappingURL=effect-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-handler.d.ts","sourceRoot":"","sources":["../../src/client/effect-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAQ/C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;IACxB,iDAAiD;IACjD,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;IACrC,0EAA0E;IAC1E,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IAC/B,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,yDAAyD;IACzD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1C,OAAO,IAAI,IAAI,CAAA;CAChB,CAAA;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,iBAAiB,IAG5B,QAAQ,WAAW,KAAG,OAAO,CAAC,IAAI,CAAC,CAwHjE"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
export function createEffectHandler(host) {
|
|
2
|
+
const doFetch = host.fetch ?? fetch.bind(globalThis);
|
|
3
|
+
return async function handle(effect) {
|
|
4
|
+
switch (effect.type) {
|
|
5
|
+
case 'AgentMintRequest': {
|
|
6
|
+
try {
|
|
7
|
+
const res = await doFetch(effect.mintUrl, { method: 'POST', credentials: 'include' });
|
|
8
|
+
if (!res.ok) {
|
|
9
|
+
const detail = await safeText(res);
|
|
10
|
+
host.send(host.wrapAgentConnect({
|
|
11
|
+
type: 'MintFailed',
|
|
12
|
+
error: { code: `http-${res.status}`, detail },
|
|
13
|
+
}));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const body = (await res.json());
|
|
17
|
+
host.send(host.wrapAgentConnect({
|
|
18
|
+
type: 'MintSucceeded',
|
|
19
|
+
token: body.token,
|
|
20
|
+
tid: body.tid,
|
|
21
|
+
lapUrl: body.lapUrl,
|
|
22
|
+
wsUrl: body.wsUrl,
|
|
23
|
+
expiresAt: body.expiresAt,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
host.send(host.wrapAgentConnect({
|
|
28
|
+
type: 'MintFailed',
|
|
29
|
+
error: { code: 'network', detail: String(e) },
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
case 'AgentOpenWS': {
|
|
35
|
+
host.openWs(effect.token, effect.wsUrl);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
case 'AgentCloseWS': {
|
|
39
|
+
host.closeWs();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
case 'AgentResumeCheck': {
|
|
43
|
+
// For v1 we call /agent/resume/list via the mint URL's origin; the mintUrl is a POST
|
|
44
|
+
// endpoint at `/agent/mint`, so we derive the origin and hit `/agent/resume/list`.
|
|
45
|
+
const origin = deriveOrigin(host);
|
|
46
|
+
if (!origin)
|
|
47
|
+
return;
|
|
48
|
+
try {
|
|
49
|
+
const res = await doFetch(`${origin}/agent/resume/list`, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
credentials: 'include',
|
|
52
|
+
headers: { 'content-type': 'application/json' },
|
|
53
|
+
body: JSON.stringify({ tids: effect.tids }),
|
|
54
|
+
});
|
|
55
|
+
if (!res.ok)
|
|
56
|
+
return;
|
|
57
|
+
const body = (await res.json());
|
|
58
|
+
host.send(host.wrapAgentConnect({ type: 'ResumeListLoaded', sessions: body.sessions }));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
/* quiet failure; user can retry */
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
case 'AgentResumeClaim': {
|
|
66
|
+
const origin = deriveOrigin(host);
|
|
67
|
+
if (!origin)
|
|
68
|
+
return;
|
|
69
|
+
try {
|
|
70
|
+
const res = await doFetch(`${origin}/agent/resume/claim`, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
credentials: 'include',
|
|
73
|
+
headers: { 'content-type': 'application/json' },
|
|
74
|
+
body: JSON.stringify({ tid: effect.tid }),
|
|
75
|
+
});
|
|
76
|
+
if (!res.ok)
|
|
77
|
+
return;
|
|
78
|
+
const body = (await res.json());
|
|
79
|
+
host.openWs(body.token, body.wsUrl);
|
|
80
|
+
host.send(host.wrapAgentConnect({ type: 'WsOpened' }));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
/* quiet */
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
case 'AgentRevoke': {
|
|
88
|
+
const origin = deriveOrigin(host);
|
|
89
|
+
if (!origin)
|
|
90
|
+
return;
|
|
91
|
+
try {
|
|
92
|
+
await doFetch(`${origin}/agent/revoke`, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
credentials: 'include',
|
|
95
|
+
headers: { 'content-type': 'application/json' },
|
|
96
|
+
body: JSON.stringify({ tid: effect.tid }),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
/* quiet */
|
|
101
|
+
}
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
case 'AgentSessionsList': {
|
|
105
|
+
const origin = deriveOrigin(host);
|
|
106
|
+
if (!origin)
|
|
107
|
+
return;
|
|
108
|
+
try {
|
|
109
|
+
const res = await doFetch(`${origin}/agent/sessions`, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
credentials: 'include',
|
|
112
|
+
});
|
|
113
|
+
if (!res.ok)
|
|
114
|
+
return;
|
|
115
|
+
const body = (await res.json());
|
|
116
|
+
host.send(host.wrapAgentConnect({ type: 'SessionsLoaded', sessions: body.sessions }));
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
/* quiet */
|
|
120
|
+
}
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
case 'AgentForwardMsg': {
|
|
124
|
+
host.forward(effect.payload);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function safeText(res) {
|
|
131
|
+
try {
|
|
132
|
+
return await res.text();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return '';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function deriveOrigin(_host) {
|
|
139
|
+
// When running in the browser, `location.origin` is correct (the agent endpoints
|
|
140
|
+
// are same-origin with the app per spec §6.2). When not in a browser (tests),
|
|
141
|
+
// the test-side host can override by monkeypatching in its own effect handler.
|
|
142
|
+
if (typeof location !== 'undefined')
|
|
143
|
+
return location.origin;
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=effect-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effect-handler.js","sourceRoot":"","sources":["../../src/client/effect-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentEffect } from './effects.js'\nimport type {\n MintResponse,\n ResumeListResponse,\n ResumeClaimResponse,\n SessionsResponse,\n} from '../protocol.js'\n\nexport type EffectHandlerHost = {\n send(msg: unknown): void // root app send; wraps agent sub-msgs into the app Msg envelope\n /** Wraps an agentConnect msg into an app-Msg. */\n wrapAgentConnect(m: unknown): unknown\n /** Called for AgentForwardMsg — the payload is re-dispatched via send. */\n forward(payload: unknown): void\n /** fetch for HTTP effects; override in tests. */\n fetch?: typeof fetch\n /** Called before opening WS / on WS lifecycle events. */\n openWs(token: string, wsUrl: string): void\n closeWs(): void\n}\n\nexport function createEffectHandler(host: EffectHandlerHost) {\n const doFetch = host.fetch ?? fetch.bind(globalThis)\n\n return async function handle(effect: AgentEffect): Promise<void> {\n switch (effect.type) {\n case 'AgentMintRequest': {\n try {\n const res = await doFetch(effect.mintUrl, { method: 'POST', credentials: 'include' })\n if (!res.ok) {\n const detail = await safeText(res)\n host.send(\n host.wrapAgentConnect({\n type: 'MintFailed',\n error: { code: `http-${res.status}`, detail },\n }),\n )\n return\n }\n const body = (await res.json()) as MintResponse\n host.send(\n host.wrapAgentConnect({\n type: 'MintSucceeded',\n token: body.token,\n tid: body.tid,\n lapUrl: body.lapUrl,\n wsUrl: body.wsUrl,\n expiresAt: body.expiresAt,\n }),\n )\n } catch (e) {\n host.send(\n host.wrapAgentConnect({\n type: 'MintFailed',\n error: { code: 'network', detail: String(e) },\n }),\n )\n }\n return\n }\n case 'AgentOpenWS': {\n host.openWs(effect.token, effect.wsUrl)\n return\n }\n case 'AgentCloseWS': {\n host.closeWs()\n return\n }\n case 'AgentResumeCheck': {\n // For v1 we call /agent/resume/list via the mint URL's origin; the mintUrl is a POST\n // endpoint at `/agent/mint`, so we derive the origin and hit `/agent/resume/list`.\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n const res = await doFetch(`${origin}/agent/resume/list`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tids: effect.tids }),\n })\n if (!res.ok) return\n const body = (await res.json()) as ResumeListResponse\n host.send(host.wrapAgentConnect({ type: 'ResumeListLoaded', sessions: body.sessions }))\n } catch {\n /* quiet failure; user can retry */\n }\n return\n }\n case 'AgentResumeClaim': {\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n const res = await doFetch(`${origin}/agent/resume/claim`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tid: effect.tid }),\n })\n if (!res.ok) return\n const body = (await res.json()) as ResumeClaimResponse\n host.openWs(body.token, body.wsUrl)\n host.send(host.wrapAgentConnect({ type: 'WsOpened' }))\n } catch {\n /* quiet */\n }\n return\n }\n case 'AgentRevoke': {\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n await doFetch(`${origin}/agent/revoke`, {\n method: 'POST',\n credentials: 'include',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tid: effect.tid }),\n })\n } catch {\n /* quiet */\n }\n return\n }\n case 'AgentSessionsList': {\n const origin = deriveOrigin(host)\n if (!origin) return\n try {\n const res = await doFetch(`${origin}/agent/sessions`, {\n method: 'GET',\n credentials: 'include',\n })\n if (!res.ok) return\n const body = (await res.json()) as SessionsResponse\n host.send(host.wrapAgentConnect({ type: 'SessionsLoaded', sessions: body.sessions }))\n } catch {\n /* quiet */\n }\n return\n }\n case 'AgentForwardMsg': {\n host.forward(effect.payload)\n return\n }\n }\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return ''\n }\n}\n\nfunction deriveOrigin(_host: EffectHandlerHost): string | null {\n // When running in the browser, `location.origin` is correct (the agent endpoints\n // are same-origin with the app per spec §6.2). When not in a browser (tests),\n // the test-side host can override by monkeypatching in its own effect handler.\n if (typeof location !== 'undefined') return location.origin\n return null\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AgentToken } from '../protocol.js';
|
|
2
|
+
export type AgentEffect = {
|
|
3
|
+
type: 'AgentMintRequest';
|
|
4
|
+
mintUrl: string;
|
|
5
|
+
} | {
|
|
6
|
+
type: 'AgentOpenWS';
|
|
7
|
+
token: AgentToken;
|
|
8
|
+
wsUrl: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'AgentCloseWS';
|
|
11
|
+
} | {
|
|
12
|
+
type: 'AgentResumeCheck';
|
|
13
|
+
tids: string[];
|
|
14
|
+
} | {
|
|
15
|
+
type: 'AgentResumeClaim';
|
|
16
|
+
tid: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'AgentRevoke';
|
|
19
|
+
tid: string;
|
|
20
|
+
} | {
|
|
21
|
+
type: 'AgentSessionsList';
|
|
22
|
+
} | {
|
|
23
|
+
type: 'AgentForwardMsg';
|
|
24
|
+
payload: unknown;
|
|
25
|
+
};
|
|
26
|
+
export type AgentEffectHandler = (effect: AgentEffect) => Promise<void>;
|
|
27
|
+
//# sourceMappingURL=effects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../../src/client/effects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEhD,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAA;AAGjD,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.js","sourceRoot":"","sources":["../../src/client/effects.ts"],"names":[],"mappings":"","sourcesContent":["import type { AgentToken } from '../protocol.js'\n\nexport type AgentEffect =\n | { type: 'AgentMintRequest'; mintUrl: string }\n | { type: 'AgentOpenWS'; token: AgentToken; wsUrl: string }\n | { type: 'AgentCloseWS' }\n | { type: 'AgentResumeCheck'; tids: string[] }\n | { type: 'AgentResumeClaim'; tid: string }\n | { type: 'AgentRevoke'; tid: string }\n | { type: 'AgentSessionsList' }\n | { type: 'AgentForwardMsg'; payload: unknown }\n\n// Handler implementation lands in Plan 7 alongside the WS client.\nexport type AgentEffectHandler = (effect: AgentEffect) => Promise<void>\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AppHandle } from '@llui/dom';
|
|
2
|
+
import type { AgentEffect } from './effects.js';
|
|
3
|
+
import type { AgentConfirmState } from './agentConfirm.js';
|
|
4
|
+
import type { AgentDocs, AgentContext, MessageAnnotations } from '../protocol.js';
|
|
5
|
+
type ComponentMetadata = {
|
|
6
|
+
__msgSchema?: unknown;
|
|
7
|
+
__stateSchema?: unknown;
|
|
8
|
+
__msgAnnotations?: Record<string, MessageAnnotations>;
|
|
9
|
+
__bindingDescriptors?: Array<{
|
|
10
|
+
variant: string;
|
|
11
|
+
}>;
|
|
12
|
+
__schemaHash?: string;
|
|
13
|
+
name: string;
|
|
14
|
+
agentAffordances?: (state: unknown) => Array<{
|
|
15
|
+
type: string;
|
|
16
|
+
[k: string]: unknown;
|
|
17
|
+
}>;
|
|
18
|
+
agentDocs?: AgentDocs;
|
|
19
|
+
agentContext?: (state: unknown) => AgentContext;
|
|
20
|
+
};
|
|
21
|
+
export type CreateAgentClientOpts<State, Msg> = {
|
|
22
|
+
handle: AppHandle;
|
|
23
|
+
def: ComponentMetadata;
|
|
24
|
+
appVersion?: string;
|
|
25
|
+
rootElement: Element | null;
|
|
26
|
+
slices: {
|
|
27
|
+
getConnect: (s: State) => unknown;
|
|
28
|
+
getConfirm: (s: State) => AgentConfirmState;
|
|
29
|
+
wrapConnectMsg: (m: unknown) => Msg;
|
|
30
|
+
wrapConfirmMsg: (m: unknown) => Msg;
|
|
31
|
+
/**
|
|
32
|
+
* Optional: wrap an agentLog msg so the client-side activity feed
|
|
33
|
+
* mirrors what Claude is doing. If omitted, outbound log-append
|
|
34
|
+
* frames still go to the server, but the local agent.log slice
|
|
35
|
+
* stays empty (the UI won't show activity).
|
|
36
|
+
*/
|
|
37
|
+
wrapLogMsg?: (m: unknown) => Msg;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export type AgentClient = {
|
|
41
|
+
effectHandler: (effect: AgentEffect) => Promise<void>;
|
|
42
|
+
start(): void;
|
|
43
|
+
stop(): void;
|
|
44
|
+
};
|
|
45
|
+
export declare function createAgentClient<State, Msg>(opts: CreateAgentClientOpts<State, Msg>): AgentClient;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,kBAAkB,EAEnB,MAAM,gBAAgB,CAAA;AAIvB,KAAK,iBAAiB,GAAG;IACvB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IACrD,oBAAoB,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,CAAA;IACpF,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,YAAY,CAAA;CAChD,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,KAAK,EAAE,GAAG,IAAI;IAC9C,MAAM,EAAE,SAAS,CAAA;IACjB,GAAG,EAAE,iBAAiB,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,OAAO,GAAG,IAAI,CAAA;IAC3B,MAAM,EAAE;QACN,UAAU,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,OAAO,CAAA;QACjC,UAAU,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,iBAAiB,CAAA;QAC3C,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,GAAG,CAAA;QACnC,cAAc,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,GAAG,CAAA;QACnC;;;;;WAKG;QACH,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,GAAG,CAAA;KACjC,CAAA;CACF,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,aAAa,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrD,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,IAAI,CAAA;CACb,CAAA;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,GAAG,EAC1C,IAAI,EAAE,qBAAqB,CAAC,KAAK,EAAE,GAAG,CAAC,GACtC,WAAW,CAoGb"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { attachWsClient } from './ws-client.js';
|
|
2
|
+
import { createEffectHandler } from './effect-handler.js';
|
|
3
|
+
export function createAgentClient(opts) {
|
|
4
|
+
let ws = null;
|
|
5
|
+
let wsClient = null;
|
|
6
|
+
let confirmPollTimer = null;
|
|
7
|
+
let stateSubscription = null;
|
|
8
|
+
const resolvedConfirms = new Set();
|
|
9
|
+
const rpcHost = {
|
|
10
|
+
getState: () => opts.handle.getState(),
|
|
11
|
+
send: (m) => opts.handle.send(m),
|
|
12
|
+
flush: () => opts.handle.flush(),
|
|
13
|
+
getMsgAnnotations: () => opts.def.__msgAnnotations ?? null,
|
|
14
|
+
getBindingDescriptors: () => opts.def.__bindingDescriptors ?? null,
|
|
15
|
+
getAgentAffordances: () => opts.def.agentAffordances ?? null,
|
|
16
|
+
getAgentContext: () => opts.def.agentContext ?? null,
|
|
17
|
+
getRootElement: () => opts.rootElement,
|
|
18
|
+
proposeConfirm: (entry) => {
|
|
19
|
+
opts.handle.send(opts.slices.wrapConfirmMsg({ type: 'Propose', entry }));
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const helloBuilder = () => ({
|
|
23
|
+
t: 'hello',
|
|
24
|
+
appName: opts.def.name,
|
|
25
|
+
appVersion: opts.appVersion ?? '0.0.0',
|
|
26
|
+
msgSchema: (opts.def.__msgSchema ?? {}),
|
|
27
|
+
stateSchema: (opts.def.__stateSchema ?? {}),
|
|
28
|
+
affordancesSample: opts.def.agentAffordances
|
|
29
|
+
? opts.def.agentAffordances(opts.handle.getState())
|
|
30
|
+
: [],
|
|
31
|
+
docs: opts.def.agentDocs ?? null,
|
|
32
|
+
schemaHash: opts.def.__schemaHash ?? '',
|
|
33
|
+
});
|
|
34
|
+
const effectHandler = createEffectHandler({
|
|
35
|
+
send: (m) => opts.handle.send(m),
|
|
36
|
+
wrapAgentConnect: (m) => opts.slices.wrapConnectMsg(m),
|
|
37
|
+
forward: (payload) => opts.handle.send(payload),
|
|
38
|
+
openWs: (token, wsUrl) => {
|
|
39
|
+
if (ws)
|
|
40
|
+
ws.close();
|
|
41
|
+
ws = new WebSocket(`${wsUrl}?token=${encodeURIComponent(token)}`);
|
|
42
|
+
wsClient = attachWsClient(ws, rpcHost, helloBuilder, {
|
|
43
|
+
onActivated: () => {
|
|
44
|
+
opts.handle.send(opts.slices.wrapConnectMsg({ type: 'ActivatedByClaude' }));
|
|
45
|
+
},
|
|
46
|
+
onLogEntry: opts.slices.wrapLogMsg
|
|
47
|
+
? (entry) => {
|
|
48
|
+
opts.handle.send(opts.slices.wrapLogMsg({ type: 'Append', entry }));
|
|
49
|
+
}
|
|
50
|
+
: undefined,
|
|
51
|
+
});
|
|
52
|
+
ws.addEventListener('open', () => {
|
|
53
|
+
opts.handle.send(opts.slices.wrapConnectMsg({ type: 'WsOpened' }));
|
|
54
|
+
});
|
|
55
|
+
ws.addEventListener('close', () => {
|
|
56
|
+
opts.handle.send(opts.slices.wrapConnectMsg({ type: 'WsClosed' }));
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
closeWs: () => {
|
|
60
|
+
wsClient?.close();
|
|
61
|
+
ws = null;
|
|
62
|
+
wsClient = null;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const pollConfirms = () => {
|
|
66
|
+
const state = opts.handle.getState();
|
|
67
|
+
const confirm = opts.slices.getConfirm(state);
|
|
68
|
+
for (const entry of confirm.pending) {
|
|
69
|
+
if (entry.status === 'pending')
|
|
70
|
+
continue;
|
|
71
|
+
if (resolvedConfirms.has(entry.id))
|
|
72
|
+
continue;
|
|
73
|
+
resolvedConfirms.add(entry.id);
|
|
74
|
+
if (entry.status === 'approved') {
|
|
75
|
+
wsClient?.resolveConfirm(entry.id, 'confirmed', opts.handle.getState());
|
|
76
|
+
}
|
|
77
|
+
else if (entry.status === 'rejected') {
|
|
78
|
+
wsClient?.resolveConfirm(entry.id, 'user-cancelled');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
effectHandler,
|
|
84
|
+
start() {
|
|
85
|
+
if (!confirmPollTimer)
|
|
86
|
+
confirmPollTimer = setInterval(pollConfirms, 200);
|
|
87
|
+
if (!stateSubscription) {
|
|
88
|
+
stateSubscription = opts.handle.subscribe((state) => {
|
|
89
|
+
wsClient?.emitStateUpdate('/', state);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
stop() {
|
|
94
|
+
if (confirmPollTimer)
|
|
95
|
+
clearInterval(confirmPollTimer);
|
|
96
|
+
confirmPollTimer = null;
|
|
97
|
+
if (stateSubscription) {
|
|
98
|
+
stateSubscription();
|
|
99
|
+
stateSubscription = null;
|
|
100
|
+
}
|
|
101
|
+
wsClient?.close();
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/client/factory.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AppHandle } from '@llui/dom'\nimport type { AgentEffect } from './effects.js'\nimport type { AgentConfirmState } from './agentConfirm.js'\nimport type {\n AgentDocs,\n AgentContext,\n MessageAnnotations,\n MessageSchemaEntry,\n} from '../protocol.js'\nimport { attachWsClient, type WsLike, type RpcHosts } from './ws-client.js'\nimport { createEffectHandler } from './effect-handler.js'\n\ntype ComponentMetadata = {\n __msgSchema?: unknown\n __stateSchema?: unknown\n __msgAnnotations?: Record<string, MessageAnnotations>\n __bindingDescriptors?: Array<{ variant: string }>\n __schemaHash?: string\n name: string\n agentAffordances?: (state: unknown) => Array<{ type: string; [k: string]: unknown }>\n agentDocs?: AgentDocs\n agentContext?: (state: unknown) => AgentContext\n}\n\nexport type CreateAgentClientOpts<State, Msg> = {\n handle: AppHandle\n def: ComponentMetadata\n appVersion?: string\n rootElement: Element | null\n slices: {\n getConnect: (s: State) => unknown\n getConfirm: (s: State) => AgentConfirmState\n wrapConnectMsg: (m: unknown) => Msg\n wrapConfirmMsg: (m: unknown) => Msg\n /**\n * Optional: wrap an agentLog msg so the client-side activity feed\n * mirrors what Claude is doing. If omitted, outbound log-append\n * frames still go to the server, but the local agent.log slice\n * stays empty (the UI won't show activity).\n */\n wrapLogMsg?: (m: unknown) => Msg\n }\n}\n\nexport type AgentClient = {\n effectHandler: (effect: AgentEffect) => Promise<void>\n start(): void\n stop(): void\n}\n\nexport function createAgentClient<State, Msg>(\n opts: CreateAgentClientOpts<State, Msg>,\n): AgentClient {\n let ws: WebSocket | null = null\n let wsClient: ReturnType<typeof attachWsClient> | null = null\n let confirmPollTimer: ReturnType<typeof setInterval> | null = null\n let stateSubscription: (() => void) | null = null\n const resolvedConfirms = new Set<string>()\n\n const rpcHost: RpcHosts = {\n getState: () => opts.handle.getState(),\n send: (m) => opts.handle.send(m),\n flush: () => opts.handle.flush(),\n getMsgAnnotations: () => opts.def.__msgAnnotations ?? null,\n getBindingDescriptors: () => opts.def.__bindingDescriptors ?? null,\n getAgentAffordances: () => opts.def.agentAffordances ?? null,\n getAgentContext: () => opts.def.agentContext ?? null,\n getRootElement: () => opts.rootElement,\n proposeConfirm: (entry) => {\n opts.handle.send(opts.slices.wrapConfirmMsg({ type: 'Propose', entry }))\n },\n }\n\n const helloBuilder = () => ({\n t: 'hello' as const,\n appName: opts.def.name,\n appVersion: opts.appVersion ?? '0.0.0',\n msgSchema: (opts.def.__msgSchema ?? {}) as Record<string, MessageSchemaEntry>,\n stateSchema: (opts.def.__stateSchema ?? {}) as object,\n affordancesSample: opts.def.agentAffordances\n ? opts.def.agentAffordances(opts.handle.getState())\n : [],\n docs: opts.def.agentDocs ?? null,\n schemaHash: opts.def.__schemaHash ?? '',\n })\n\n const effectHandler = createEffectHandler({\n send: (m) => opts.handle.send(m),\n wrapAgentConnect: (m) => opts.slices.wrapConnectMsg(m),\n forward: (payload) => opts.handle.send(payload),\n openWs: (token, wsUrl) => {\n if (ws) ws.close()\n ws = new WebSocket(`${wsUrl}?token=${encodeURIComponent(token)}`)\n wsClient = attachWsClient(ws as unknown as WsLike, rpcHost, helloBuilder, {\n onActivated: () => {\n opts.handle.send(opts.slices.wrapConnectMsg({ type: 'ActivatedByClaude' }))\n },\n onLogEntry: opts.slices.wrapLogMsg\n ? (entry) => {\n opts.handle.send(opts.slices.wrapLogMsg!({ type: 'Append', entry }))\n }\n : undefined,\n })\n ws.addEventListener('open', () => {\n opts.handle.send(opts.slices.wrapConnectMsg({ type: 'WsOpened' }))\n })\n ws.addEventListener('close', () => {\n opts.handle.send(opts.slices.wrapConnectMsg({ type: 'WsClosed' }))\n })\n },\n closeWs: () => {\n wsClient?.close()\n ws = null\n wsClient = null\n },\n })\n\n const pollConfirms = () => {\n const state = opts.handle.getState() as State\n const confirm = opts.slices.getConfirm(state)\n for (const entry of confirm.pending) {\n if (entry.status === 'pending') continue\n if (resolvedConfirms.has(entry.id)) continue\n resolvedConfirms.add(entry.id)\n if (entry.status === 'approved') {\n wsClient?.resolveConfirm(entry.id, 'confirmed', opts.handle.getState())\n } else if (entry.status === 'rejected') {\n wsClient?.resolveConfirm(entry.id, 'user-cancelled')\n }\n }\n }\n\n return {\n effectHandler,\n start() {\n if (!confirmPollTimer) confirmPollTimer = setInterval(pollConfirms, 200)\n if (!stateSubscription) {\n stateSubscription = opts.handle.subscribe((state) => {\n wsClient?.emitStateUpdate('/', state)\n })\n }\n },\n stop() {\n if (confirmPollTimer) clearInterval(confirmPollTimer)\n confirmPollTimer = null\n if (stateSubscription) {\n stateSubscription()\n stateSubscription = null\n }\n wsClient?.close()\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * as agentConnect from './agentConnect.js';
|
|
2
|
+
export * as agentConfirm from './agentConfirm.js';
|
|
3
|
+
export * as agentLog from './agentLog.js';
|
|
4
|
+
export type { AgentEffect, AgentEffectHandler } from './effects.js';
|
|
5
|
+
export { createAgentClient } from './factory.js';
|
|
6
|
+
export type { CreateAgentClientOpts, AgentClient } from './factory.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AACzC,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,YAAY,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAA;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA","sourcesContent":["export * as agentConnect from './agentConnect.js'\nexport * as agentConfirm from './agentConfirm.js'\nexport * as agentLog from './agentLog.js'\nexport type { AgentEffect, AgentEffectHandler } from './effects.js'\nexport { createAgentClient } from './factory.js'\nexport type { CreateAgentClientOpts, AgentClient } from './factory.js'\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AgentContext } from '../../protocol.js';
|
|
2
|
+
export type DescribeContextHost = {
|
|
3
|
+
getState(): unknown;
|
|
4
|
+
getAgentContext(): ((state: unknown) => AgentContext) | null;
|
|
5
|
+
};
|
|
6
|
+
export type DescribeContextResult = {
|
|
7
|
+
context: AgentContext;
|
|
8
|
+
};
|
|
9
|
+
export declare function handleDescribeContext(host: DescribeContextHost): DescribeContextResult;
|
|
10
|
+
//# sourceMappingURL=describe-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe-context.d.ts","sourceRoot":"","sources":["../../../src/client/rpc/describe-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,IAAI,OAAO,CAAA;IACnB,eAAe,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,YAAY,CAAC,GAAG,IAAI,CAAA;CAC7D,CAAA;AACD,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,YAAY,CAAA;CAAE,CAAA;AAI7D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,qBAAqB,CAItF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const EMPTY = { summary: '', hints: [], cautions: [] };
|
|
2
|
+
export function handleDescribeContext(host) {
|
|
3
|
+
const fn = host.getAgentContext();
|
|
4
|
+
if (!fn)
|
|
5
|
+
return { context: EMPTY };
|
|
6
|
+
return { context: fn(host.getState()) };
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=describe-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe-context.js","sourceRoot":"","sources":["../../../src/client/rpc/describe-context.ts"],"names":[],"mappings":"AAQA,MAAM,KAAK,GAAiB,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;AAEpE,MAAM,UAAU,qBAAqB,CAAC,IAAyB;IAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,eAAe,EAAE,CAAA;IACjC,IAAI,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAA;IAClC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAA;AACzC,CAAC","sourcesContent":["import type { AgentContext } from '../../protocol.js'\n\nexport type DescribeContextHost = {\n getState(): unknown\n getAgentContext(): ((state: unknown) => AgentContext) | null\n}\nexport type DescribeContextResult = { context: AgentContext }\n\nconst EMPTY: AgentContext = { summary: '', hints: [], cautions: [] }\n\nexport function handleDescribeContext(host: DescribeContextHost): DescribeContextResult {\n const fn = host.getAgentContext()\n if (!fn) return { context: EMPTY }\n return { context: fn(host.getState()) }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OutlineNode } from '../../protocol.js';
|
|
2
|
+
export type DescribeVisibleArgs = Record<string, never>;
|
|
3
|
+
export type DescribeVisibleResult = {
|
|
4
|
+
outline: OutlineNode[];
|
|
5
|
+
};
|
|
6
|
+
export type DescribeVisibleHost = {
|
|
7
|
+
getRootElement(): Element | null;
|
|
8
|
+
getBindingDescriptors(): Array<{
|
|
9
|
+
variant: string;
|
|
10
|
+
}> | null;
|
|
11
|
+
getMsgAnnotations(): Record<string, {
|
|
12
|
+
intent: string | null;
|
|
13
|
+
humanOnly: boolean;
|
|
14
|
+
}> | null;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Walk data-agent-tagged subtrees and produce a structured outline.
|
|
18
|
+
* Buttons cross-reference __bindingDescriptors so Claude can tie
|
|
19
|
+
* visible text to variant names.
|
|
20
|
+
*/
|
|
21
|
+
export declare function handleDescribeVisibleContent(host: DescribeVisibleHost): DescribeVisibleResult;
|
|
22
|
+
//# sourceMappingURL=describe-visible-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe-visible-content.d.ts","sourceRoot":"","sources":["../../../src/client/rpc/describe-visible-content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;AACvD,MAAM,MAAM,qBAAqB,GAAG;IAAE,OAAO,EAAE,WAAW,EAAE,CAAA;CAAE,CAAA;AAE9D,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,IAAI,OAAO,GAAG,IAAI,CAAA;IAChC,qBAAqB,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAA;IAC1D,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,CAAC,GAAG,IAAI,CAAA;CAC1F,CAAA;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,mBAAmB,GAAG,qBAAqB,CAa7F"}
|