@ai-ecoverse/slicc-agent 3.34.0 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -3
- package/dist/host.js +2 -0
- package/dist/host.js.map +2 -2
- package/dist/index.js +14 -1
- package/dist/index.js.map +2 -2
- package/dist/kernel/users.js +113 -0
- package/dist/kernel/users.js.map +7 -0
- package/dist/main.js +34 -9
- package/dist/main.js.map +2 -2
- package/dist/mcp/accounts.js +79 -0
- package/dist/mcp/accounts.js.map +7 -0
- package/dist/mcp/config.js +40 -5
- package/dist/mcp/config.js.map +2 -2
- package/dist/mcp/connection.js +11 -5
- package/dist/mcp/connection.js.map +2 -2
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/index.js.map +2 -2
- package/dist/mcp/oauth.js +260 -0
- package/dist/mcp/oauth.js.map +7 -0
- package/dist/mcp/runtime.js +25 -60
- package/dist/mcp/runtime.js.map +2 -2
- package/dist/oauth/mcp-callback.html +109 -0
- package/dist/owner.js +19 -2
- package/dist/owner.js.map +2 -2
- package/dist/scoops/index.js +28 -8
- package/dist/scoops/index.js.map +2 -2
- package/dist/services.js.map +2 -2
- package/dist/settings.js +15 -2
- package/dist/settings.js.map +2 -2
- package/dist/spectrum/mcp-login.js +73 -0
- package/dist/spectrum/mcp-login.js.map +7 -0
- package/dist/spectrum/settings-port.js +12 -5
- package/dist/spectrum/settings-port.js.map +2 -2
- package/dist/types/host.d.ts +3 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/kernel/users.d.ts +53 -0
- package/dist/types/main.d.ts +6 -0
- package/dist/types/mcp/accounts.d.ts +20 -0
- package/dist/types/mcp/config.d.ts +8 -0
- package/dist/types/mcp/connection.d.ts +1 -0
- package/dist/types/mcp/oauth.d.ts +57 -0
- package/dist/types/mcp/runtime.d.ts +3 -8
- package/dist/types/owner.d.ts +2 -3
- package/dist/types/scoops/index.d.ts +4 -1
- package/dist/types/services.d.ts +5 -1
- package/dist/types/settings.d.ts +1 -0
- package/dist/types/spectrum/mcp-login.d.ts +26 -0
- package/dist/types/spectrum/settings-port.d.ts +1 -1
- package/dist/types/worker.d.ts +5 -0
- package/dist/worker.js +9 -3
- package/dist/worker.js.map +2 -2
- package/package.json +1 -1
package/dist/owner.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { connectAgent } from "./client.js";
|
|
2
|
+
import { serveAdmin } from "./kernel/users.js";
|
|
2
3
|
import { holdLock } from "./opfs-pool.js";
|
|
3
4
|
const AGENT_LOCK = "slicc-agent";
|
|
4
5
|
async function startAgent(options) {
|
|
@@ -6,16 +7,32 @@ async function startAgent(options) {
|
|
|
6
7
|
const channel = options.channel ?? (() => new MessageChannel());
|
|
7
8
|
const spawn = async () => {
|
|
8
9
|
const created = options.worker();
|
|
10
|
+
let admin;
|
|
9
11
|
try {
|
|
10
12
|
if (options.kernel) {
|
|
11
13
|
const port = await options.kernel.connect();
|
|
12
|
-
created.postMessage({ kernel: port }, [port]);
|
|
14
|
+
if (!options.kernel.users) created.postMessage({ kernel: port }, [port]);
|
|
15
|
+
else {
|
|
16
|
+
const { port1, port2 } = channel();
|
|
17
|
+
admin = port1;
|
|
18
|
+
serveAdmin(port1, options.kernel);
|
|
19
|
+
created.postMessage({ kernel: port, admin: port2 }, [port, port2]);
|
|
20
|
+
}
|
|
13
21
|
}
|
|
14
22
|
} catch (error) {
|
|
23
|
+
admin?.close?.();
|
|
15
24
|
created.terminate();
|
|
16
25
|
throw error;
|
|
17
26
|
}
|
|
18
|
-
return created;
|
|
27
|
+
if (!admin) return created;
|
|
28
|
+
const served = admin;
|
|
29
|
+
return {
|
|
30
|
+
postMessage: (message, transfer) => created.postMessage(message, transfer),
|
|
31
|
+
terminate() {
|
|
32
|
+
served.close?.();
|
|
33
|
+
created.terminate();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
19
36
|
};
|
|
20
37
|
let worker = Promise.resolve().then(spawn);
|
|
21
38
|
try {
|
package/dist/owner.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/owner.ts"],
|
|
4
|
-
"sourcesContent": ["import { type AgentConnection, connectAgent } from './client.ts';\nimport { holdLock } from './opfs-pool.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport const AGENT_LOCK = 'slicc-agent';\n\nexport interface AgentWorker {\n postMessage(message: unknown, transfer: Transferable[]): void;\n terminate(): void;\n}\n\nexport interface PortOptions {\n readOnly?: boolean;\n}\n\nexport interface AgentOwner {\n connect(options?: PortOptions): Promise<AgentConnection>;\n port(options?: PortOptions): Promise<PortEndpoint & Transferable>;\n restart(): Promise<void>;\n release(): Promise<void>;\n}\n\nexport
|
|
5
|
-
"mappings": "AAAA,SAA+B,oBAAoB;AACnD,SAAS,gBAAgB;AAGlB,MAAM,aAAa;
|
|
4
|
+
"sourcesContent": ["import { type AgentConnection, connectAgent } from './client.ts';\nimport { type KernelSource, serveAdmin } from './kernel/users.ts';\nimport { holdLock } from './opfs-pool.ts';\nimport type { PortEndpoint } from './wire.ts';\n\nexport const AGENT_LOCK = 'slicc-agent';\n\nexport interface AgentWorker {\n postMessage(message: unknown, transfer: Transferable[]): void;\n terminate(): void;\n}\n\nexport interface PortOptions {\n readOnly?: boolean;\n}\n\nexport interface AgentOwner {\n connect(options?: PortOptions): Promise<AgentConnection>;\n port(options?: PortOptions): Promise<PortEndpoint & Transferable>;\n restart(): Promise<void>;\n release(): Promise<void>;\n}\n\nexport type { KernelSource } from './kernel/users.ts';\n\nexport interface OwnerOptions {\n worker: () => AgentWorker;\n kernel?: KernelSource;\n locks?: LockManager;\n held?: boolean;\n channel?: () => { port1: PortEndpoint & Transferable; port2: Transferable };\n}\n\nexport async function startAgent(options: OwnerOptions): Promise<AgentOwner> {\n const release = options.held\n ? () => undefined\n : await holdLock(options.locks ?? navigator.locks, AGENT_LOCK);\n const channel = options.channel ?? (() => new MessageChannel());\n const spawn = async (): Promise<AgentWorker> => {\n const created = options.worker();\n let admin: (PortEndpoint & Transferable) | undefined;\n try {\n if (options.kernel) {\n const port = await options.kernel.connect();\n if (!options.kernel.users) created.postMessage({ kernel: port }, [port]);\n else {\n const { port1, port2 } = channel();\n admin = port1;\n serveAdmin(port1, options.kernel);\n created.postMessage({ kernel: port, admin: port2 }, [port, port2]);\n }\n }\n } catch (error) {\n admin?.close?.();\n created.terminate();\n throw error;\n }\n if (!admin) return created;\n const served = admin;\n return {\n postMessage: (message, transfer) => created.postMessage(message, transfer),\n terminate() {\n served.close?.();\n created.terminate();\n },\n };\n };\n let worker: Promise<AgentWorker | undefined> = Promise.resolve().then(spawn);\n try {\n await worker;\n } catch (error) {\n release();\n throw error;\n }\n const open = async (portOptions: PortOptions = {}): Promise<PortEndpoint & Transferable> => {\n const ready = await worker;\n if (!ready) throw new Error('the agent was released');\n const { port1, port2 } = channel();\n const readOnly = portOptions.readOnly === true ? { readOnly: true } : {};\n ready.postMessage({ connect: port2, ...readOnly }, [port2]);\n return port1;\n };\n return {\n async connect(portOptions) {\n return connectAgent(await open(portOptions));\n },\n port: open,\n restart() {\n worker = worker\n .catch(() => undefined)\n .then((old) => {\n old?.terminate();\n return spawn();\n });\n return worker.then(() => undefined);\n },\n async release() {\n const previous = worker;\n worker = Promise.resolve(undefined);\n try {\n (await previous.catch(() => undefined))?.terminate();\n } finally {\n release();\n }\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAA+B,oBAAoB;AACnD,SAA4B,kBAAkB;AAC9C,SAAS,gBAAgB;AAGlB,MAAM,aAAa;AA4B1B,eAAsB,WAAW,SAA4C;AAC3E,QAAM,UAAU,QAAQ,OACpB,MAAM,SACN,MAAM,SAAS,QAAQ,SAAS,UAAU,OAAO,UAAU;AAC/D,QAAM,UAAU,QAAQ,YAAY,MAAM,IAAI,eAAe;AAC7D,QAAM,QAAQ,YAAkC;AAC9C,UAAM,UAAU,QAAQ,OAAO;AAC/B,QAAI;AACJ,QAAI;AACF,UAAI,QAAQ,QAAQ;AAClB,cAAM,OAAO,MAAM,QAAQ,OAAO,QAAQ;AAC1C,YAAI,CAAC,QAAQ,OAAO,MAAO,SAAQ,YAAY,EAAE,QAAQ,KAAK,GAAG,CAAC,IAAI,CAAC;AAAA,aAClE;AACH,gBAAM,EAAE,OAAO,MAAM,IAAI,QAAQ;AACjC,kBAAQ;AACR,qBAAW,OAAO,QAAQ,MAAM;AAChC,kBAAQ,YAAY,EAAE,QAAQ,MAAM,OAAO,MAAM,GAAG,CAAC,MAAM,KAAK,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO,QAAQ;AACf,cAAQ,UAAU;AAClB,YAAM;AAAA,IACR;AACA,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,SAAS;AACf,WAAO;AAAA,MACL,aAAa,CAAC,SAAS,aAAa,QAAQ,YAAY,SAAS,QAAQ;AAAA,MACzE,YAAY;AACV,eAAO,QAAQ;AACf,gBAAQ,UAAU;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAA2C,QAAQ,QAAQ,EAAE,KAAK,KAAK;AAC3E,MAAI;AACF,UAAM;AAAA,EACR,SAAS,OAAO;AACd,YAAQ;AACR,UAAM;AAAA,EACR;AACA,QAAM,OAAO,OAAO,cAA2B,CAAC,MAA4C;AAC1F,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,wBAAwB;AACpD,UAAM,EAAE,OAAO,MAAM,IAAI,QAAQ;AACjC,UAAM,WAAW,YAAY,aAAa,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;AACvE,UAAM,YAAY,EAAE,SAAS,OAAO,GAAG,SAAS,GAAG,CAAC,KAAK,CAAC;AAC1D,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM,QAAQ,aAAa;AACzB,aAAO,aAAa,MAAM,KAAK,WAAW,CAAC;AAAA,IAC7C;AAAA,IACA,MAAM;AAAA,IACN,UAAU;AACR,eAAS,OACN,MAAM,MAAM,MAAS,EACrB,KAAK,CAAC,QAAQ;AACb,aAAK,UAAU;AACf,eAAO,MAAM;AAAA,MACf,CAAC;AACH,aAAO,OAAO,KAAK,MAAM,MAAS;AAAA,IACpC;AAAA,IACA,MAAM,UAAU;AACd,YAAM,WAAW;AACjB,eAAS,QAAQ,QAAQ,MAAS;AAClC,UAAI;AACF,SAAC,MAAM,SAAS,MAAM,MAAM,MAAS,IAAI,UAAU;AAAA,MACrD,UAAE;AACA,gBAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/scoops/index.js
CHANGED
|
@@ -2,10 +2,11 @@ import { live } from "../agents.js";
|
|
|
2
2
|
import { DEFAULT_LIMITS, loadRoles, packageDirs } from "../roles/roles.js";
|
|
3
3
|
import { createCli, RUN_DIR } from "./cli.js";
|
|
4
4
|
import { guardExtension, scoopsExtension, scoopTasks } from "./extension.js";
|
|
5
|
-
import { controlPlane } from "./requests.js";
|
|
5
|
+
import { controlPlane, PROTOCOL } from "./requests.js";
|
|
6
6
|
import { createScoops } from "./service.js";
|
|
7
7
|
const BUILTIN_ROLES = ["scout", "worker", "reviewer", "oracle", "delegate", "gelatiere"];
|
|
8
8
|
const PNPM_HOME = "/home/.local/share/pnpm";
|
|
9
|
+
const BIN_DIR = "/usr/local/bin";
|
|
9
10
|
function packageAssets(base = new URL("../../", import.meta.url)) {
|
|
10
11
|
return async (path) => {
|
|
11
12
|
const response = await fetch(new URL(path, base));
|
|
@@ -35,12 +36,28 @@ async function pnpmHomeOf(env, context) {
|
|
|
35
36
|
).catch(() => void 0);
|
|
36
37
|
return ran?.ok && ran.value.exitCode === 0 && /^\/\S*$/.test(out) ? out : PNPM_HOME;
|
|
37
38
|
}
|
|
38
|
-
async function install(env, script,
|
|
39
|
-
await env.createDir(
|
|
39
|
+
async function install(env, script, binDir, context) {
|
|
40
|
+
if (!(await env.createDir(binDir, { recursive: true }, context)).ok) return false;
|
|
40
41
|
for (const name of COMMANDS) {
|
|
41
|
-
const path = `${
|
|
42
|
-
await env.writeFile(path, script, context);
|
|
43
|
-
await env.exec(["chmod", "
|
|
42
|
+
const path = `${binDir}/${name}`;
|
|
43
|
+
if (!(await env.writeFile(path, script, context)).ok) return false;
|
|
44
|
+
const mode = await env.exec(["chmod", "755", path], void 0, context);
|
|
45
|
+
if (!mode.ok || mode.value.exitCode !== 0) return false;
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
async function installCommands(env, script, binDir, context) {
|
|
50
|
+
const done = await install(env, script, binDir, context).catch(() => false);
|
|
51
|
+
if (done) await retire(env, binDir, context).catch(() => void 0);
|
|
52
|
+
return done;
|
|
53
|
+
}
|
|
54
|
+
async function retire(env, binDir, context) {
|
|
55
|
+
const old = `${await pnpmHomeOf(env, context)}/bin`;
|
|
56
|
+
if (old === binDir) return;
|
|
57
|
+
for (const name of COMMANDS) {
|
|
58
|
+
const path = `${old}/${name}`;
|
|
59
|
+
const text = await env.readTextFile(path, context);
|
|
60
|
+
if (text.ok && text.value.includes(PROTOCOL)) await env.remove(path, { force: true }, context);
|
|
44
61
|
}
|
|
45
62
|
}
|
|
46
63
|
function mirror(agents, env) {
|
|
@@ -119,8 +136,8 @@ function setupScoops(registry, licks, fileTools = []) {
|
|
|
119
136
|
await roles(context).catch(() => cached);
|
|
120
137
|
const script = await assets("bin/agent").catch(() => void 0);
|
|
121
138
|
if (script) {
|
|
122
|
-
const
|
|
123
|
-
await
|
|
139
|
+
const binDir = options.binDir ?? BIN_DIR;
|
|
140
|
+
await installCommands(env, script, binDir, context);
|
|
124
141
|
}
|
|
125
142
|
const cli = createCli({
|
|
126
143
|
env,
|
|
@@ -146,11 +163,14 @@ function setupScoops(registry, licks, fileTools = []) {
|
|
|
146
163
|
};
|
|
147
164
|
}
|
|
148
165
|
export {
|
|
166
|
+
BIN_DIR,
|
|
149
167
|
BUILTIN_ROLES,
|
|
150
168
|
COMMANDS,
|
|
151
169
|
PNPM_HOME,
|
|
170
|
+
installCommands,
|
|
152
171
|
packageAssets,
|
|
153
172
|
pnpmHomeOf,
|
|
173
|
+
retire,
|
|
154
174
|
setupScoops
|
|
155
175
|
};
|
|
156
176
|
//# sourceMappingURL=index.js.map
|
package/dist/scoops/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/scoops/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Harness, Registry, ToolRegistration } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport type { ProcessGroups } from '../kernel/groups.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport { DEFAULT_LIMITS, loadRoles, packageDirs, type Roles } from '../roles/roles.ts';\nimport { type CliOptions, createCli, RUN_DIR } from './cli.ts';\nimport { guardExtension, scoopsExtension, scoopTasks } from './extension.ts';\nimport { type ControlPlane, controlPlane } from './requests.ts';\nimport { createScoops, type Scoops, type ScoopsHost } from './service.ts';\n\nexport const BUILTIN_ROLES = ['scout', 'worker', 'reviewer', 'oracle', 'delegate', 'gelatiere'];\nexport const PNPM_HOME = '/home/.local/share/pnpm';\n\nexport type Assets = (path: string) => Promise<string>;\n\nexport function packageAssets(base: URL = new URL('../../', import.meta.url)): Assets {\n return async (path) => {\n const response = await fetch(new URL(path, base));\n if (!response.ok) throw new Error(`${path}: ${response.status}`);\n return response.text();\n };\n}\n\nexport interface AttachOptions {\n harness: Harness;\n agents: Agents;\n groups: ProcessGroups;\n env: ExecutionEnv;\n home: string;\n assets?: Assets;\n
|
|
5
|
-
"mappings": "AAGA,SAAsB,YAAY;AAGlC,SAAS,gBAAgB,WAAW,mBAA+B;AACnE,SAA0B,WAAW,eAAe;AACpD,SAAS,gBAAgB,iBAAiB,kBAAkB;AAC5D,SAA4B,
|
|
4
|
+
"sourcesContent": ["import type { Context } from '@earendil-works/chord';\nimport type { Harness, Registry, ToolRegistration } from '@earendil-works/pi-durable';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\nimport { type Agents, live } from '../agents.ts';\nimport type { ProcessGroups } from '../kernel/groups.ts';\nimport type { Licks } from '../licks/licks.ts';\nimport { DEFAULT_LIMITS, loadRoles, packageDirs, type Roles } from '../roles/roles.ts';\nimport { type CliOptions, createCli, RUN_DIR } from './cli.ts';\nimport { guardExtension, scoopsExtension, scoopTasks } from './extension.ts';\nimport { type ControlPlane, controlPlane, PROTOCOL } from './requests.ts';\nimport { createScoops, type Scoops, type ScoopsHost } from './service.ts';\n\nexport const BUILTIN_ROLES = ['scout', 'worker', 'reviewer', 'oracle', 'delegate', 'gelatiere'];\nexport const PNPM_HOME = '/home/.local/share/pnpm';\nexport const BIN_DIR = '/usr/local/bin';\n\nexport type Assets = (path: string) => Promise<string>;\n\nexport function packageAssets(base: URL = new URL('../../', import.meta.url)): Assets {\n return async (path) => {\n const response = await fetch(new URL(path, base));\n if (!response.ok) throw new Error(`${path}: ${response.status}`);\n return response.text();\n };\n}\n\nexport interface AttachOptions {\n harness: Harness;\n agents: Agents;\n groups: ProcessGroups;\n env: ExecutionEnv;\n home: string;\n assets?: Assets;\n binDir?: string;\n controlDir?: string;\n sweepEvery?: number;\n alive?: (pid: number) => Promise<boolean>;\n reads: () => readonly string[];\n sprinkle?: CliOptions['sprinkle'];\n memory?: CliOptions['memory'];\n gelatiere?: CliOptions['gelatiere'];\n freezer?: CliOptions['freezer'];\n models?: CliOptions['models'];\n mcp?: (names: readonly string[]) => ToolRegistration[];\n}\n\nexport interface ScoopsRuntime {\n roles(context: Context): Promise<Roles>;\n plane: ControlPlane;\n close(context: Context): Promise<void>;\n}\n\nexport interface ScoopsSetup {\n scoops: Scoops;\n attach(options: AttachOptions, context: Context): Promise<ScoopsRuntime>;\n}\n\nexport const COMMANDS = [\n 'agent',\n 'subagent',\n 'sprinkle',\n 'memory',\n 'gelatiere',\n 'freezer',\n 'models',\n];\n\nexport async function pnpmHomeOf(env: ExecutionEnv, context: Context): Promise<string> {\n let out = '';\n const ran = await env\n .exec(\n 'printf %s \"$PNPM_HOME\"',\n {\n onOutput: (text) => {\n out += text;\n },\n },\n context\n )\n .catch(() => undefined);\n return ran?.ok && ran.value.exitCode === 0 && /^\\/\\S*$/.test(out) ? out : PNPM_HOME;\n}\n\nasync function install(env: ExecutionEnv, script: string, binDir: string, context: Context) {\n if (!(await env.createDir(binDir, { recursive: true }, context)).ok) return false;\n for (const name of COMMANDS) {\n const path = `${binDir}/${name}`;\n if (!(await env.writeFile(path, script, context)).ok) return false;\n const mode = await env.exec(['chmod', '755', path], undefined, context);\n if (!mode.ok || mode.value.exitCode !== 0) return false;\n }\n return true;\n}\n\nexport async function installCommands(\n env: ExecutionEnv,\n script: string,\n binDir: string,\n context: Context\n): Promise<boolean> {\n const done = await install(env, script, binDir, context).catch(() => false);\n if (done) await retire(env, binDir, context).catch(() => undefined);\n return done;\n}\n\nexport async function retire(env: ExecutionEnv, binDir: string, context: Context) {\n const old = `${await pnpmHomeOf(env, context)}/bin`;\n if (old === binDir) return;\n for (const name of COMMANDS) {\n const path = `${old}/${name}`;\n const text = await env.readTextFile(path, context);\n if (text.ok && text.value.includes(PROTOCOL)) await env.remove(path, { force: true }, context);\n }\n}\n\nfunction mirror(agents: Agents, env: ExecutionEnv) {\n return async (context: Context) => {\n for (const [id, record] of Object.entries(agents.state().scoops)) {\n const state = record.gone ? 'gone' : live(record) ? 'live' : 'stopped';\n const metadata = {\n handle: record.folder,\n id,\n name: record.name,\n role: record.role,\n cone: record.cone,\n state,\n };\n await env.writeFile(\n `${RUN_DIR}/${record.folder}/metadata.json`,\n `${JSON.stringify(metadata, null, 2)}\\n`,\n context\n );\n }\n };\n}\n\nexport function setupScoops(\n registry: Registry,\n licks: Licks,\n fileTools: readonly ToolRegistration[] = []\n): ScoopsSetup {\n let bind: (host: ScoopsHost) => void = () => undefined;\n const host = new Promise<ScoopsHost>((resolve) => {\n bind = resolve;\n });\n const lookup = () => host;\n const tasks = scoopTasks(lookup);\n const scoops = createScoops(host, () => tasks);\n let cached: Roles = { roles: [], warnings: [], limits: { ...DEFAULT_LIMITS } };\n registry.install(scoopsExtension(tasks));\n registry.install(guardExtension(lookup, fileTools));\n return {\n scoops,\n async attach(options, context) {\n const { harness, agents, groups, env, home } = options;\n const assets = options.assets ?? packageAssets();\n bind({\n harness,\n agents,\n licks,\n tools: fileTools,\n groups,\n reads: options.reads,\n files: env,\n ...(options.mcp ? { mcp: options.mcp } : {}),\n });\n const builtin = async () => {\n const out: { path: string; text: string }[] = [];\n for (const name of BUILTIN_ROLES) {\n const path = `packages/vfs-root/agents/${name}.md`;\n out.push({ path: `builtin:${name}`, text: await assets(path) });\n }\n return out;\n };\n const roles = async (using: Context) => {\n cached = await loadRoles(\n {\n files: env,\n builtin,\n dirs: [\n ...(await packageDirs(env, '/node_modules', using)).map((dir) => ({\n source: 'package' as const,\n dir,\n })),\n { source: 'user', dir: `${home}/.pi/agent/agents` },\n ],\n settingsPath: `${home}/.pi/agent/settings.json`,\n },\n using\n );\n return cached;\n };\n await roles(context).catch(() => cached);\n const script = await assets('bin/agent').catch(() => undefined);\n if (script) {\n const binDir = options.binDir ?? BIN_DIR;\n await installCommands(env, script, binDir, context);\n }\n const cli = createCli({\n env,\n harness,\n agents,\n scoops,\n roles: () => roles(context),\n ...(options.alive ? { alive: options.alive } : {}),\n ...(options.sprinkle ? { sprinkle: options.sprinkle } : {}),\n ...(options.memory ? { memory: options.memory } : {}),\n ...(options.gelatiere ? { gelatiere: options.gelatiere } : {}),\n ...(options.freezer ? { freezer: options.freezer } : {}),\n ...(options.models ? { models: options.models } : {}),\n });\n const plane = controlPlane(env, cli, {\n ...(options.controlDir ? { dir: options.controlDir } : {}),\n ...(options.sweepEvery ? { sweepEvery: options.sweepEvery } : {}),\n mirror: mirror(agents, env),\n });\n await plane.start(context);\n return { roles, plane, close: (using) => plane.close(using) };\n },\n };\n}\n\nexport type { Rewound, Scoops } from './service.ts';\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/services.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/services.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n defineService,\n type JsonValue,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill';\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AgentRemoteService = defineService<AgentRemote>('slicc.agent.remote');\n\nexport const AGENT_SESSION = 'agent';\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected' | 'expired';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n group?: 'providers' | 'mcp';\n secret?: 'api-key' | 'token';\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string,\n region: string | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | null>;\n}\n\nexport const AgentSettings = defineService<AgentSettings>('slicc.agent.settings');\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEE;AAAA,OAGK;AA4IA,MAAM,eAAe,cAA4B,qBAAqB;AAuBtE,MAAM,kBAAkB,cAA+B,wBAAwB;AAO/E,MAAM,gBAAgB,cAA6B,sBAAsB;AAEzE,MAAM,qBAAqB,cAA2B,oBAAoB;AAE1E,MAAM,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n defineService,\n type JsonValue,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill';\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AgentRemoteService = defineService<AgentRemote>('slicc.agent.remote');\n\nexport const AGENT_SESSION = 'agent';\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected' | 'expired';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n group?: 'providers' | 'mcp';\n secret?: 'api-key' | 'token';\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface McpSignIn {\n url: string;\n state: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string,\n region: string | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;\n}\n\nexport const AgentSettings = defineService<AgentSettings>('slicc.agent.settings');\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEE;AAAA,OAGK;AA4IA,MAAM,eAAe,cAA4B,qBAAqB;AAuBtE,MAAM,kBAAkB,cAA+B,wBAAwB;AAO/E,MAAM,gBAAgB,cAA6B,sBAAsB;AAEzE,MAAM,qBAAqB,cAA2B,oBAAoB;AAE1E,MAAM,gBAAgB;AA2DtB,MAAM,gBAAgB,cAA6B,sBAAsB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/settings.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { replicatedState } from "@earendil-works/chord";
|
|
1
|
+
import { RemoteServiceError, replicatedState } from "@earendil-works/chord";
|
|
2
2
|
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
3
3
|
import { createModels } from "@earendil-works/pi-ai/models";
|
|
4
4
|
import { amazonBedrockProvider } from "@earendil-works/pi-ai/providers/amazon-bedrock";
|
|
@@ -62,6 +62,16 @@ function accounts(stored, providers) {
|
|
|
62
62
|
needs: corsFree.has(provider.id) ? "cors-free-transport" : null
|
|
63
63
|
}));
|
|
64
64
|
}
|
|
65
|
+
async function shown(run) {
|
|
66
|
+
try {
|
|
67
|
+
return await run();
|
|
68
|
+
} catch (error) {
|
|
69
|
+
throw new RemoteServiceError(
|
|
70
|
+
"service_invalid_value",
|
|
71
|
+
error instanceof Error ? error.message : String(error)
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
65
75
|
async function budget(credentials, usage) {
|
|
66
76
|
const credential = await credentials.read(ADOBE);
|
|
67
77
|
const key = credential?.type === "api_key" ? credential.key : void 0;
|
|
@@ -105,7 +115,7 @@ async function createAgentSettings(models, credentials, providers = sliccProvide
|
|
|
105
115
|
async connect(providerId, secret, region, context) {
|
|
106
116
|
const server = routed(providerId);
|
|
107
117
|
if (server) {
|
|
108
|
-
await server.connect(providerId, secret);
|
|
118
|
+
await shown(() => server.connect(providerId, secret));
|
|
109
119
|
await refresh(context);
|
|
110
120
|
return;
|
|
111
121
|
}
|
|
@@ -118,6 +128,8 @@ async function createAgentSettings(models, credentials, providers = sliccProvide
|
|
|
118
128
|
await refresh(context);
|
|
119
129
|
},
|
|
120
130
|
async signIn(providerId) {
|
|
131
|
+
const server = routed(providerId);
|
|
132
|
+
if (server) return shown(() => server.signIn(providerId));
|
|
121
133
|
if (providerId !== ADOBE) return null;
|
|
122
134
|
const { clientId, scopes, imsEnvironment } = await adobeConfig(
|
|
123
135
|
endpoint,
|
|
@@ -139,6 +151,7 @@ export {
|
|
|
139
151
|
DEFAULT_REGIONS,
|
|
140
152
|
createAgentSettings,
|
|
141
153
|
createSliccModels,
|
|
154
|
+
shown,
|
|
142
155
|
sliccProviders,
|
|
143
156
|
withDefaultRegions
|
|
144
157
|
};
|
package/dist/settings.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/settings.ts"],
|
|
4
|
-
"sourcesContent": ["import { type Context, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport { createModels, type MutableModels } from '@earendil-works/pi-ai/models';\nimport { amazonBedrockProvider } from '@earendil-works/pi-ai/providers/amazon-bedrock';\nimport {\n ADOBE,\n ADOBE_PROXY,\n adobeConfig,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nimport type { McpAccounts } from './mcp/index.ts';\nimport { MCP_ACCOUNT } from './mcp/label.ts';\nimport type { AccountState, AgentSettings, ModelChoice, SettingsState } from './services.ts';\n\nexport const BEDROCK = 'amazon-bedrock';\nexport const DEFAULT_MODEL = { provider: BEDROCK, modelId: 'us.anthropic.claude-sonnet-5-5' };\nexport const DEFAULT_REGIONS: Readonly<Record<string, string>> = { [BEDROCK]: 'us-west-2' };\n\nconst corsFree = new Set([BEDROCK, ADOBE]);\nconst signIn = new Set([ADOBE]);\nconst BUDGET_EVERY = 5 * 60 * 1000;\n\nexport function sliccProviders(): Provider[] {\n return [amazonBedrockProvider() as Provider, adobeProvider()];\n}\n\nexport function withDefaultRegions(credentials: CredentialStore): CredentialStore {\n return {\n async read(providerId, options) {\n const credential = await credentials.read(providerId, options);\n const region = DEFAULT_REGIONS[providerId];\n if (credential?.type !== 'api_key' || !region || credential.env?.AWS_REGION) {\n return credential;\n }\n return { ...credential, env: { ...credential.env, AWS_REGION: region } };\n },\n list: (options) => credentials.list(options),\n modify: (providerId, fn, options) => credentials.modify(providerId, fn, options),\n delete: (providerId, options) => credentials.delete(providerId, options),\n };\n}\n\nexport function createSliccModels(\n credentials: CredentialStore,\n providers = sliccProviders()\n): MutableModels {\n const models = createModels({ credentials: withDefaultRegions(credentials) });\n for (const provider of providers) models.setProvider(provider);\n return models;\n}\n\nfunction choices(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): ModelChoice[] {\n return providers\n .filter((provider) => stored.has(provider.id))\n .flatMap((provider) =>\n models.getModels(provider.id).map((model) => ({\n id: `${provider.id}/${model.id}`,\n label: model.name,\n provider: provider.name ?? provider.id,\n kind: 'chat' as const,\n reasoning: Boolean(model.reasoning),\n images: model.input.includes('image'),\n contextWindow: model.contextWindow,\n }))\n );\n}\n\nfunction accounts(stored: ReadonlySet<string>, providers: Provider[]): AccountState[] {\n return providers.map((provider) => ({\n id: provider.id,\n provider: provider.name ?? provider.id,\n identity: stored.has(provider.id) ? (signIn.has(provider.id) ? 'Adobe ID' : 'API key') : '',\n status: stored.has(provider.id) ? 'connected' : 'disconnected',\n auth: signIn.has(provider.id) ? 'oauth' : 'api-key',\n needs: corsFree.has(provider.id) ? 'cors-free-transport' : null,\n }));\n}\n\nexport type UsageReader = (token: string) => Promise<Budget | null>;\n\nasync function budget(credentials: CredentialStore, usage: UsageReader) {\n const credential = await credentials.read(ADOBE);\n const key = credential?.type === 'api_key' ? credential.key : undefined;\n const found = key ? await usage(key).catch(() => null) : null;\n return found ? { provider: ADOBE, ...found } : null;\n}\n\nexport async function createAgentSettings(\n models: MutableModels,\n credentials: CredentialStore,\n providers = sliccProviders(),\n options: { usage?: UsageReader; every?: number; mcp?: McpAccounts } = {}\n): Promise<AgentSettings> {\n const { mcp } = options;\n const routed = (providerId: string) => (providerId.startsWith(MCP_ACCOUNT) ? mcp : undefined);\n const endpoint = providers.find((provider) => provider.id === ADOBE)?.baseUrl ?? ADOBE_PROXY;\n const usage = options.usage ?? ((token: string) => adobeUsage(token, { endpoint }));\n const snapshot = async (): Promise<SettingsState> => {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\n return {\n models: choices(models, providers, stored),\n accounts: [...accounts(stored, providers), ...((await mcp?.accounts()) ?? [])],\n budget: await budget(credentials, usage),\n };\n };\n const state = replicatedState<SettingsState>(await snapshot());\n let latest = Promise.resolve();\n const refresh = (context: Context) => {\n const next = latest.then(async () => state.replace(context, await snapshot()));\n latest = next.catch(() => undefined);\n return next;\n };\n const signedIn = providers\n .filter((provider) => signIn.has(provider.id))\n .map((provider) => provider.id);\n const discover = (ids: string[]) =>\n models.refresh({ providers: ids }).then(\n () => undefined,\n () => undefined\n );\n if (signedIn.length) {\n const cycle = () =>\n void discover(signedIn)\n .then(() => refresh(BACKGROUND_CONTEXT))\n .catch(() => undefined);\n cycle();\n const timer: unknown = setInterval(cycle, options.every ?? BUDGET_EVERY);\n (timer as { unref?: () => void }).unref?.();\n }\n mcp?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => undefined));\n return {\n state,\n async connect(providerId, secret, region, context) {\n const server = routed(providerId);\n if (server) {\n await server.connect(providerId, secret);\n await refresh(context);\n return;\n }\n await credentials.modify(providerId, async () => ({\n type: 'api_key',\n key: secret,\n ...(region ? { env: { AWS_REGION: region } } : {}),\n }));\n if (signIn.has(providerId)) await discover([providerId]);\n await refresh(context);\n },\n async signIn(providerId) {\n if (providerId !== ADOBE) return null;\n const { clientId, scopes, imsEnvironment } = await adobeConfig(endpoint, (input, init) =>\n globalThis.fetch(input, init)\n );\n return { clientId, scopes, imsEnvironment: imsEnvironment || 'prod' };\n },\n async disconnect(providerId, context) {\n const server = routed(providerId);\n if (server) await server.disconnect(providerId);\n else await credentials.delete(providerId);\n await refresh(context);\n },\n };\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAuB,uBAAuB;
|
|
4
|
+
"sourcesContent": ["import { type Context, RemoteServiceError, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { CredentialStore, Provider } from '@earendil-works/pi-ai';\nimport { createModels, type MutableModels } from '@earendil-works/pi-ai/models';\nimport { amazonBedrockProvider } from '@earendil-works/pi-ai/providers/amazon-bedrock';\nimport {\n ADOBE,\n ADOBE_PROXY,\n adobeConfig,\n adobeProvider,\n adobeUsage,\n type Budget,\n} from './adobe.ts';\nimport type { McpAccounts } from './mcp/index.ts';\nimport { MCP_ACCOUNT } from './mcp/label.ts';\nimport type { AccountState, AgentSettings, ModelChoice, SettingsState } from './services.ts';\n\nexport const BEDROCK = 'amazon-bedrock';\nexport const DEFAULT_MODEL = { provider: BEDROCK, modelId: 'us.anthropic.claude-sonnet-5-5' };\nexport const DEFAULT_REGIONS: Readonly<Record<string, string>> = { [BEDROCK]: 'us-west-2' };\n\nconst corsFree = new Set([BEDROCK, ADOBE]);\nconst signIn = new Set([ADOBE]);\nconst BUDGET_EVERY = 5 * 60 * 1000;\n\nexport function sliccProviders(): Provider[] {\n return [amazonBedrockProvider() as Provider, adobeProvider()];\n}\n\nexport function withDefaultRegions(credentials: CredentialStore): CredentialStore {\n return {\n async read(providerId, options) {\n const credential = await credentials.read(providerId, options);\n const region = DEFAULT_REGIONS[providerId];\n if (credential?.type !== 'api_key' || !region || credential.env?.AWS_REGION) {\n return credential;\n }\n return { ...credential, env: { ...credential.env, AWS_REGION: region } };\n },\n list: (options) => credentials.list(options),\n modify: (providerId, fn, options) => credentials.modify(providerId, fn, options),\n delete: (providerId, options) => credentials.delete(providerId, options),\n };\n}\n\nexport function createSliccModels(\n credentials: CredentialStore,\n providers = sliccProviders()\n): MutableModels {\n const models = createModels({ credentials: withDefaultRegions(credentials) });\n for (const provider of providers) models.setProvider(provider);\n return models;\n}\n\nfunction choices(\n models: MutableModels,\n providers: Provider[],\n stored: ReadonlySet<string>\n): ModelChoice[] {\n return providers\n .filter((provider) => stored.has(provider.id))\n .flatMap((provider) =>\n models.getModels(provider.id).map((model) => ({\n id: `${provider.id}/${model.id}`,\n label: model.name,\n provider: provider.name ?? provider.id,\n kind: 'chat' as const,\n reasoning: Boolean(model.reasoning),\n images: model.input.includes('image'),\n contextWindow: model.contextWindow,\n }))\n );\n}\n\nfunction accounts(stored: ReadonlySet<string>, providers: Provider[]): AccountState[] {\n return providers.map((provider) => ({\n id: provider.id,\n provider: provider.name ?? provider.id,\n identity: stored.has(provider.id) ? (signIn.has(provider.id) ? 'Adobe ID' : 'API key') : '',\n status: stored.has(provider.id) ? 'connected' : 'disconnected',\n auth: signIn.has(provider.id) ? 'oauth' : 'api-key',\n needs: corsFree.has(provider.id) ? 'cors-free-transport' : null,\n }));\n}\n\nexport async function shown<T>(run: () => Promise<T>): Promise<T> {\n try {\n return await run();\n } catch (error) {\n throw new RemoteServiceError(\n 'service_invalid_value',\n error instanceof Error ? error.message : String(error)\n );\n }\n}\n\nexport type UsageReader = (token: string) => Promise<Budget | null>;\n\nasync function budget(credentials: CredentialStore, usage: UsageReader) {\n const credential = await credentials.read(ADOBE);\n const key = credential?.type === 'api_key' ? credential.key : undefined;\n const found = key ? await usage(key).catch(() => null) : null;\n return found ? { provider: ADOBE, ...found } : null;\n}\n\nexport async function createAgentSettings(\n models: MutableModels,\n credentials: CredentialStore,\n providers = sliccProviders(),\n options: { usage?: UsageReader; every?: number; mcp?: McpAccounts } = {}\n): Promise<AgentSettings> {\n const { mcp } = options;\n const routed = (providerId: string) => (providerId.startsWith(MCP_ACCOUNT) ? mcp : undefined);\n const endpoint = providers.find((provider) => provider.id === ADOBE)?.baseUrl ?? ADOBE_PROXY;\n const usage = options.usage ?? ((token: string) => adobeUsage(token, { endpoint }));\n const snapshot = async (): Promise<SettingsState> => {\n const stored = new Set((await credentials.list()).map((info) => info.providerId));\n return {\n models: choices(models, providers, stored),\n accounts: [...accounts(stored, providers), ...((await mcp?.accounts()) ?? [])],\n budget: await budget(credentials, usage),\n };\n };\n const state = replicatedState<SettingsState>(await snapshot());\n let latest = Promise.resolve();\n const refresh = (context: Context) => {\n const next = latest.then(async () => state.replace(context, await snapshot()));\n latest = next.catch(() => undefined);\n return next;\n };\n const signedIn = providers\n .filter((provider) => signIn.has(provider.id))\n .map((provider) => provider.id);\n const discover = (ids: string[]) =>\n models.refresh({ providers: ids }).then(\n () => undefined,\n () => undefined\n );\n if (signedIn.length) {\n const cycle = () =>\n void discover(signedIn)\n .then(() => refresh(BACKGROUND_CONTEXT))\n .catch(() => undefined);\n cycle();\n const timer: unknown = setInterval(cycle, options.every ?? BUDGET_EVERY);\n (timer as { unref?: () => void }).unref?.();\n }\n mcp?.onChange(() => void refresh(BACKGROUND_CONTEXT).catch(() => undefined));\n return {\n state,\n async connect(providerId, secret, region, context) {\n const server = routed(providerId);\n if (server) {\n await shown(() => server.connect(providerId, secret));\n await refresh(context);\n return;\n }\n await credentials.modify(providerId, async () => ({\n type: 'api_key',\n key: secret,\n ...(region ? { env: { AWS_REGION: region } } : {}),\n }));\n if (signIn.has(providerId)) await discover([providerId]);\n await refresh(context);\n },\n async signIn(providerId) {\n const server = routed(providerId);\n if (server) return shown(() => server.signIn(providerId));\n if (providerId !== ADOBE) return null;\n const { clientId, scopes, imsEnvironment } = await adobeConfig(endpoint, (input, init) =>\n globalThis.fetch(input, init)\n );\n return { clientId, scopes, imsEnvironment: imsEnvironment || 'prod' };\n },\n async disconnect(providerId, context) {\n const server = routed(providerId);\n if (server) await server.disconnect(providerId);\n else await credentials.delete(providerId);\n await refresh(context);\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAuB,oBAAoB,uBAAuB;AAClE,SAAS,0BAA0B;AAEnC,SAAS,oBAAwC;AACjD,SAAS,6BAA6B;AACtC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAEP,SAAS,mBAAmB;AAGrB,MAAM,UAAU;AAChB,MAAM,gBAAgB,EAAE,UAAU,SAAS,SAAS,iCAAiC;AACrF,MAAM,kBAAoD,EAAE,CAAC,OAAO,GAAG,YAAY;AAE1F,MAAM,WAAW,oBAAI,IAAI,CAAC,SAAS,KAAK,CAAC;AACzC,MAAM,SAAS,oBAAI,IAAI,CAAC,KAAK,CAAC;AAC9B,MAAM,eAAe,IAAI,KAAK;AAEvB,SAAS,iBAA6B;AAC3C,SAAO,CAAC,sBAAsB,GAAe,cAAc,CAAC;AAC9D;AAEO,SAAS,mBAAmB,aAA+C;AAChF,SAAO;AAAA,IACL,MAAM,KAAK,YAAY,SAAS;AAC9B,YAAM,aAAa,MAAM,YAAY,KAAK,YAAY,OAAO;AAC7D,YAAM,SAAS,gBAAgB,UAAU;AACzC,UAAI,YAAY,SAAS,aAAa,CAAC,UAAU,WAAW,KAAK,YAAY;AAC3E,eAAO;AAAA,MACT;AACA,aAAO,EAAE,GAAG,YAAY,KAAK,EAAE,GAAG,WAAW,KAAK,YAAY,OAAO,EAAE;AAAA,IACzE;AAAA,IACA,MAAM,CAAC,YAAY,YAAY,KAAK,OAAO;AAAA,IAC3C,QAAQ,CAAC,YAAY,IAAI,YAAY,YAAY,OAAO,YAAY,IAAI,OAAO;AAAA,IAC/E,QAAQ,CAAC,YAAY,YAAY,YAAY,OAAO,YAAY,OAAO;AAAA,EACzE;AACF;AAEO,SAAS,kBACd,aACA,YAAY,eAAe,GACZ;AACf,QAAM,SAAS,aAAa,EAAE,aAAa,mBAAmB,WAAW,EAAE,CAAC;AAC5E,aAAW,YAAY,UAAW,QAAO,YAAY,QAAQ;AAC7D,SAAO;AACT;AAEA,SAAS,QACP,QACA,WACA,QACe;AACf,SAAO,UACJ,OAAO,CAAC,aAAa,OAAO,IAAI,SAAS,EAAE,CAAC,EAC5C;AAAA,IAAQ,CAAC,aACR,OAAO,UAAU,SAAS,EAAE,EAAE,IAAI,CAAC,WAAW;AAAA,MAC5C,IAAI,GAAG,SAAS,EAAE,IAAI,MAAM,EAAE;AAAA,MAC9B,OAAO,MAAM;AAAA,MACb,UAAU,SAAS,QAAQ,SAAS;AAAA,MACpC,MAAM;AAAA,MACN,WAAW,QAAQ,MAAM,SAAS;AAAA,MAClC,QAAQ,MAAM,MAAM,SAAS,OAAO;AAAA,MACpC,eAAe,MAAM;AAAA,IACvB,EAAE;AAAA,EACJ;AACJ;AAEA,SAAS,SAAS,QAA6B,WAAuC;AACpF,SAAO,UAAU,IAAI,CAAC,cAAc;AAAA,IAClC,IAAI,SAAS;AAAA,IACb,UAAU,SAAS,QAAQ,SAAS;AAAA,IACpC,UAAU,OAAO,IAAI,SAAS,EAAE,IAAK,OAAO,IAAI,SAAS,EAAE,IAAI,aAAa,YAAa;AAAA,IACzF,QAAQ,OAAO,IAAI,SAAS,EAAE,IAAI,cAAc;AAAA,IAChD,MAAM,OAAO,IAAI,SAAS,EAAE,IAAI,UAAU;AAAA,IAC1C,OAAO,SAAS,IAAI,SAAS,EAAE,IAAI,wBAAwB;AAAA,EAC7D,EAAE;AACJ;AAEA,eAAsB,MAAS,KAAmC;AAChE,MAAI;AACF,WAAO,MAAM,IAAI;AAAA,EACnB,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR;AAAA,MACA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IACvD;AAAA,EACF;AACF;AAIA,eAAe,OAAO,aAA8B,OAAoB;AACtE,QAAM,aAAa,MAAM,YAAY,KAAK,KAAK;AAC/C,QAAM,MAAM,YAAY,SAAS,YAAY,WAAW,MAAM;AAC9D,QAAM,QAAQ,MAAM,MAAM,MAAM,GAAG,EAAE,MAAM,MAAM,IAAI,IAAI;AACzD,SAAO,QAAQ,EAAE,UAAU,OAAO,GAAG,MAAM,IAAI;AACjD;AAEA,eAAsB,oBACpB,QACA,aACA,YAAY,eAAe,GAC3B,UAAsE,CAAC,GAC/C;AACxB,QAAM,EAAE,IAAI,IAAI;AAChB,QAAM,SAAS,CAAC,eAAwB,WAAW,WAAW,WAAW,IAAI,MAAM;AACnF,QAAM,WAAW,UAAU,KAAK,CAAC,aAAa,SAAS,OAAO,KAAK,GAAG,WAAW;AACjF,QAAM,QAAQ,QAAQ,UAAU,CAAC,UAAkB,WAAW,OAAO,EAAE,SAAS,CAAC;AACjF,QAAM,WAAW,YAAoC;AACnD,UAAM,SAAS,IAAI,KAAK,MAAM,YAAY,KAAK,GAAG,IAAI,CAAC,SAAS,KAAK,UAAU,CAAC;AAChF,WAAO;AAAA,MACL,QAAQ,QAAQ,QAAQ,WAAW,MAAM;AAAA,MACzC,UAAU,CAAC,GAAG,SAAS,QAAQ,SAAS,GAAG,GAAK,MAAM,KAAK,SAAS,KAAM,CAAC,CAAE;AAAA,MAC7E,QAAQ,MAAM,OAAO,aAAa,KAAK;AAAA,IACzC;AAAA,EACF;AACA,QAAM,QAAQ,gBAA+B,MAAM,SAAS,CAAC;AAC7D,MAAI,SAAS,QAAQ,QAAQ;AAC7B,QAAM,UAAU,CAAC,YAAqB;AACpC,UAAM,OAAO,OAAO,KAAK,YAAY,MAAM,QAAQ,SAAS,MAAM,SAAS,CAAC,CAAC;AAC7E,aAAS,KAAK,MAAM,MAAM,MAAS;AACnC,WAAO;AAAA,EACT;AACA,QAAM,WAAW,UACd,OAAO,CAAC,aAAa,OAAO,IAAI,SAAS,EAAE,CAAC,EAC5C,IAAI,CAAC,aAAa,SAAS,EAAE;AAChC,QAAM,WAAW,CAAC,QAChB,OAAO,QAAQ,EAAE,WAAW,IAAI,CAAC,EAAE;AAAA,IACjC,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF,MAAI,SAAS,QAAQ;AACnB,UAAM,QAAQ,MACZ,KAAK,SAAS,QAAQ,EACnB,KAAK,MAAM,QAAQ,kBAAkB,CAAC,EACtC,MAAM,MAAM,MAAS;AAC1B,UAAM;AACN,UAAM,QAAiB,YAAY,OAAO,QAAQ,SAAS,YAAY;AACvE,IAAC,MAAiC,QAAQ;AAAA,EAC5C;AACA,OAAK,SAAS,MAAM,KAAK,QAAQ,kBAAkB,EAAE,MAAM,MAAM,MAAS,CAAC;AAC3E,SAAO;AAAA,IACL;AAAA,IACA,MAAM,QAAQ,YAAY,QAAQ,QAAQ,SAAS;AACjD,YAAM,SAAS,OAAO,UAAU;AAChC,UAAI,QAAQ;AACV,cAAM,MAAM,MAAM,OAAO,QAAQ,YAAY,MAAM,CAAC;AACpD,cAAM,QAAQ,OAAO;AACrB;AAAA,MACF;AACA,YAAM,YAAY,OAAO,YAAY,aAAa;AAAA,QAChD,MAAM;AAAA,QACN,KAAK;AAAA,QACL,GAAI,SAAS,EAAE,KAAK,EAAE,YAAY,OAAO,EAAE,IAAI,CAAC;AAAA,MAClD,EAAE;AACF,UAAI,OAAO,IAAI,UAAU,EAAG,OAAM,SAAS,CAAC,UAAU,CAAC;AACvD,YAAM,QAAQ,OAAO;AAAA,IACvB;AAAA,IACA,MAAM,OAAO,YAAY;AACvB,YAAM,SAAS,OAAO,UAAU;AAChC,UAAI,OAAQ,QAAO,MAAM,MAAM,OAAO,OAAO,UAAU,CAAC;AACxD,UAAI,eAAe,MAAO,QAAO;AACjC,YAAM,EAAE,UAAU,QAAQ,eAAe,IAAI,MAAM;AAAA,QAAY;AAAA,QAAU,CAAC,OAAO,SAC/E,WAAW,MAAM,OAAO,IAAI;AAAA,MAC9B;AACA,aAAO,EAAE,UAAU,QAAQ,gBAAgB,kBAAkB,OAAO;AAAA,IACtE;AAAA,IACA,MAAM,WAAW,YAAY,SAAS;AACpC,YAAM,SAAS,OAAO,UAAU;AAChC,UAAI,OAAQ,OAAM,OAAO,WAAW,UAAU;AAAA,UACzC,OAAM,YAAY,OAAO,UAAU;AACxC,YAAM,QAAQ,OAAO;AAAA,IACvB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
const MCP_CHANNEL = "slicc-mcp-oauth";
|
|
2
|
+
const MCP_NAME_KEY = "slicc-mcp-oauth:";
|
|
3
|
+
const SIGN_IN_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
4
|
+
const browser = {
|
|
5
|
+
open: () => globalThis.open?.("about:blank", "slicc-mcp-oauth", "popup,width=520,height=720") ?? null,
|
|
6
|
+
channel: () => new BroadcastChannel(MCP_CHANNEL),
|
|
7
|
+
remember: (state, name) => {
|
|
8
|
+
const key = `${MCP_NAME_KEY}${state}`;
|
|
9
|
+
if (name === null) globalThis.localStorage?.removeItem(key);
|
|
10
|
+
else globalThis.localStorage?.setItem(key, name);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const LOOPBACK = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
14
|
+
function safeAuthorizationUrl(value) {
|
|
15
|
+
if (!URL.canParse(value)) return false;
|
|
16
|
+
const url = new URL(value);
|
|
17
|
+
return url.protocol === "https:" || url.protocol === "http:" && LOOPBACK.has(url.hostname);
|
|
18
|
+
}
|
|
19
|
+
function answered(channel, state, signal, timeoutMs) {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const done = () => {
|
|
22
|
+
clearTimeout(timer);
|
|
23
|
+
signal.removeEventListener("abort", stop);
|
|
24
|
+
};
|
|
25
|
+
const stop = () => {
|
|
26
|
+
done();
|
|
27
|
+
reject(signal.reason);
|
|
28
|
+
};
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
done();
|
|
31
|
+
reject(new Error("the sign-in window gave no answer; try again"));
|
|
32
|
+
}, timeoutMs);
|
|
33
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
34
|
+
channel.onmessage = ({ data }) => {
|
|
35
|
+
const answer = data;
|
|
36
|
+
if (answer?.state !== state) return;
|
|
37
|
+
done();
|
|
38
|
+
resolve(JSON.stringify(answer));
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function mcpLogin(host = browser) {
|
|
43
|
+
return async (providerId, signIn, options) => {
|
|
44
|
+
const popup = host.open();
|
|
45
|
+
const channel = host.channel();
|
|
46
|
+
let state;
|
|
47
|
+
try {
|
|
48
|
+
const started = await signIn();
|
|
49
|
+
options.signal.throwIfAborted();
|
|
50
|
+
if (!started?.url) throw new Error("this MCP server has no sign-in");
|
|
51
|
+
if (!safeAuthorizationUrl(started.url))
|
|
52
|
+
throw new Error("the authorization server gave a sign-in address that is not https");
|
|
53
|
+
if (!popup)
|
|
54
|
+
throw new Error("the browser blocked the sign-in window; allow pop-ups for SLICC");
|
|
55
|
+
state = started.state;
|
|
56
|
+
host.remember?.(state, providerId.replace(/^mcp:/, ""));
|
|
57
|
+
popup.location.href = started.url;
|
|
58
|
+
return await answered(channel, state, options.signal, host.timeoutMs ?? SIGN_IN_TIMEOUT_MS);
|
|
59
|
+
} finally {
|
|
60
|
+
if (state) host.remember?.(state, null);
|
|
61
|
+
channel.close();
|
|
62
|
+
popup?.close();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
MCP_CHANNEL,
|
|
68
|
+
MCP_NAME_KEY,
|
|
69
|
+
SIGN_IN_TIMEOUT_MS,
|
|
70
|
+
mcpLogin,
|
|
71
|
+
safeAuthorizationUrl
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=mcp-login.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/spectrum/mcp-login.ts"],
|
|
4
|
+
"sourcesContent": ["import type { McpSignIn, SignIn } from '../services.ts';\n\nexport const MCP_CHANNEL = 'slicc-mcp-oauth';\nexport const MCP_NAME_KEY = 'slicc-mcp-oauth:';\nexport const SIGN_IN_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface Popup {\n location: { href: string };\n close(): void;\n}\n\nexport interface Channel {\n onmessage: ((event: { data: unknown }) => void) | null;\n close(): void;\n}\n\nexport interface McpLoginHost {\n open(): Popup | null;\n channel(): Channel;\n remember?(state: string, name: string | null): void;\n timeoutMs?: number;\n}\n\nconst browser: McpLoginHost = {\n open: () =>\n globalThis.open?.('about:blank', 'slicc-mcp-oauth', 'popup,width=520,height=720') ?? null,\n channel: () => new BroadcastChannel(MCP_CHANNEL) as unknown as Channel,\n remember: (state, name) => {\n const key = `${MCP_NAME_KEY}${state}`;\n if (name === null) globalThis.localStorage?.removeItem(key);\n else globalThis.localStorage?.setItem(key, name);\n },\n};\n\nconst LOOPBACK = new Set(['localhost', '127.0.0.1', '[::1]']);\n\nexport function safeAuthorizationUrl(value: string): boolean {\n if (!URL.canParse(value)) return false;\n const url = new URL(value);\n return url.protocol === 'https:' || (url.protocol === 'http:' && LOOPBACK.has(url.hostname));\n}\n\nfunction answered(channel: Channel, state: string, signal: AbortSignal, timeoutMs: number) {\n return new Promise<string>((resolve, reject) => {\n const done = () => {\n clearTimeout(timer);\n signal.removeEventListener('abort', stop);\n };\n const stop = () => {\n done();\n reject(signal.reason);\n };\n const timer = setTimeout(() => {\n done();\n reject(new Error('the sign-in window gave no answer; try again'));\n }, timeoutMs);\n signal.addEventListener('abort', stop, { once: true });\n channel.onmessage = ({ data }) => {\n const answer = data as { state?: unknown } | null;\n if (answer?.state !== state) return;\n done();\n resolve(JSON.stringify(answer));\n };\n });\n}\n\nexport function mcpLogin(host: McpLoginHost = browser) {\n return async (\n providerId: string,\n signIn: () => Promise<SignIn | McpSignIn | null>,\n options: { signal: AbortSignal }\n ): Promise<string> => {\n const popup = host.open();\n const channel = host.channel();\n let state: string | undefined;\n try {\n const started = (await signIn()) as McpSignIn | null;\n options.signal.throwIfAborted();\n if (!started?.url) throw new Error('this MCP server has no sign-in');\n if (!safeAuthorizationUrl(started.url))\n throw new Error('the authorization server gave a sign-in address that is not https');\n if (!popup)\n throw new Error('the browser blocked the sign-in window; allow pop-ups for SLICC');\n state = started.state;\n host.remember?.(state, providerId.replace(/^mcp:/, ''));\n popup.location.href = started.url;\n return await answered(channel, state, options.signal, host.timeoutMs ?? SIGN_IN_TIMEOUT_MS);\n } finally {\n if (state) host.remember?.(state, null);\n channel.close();\n popup?.close();\n }\n };\n}\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,cAAc;AACpB,MAAM,eAAe;AACrB,MAAM,qBAAqB,IAAI,KAAK;AAmB3C,MAAM,UAAwB;AAAA,EAC5B,MAAM,MACJ,WAAW,OAAO,eAAe,mBAAmB,4BAA4B,KAAK;AAAA,EACvF,SAAS,MAAM,IAAI,iBAAiB,WAAW;AAAA,EAC/C,UAAU,CAAC,OAAO,SAAS;AACzB,UAAM,MAAM,GAAG,YAAY,GAAG,KAAK;AACnC,QAAI,SAAS,KAAM,YAAW,cAAc,WAAW,GAAG;AAAA,QACrD,YAAW,cAAc,QAAQ,KAAK,IAAI;AAAA,EACjD;AACF;AAEA,MAAM,WAAW,oBAAI,IAAI,CAAC,aAAa,aAAa,OAAO,CAAC;AAErD,SAAS,qBAAqB,OAAwB;AAC3D,MAAI,CAAC,IAAI,SAAS,KAAK,EAAG,QAAO;AACjC,QAAM,MAAM,IAAI,IAAI,KAAK;AACzB,SAAO,IAAI,aAAa,YAAa,IAAI,aAAa,WAAW,SAAS,IAAI,IAAI,QAAQ;AAC5F;AAEA,SAAS,SAAS,SAAkB,OAAe,QAAqB,WAAmB;AACzF,SAAO,IAAI,QAAgB,CAAC,SAAS,WAAW;AAC9C,UAAM,OAAO,MAAM;AACjB,mBAAa,KAAK;AAClB,aAAO,oBAAoB,SAAS,IAAI;AAAA,IAC1C;AACA,UAAM,OAAO,MAAM;AACjB,WAAK;AACL,aAAO,OAAO,MAAM;AAAA,IACtB;AACA,UAAM,QAAQ,WAAW,MAAM;AAC7B,WAAK;AACL,aAAO,IAAI,MAAM,8CAA8C,CAAC;AAAA,IAClE,GAAG,SAAS;AACZ,WAAO,iBAAiB,SAAS,MAAM,EAAE,MAAM,KAAK,CAAC;AACrD,YAAQ,YAAY,CAAC,EAAE,KAAK,MAAM;AAChC,YAAM,SAAS;AACf,UAAI,QAAQ,UAAU,MAAO;AAC7B,WAAK;AACL,cAAQ,KAAK,UAAU,MAAM,CAAC;AAAA,IAChC;AAAA,EACF,CAAC;AACH;AAEO,SAAS,SAAS,OAAqB,SAAS;AACrD,SAAO,OACL,YACA,QACA,YACoB;AACpB,UAAM,QAAQ,KAAK,KAAK;AACxB,UAAM,UAAU,KAAK,QAAQ;AAC7B,QAAI;AACJ,QAAI;AACF,YAAM,UAAW,MAAM,OAAO;AAC9B,cAAQ,OAAO,eAAe;AAC9B,UAAI,CAAC,SAAS,IAAK,OAAM,IAAI,MAAM,gCAAgC;AACnE,UAAI,CAAC,qBAAqB,QAAQ,GAAG;AACnC,cAAM,IAAI,MAAM,mEAAmE;AACrF,UAAI,CAAC;AACH,cAAM,IAAI,MAAM,iEAAiE;AACnF,cAAQ,QAAQ;AAChB,WAAK,WAAW,OAAO,WAAW,QAAQ,SAAS,EAAE,CAAC;AACtD,YAAM,SAAS,OAAO,QAAQ;AAC9B,aAAO,MAAM,SAAS,SAAS,OAAO,QAAQ,QAAQ,KAAK,aAAa,kBAAkB;AAAA,IAC5F,UAAE;AACA,UAAI,MAAO,MAAK,WAAW,OAAO,IAAI;AACtC,cAAQ,MAAM;AACd,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
2
|
import { Emitter } from "./emitter.js";
|
|
3
|
+
import { mcpLogin } from "./mcp-login.js";
|
|
3
4
|
const SETTINGS_KEY = "slicc-agent.settings";
|
|
4
5
|
const defaults = {
|
|
5
6
|
color: "system",
|
|
@@ -14,10 +15,12 @@ class SettingsAdapter extends Emitter {
|
|
|
14
15
|
#agent;
|
|
15
16
|
#storage;
|
|
16
17
|
#login;
|
|
18
|
+
#mcpLogin;
|
|
17
19
|
#signing = /* @__PURE__ */ new Map();
|
|
18
20
|
#local;
|
|
19
|
-
constructor(settings, agent, storage, login = null) {
|
|
21
|
+
constructor(settings, agent, storage, login = null, mcp = mcpLogin()) {
|
|
20
22
|
super();
|
|
23
|
+
this.#mcpLogin = mcp;
|
|
21
24
|
this.#settings = settings;
|
|
22
25
|
this.#agent = agent;
|
|
23
26
|
this.#storage = storage;
|
|
@@ -65,7 +68,7 @@ class SettingsAdapter extends Emitter {
|
|
|
65
68
|
}
|
|
66
69
|
async connect(id, secret, options = {}) {
|
|
67
70
|
const account = this.#state().accounts.find((candidate) => candidate.id === id);
|
|
68
|
-
const login = account?.auth
|
|
71
|
+
const login = account?.auth !== "oauth" ? null : account.group === "mcp" ? this.#mcpLogin : this.#login;
|
|
69
72
|
const key = secret ?? (login ? await this.#signIn(id, login) : void 0);
|
|
70
73
|
if (!key)
|
|
71
74
|
throw new Error(`${id} needs ${account?.auth === "oauth" ? "a sign-in" : "an API key"}`);
|
|
@@ -77,9 +80,13 @@ class SettingsAdapter extends Emitter {
|
|
|
77
80
|
this.#signing.set(id, controller);
|
|
78
81
|
this.emit("accounts", this.accounts());
|
|
79
82
|
try {
|
|
80
|
-
const key = await login(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
const key = await login(
|
|
84
|
+
id,
|
|
85
|
+
() => this.#settings.signIn(id, BACKGROUND_CONTEXT),
|
|
86
|
+
{
|
|
87
|
+
signal: controller.signal
|
|
88
|
+
}
|
|
89
|
+
);
|
|
83
90
|
controller.signal.throwIfAborted();
|
|
84
91
|
return key;
|
|
85
92
|
} finally {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/spectrum/settings-port.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { AgentSettings, SettingsState, SignIn } from '../services.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { Emitter } from './emitter.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Login = (\n providerId: string,\n signIn: () => Promise<SignIn | null>,\n options: { signal: AbortSignal }\n) => Promise<string>;\n\nexport class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n readonly #signing = new Map<string, AbortController>();\n #local: Local;\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null\n ) {\n super();\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n settings.state.subscribe(() => {\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n return this.#state().models.map(({ id, label, provider, kind, reasoning, images }) => ({\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n }));\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) => {\n const shown = this.#signing.has(account.id)\n ? { ...account, status: 'signing-in' as const }\n : account;\n return needs ? { ...shown, needs } : shown;\n });\n }\n\n async connect(id: string, secret?: string, options: { region?: string } = {}): Promise<void> {\n const account = this.#state().accounts.find((candidate) => candidate.id === id);\n const login
|
|
5
|
-
"mappings": "AAOA,SAAS,0BAA0B;AAGnC,SAAS,eAAe;
|
|
4
|
+
"sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { AgentSettings, SettingsState, SignIn } from '../services.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { Emitter } from './emitter.ts';\nimport { mcpLogin } from './mcp-login.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Login = (\n providerId: string,\n signIn: () => Promise<SignIn | null>,\n options: { signal: AbortSignal }\n) => Promise<string>;\n\nexport class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n readonly #mcpLogin: Login;\n readonly #signing = new Map<string, AbortController>();\n #local: Local;\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null,\n mcp: Login = mcpLogin() as Login\n ) {\n super();\n this.#mcpLogin = mcp;\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n settings.state.subscribe(() => {\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n return this.#state().models.map(({ id, label, provider, kind, reasoning, images }) => ({\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n }));\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) => {\n const shown = this.#signing.has(account.id)\n ? { ...account, status: 'signing-in' as const }\n : account;\n return needs ? { ...shown, needs } : shown;\n });\n }\n\n async connect(id: string, secret?: string, options: { region?: string } = {}): Promise<void> {\n const account = this.#state().accounts.find((candidate) => candidate.id === id);\n const login =\n account?.auth !== 'oauth' ? null : account.group === 'mcp' ? this.#mcpLogin : this.#login;\n const key = secret ?? (login ? await this.#signIn(id, login) : undefined);\n if (!key)\n throw new Error(`${id} needs ${account?.auth === 'oauth' ? 'a sign-in' : 'an API key'}`);\n await this.#settings.connect(id, key, options.region ?? null, BACKGROUND_CONTEXT);\n }\n\n async #signIn(id: string, login: Login): Promise<string> {\n const controller = new AbortController();\n this.#signing\n .get(id)\n ?.abort(new DOMException('A newer sign-in replaced this one.', 'AbortError'));\n this.#signing.set(id, controller);\n this.emit('accounts', this.accounts());\n try {\n const key = await login(\n id,\n () => this.#settings.signIn(id, BACKGROUND_CONTEXT) as Promise<SignIn | null>,\n {\n signal: controller.signal,\n }\n );\n controller.signal.throwIfAborted();\n return key;\n } finally {\n if (this.#signing.get(id) === controller) this.#signing.delete(id);\n this.emit('accounts', this.accounts());\n }\n }\n\n cancel(id: string): void {\n const controller = this.#signing.get(id);\n if (!controller) return;\n this.#signing.delete(id);\n controller.abort(new DOMException('The sign-in was cancelled.', 'AbortError'));\n this.emit('accounts', this.accounts());\n }\n\n disconnect(id: string): void {\n void this.#settings.disconnect(id, BACKGROUND_CONTEXT);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/types/host.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Agent } from './agent.ts';
|
|
|
3
3
|
import type { ChangesRuntime } from './changes/index.ts';
|
|
4
4
|
import { type HostLicks, type HostScoops } from './control.ts';
|
|
5
5
|
import type { FreezerRuntime } from './freezer/index.ts';
|
|
6
|
+
import type { UserClients } from './kernel/users.ts';
|
|
6
7
|
import type { McpRuntime } from './mcp/index.ts';
|
|
7
8
|
import type { MemoryRuntime } from './memory/index.ts';
|
|
8
9
|
import { AgentSettings } from './services.ts';
|
|
@@ -12,6 +13,7 @@ import type { PortEndpoint } from './wire.ts';
|
|
|
12
13
|
export interface AgentHost {
|
|
13
14
|
readonly serverId: string;
|
|
14
15
|
readonly agent: Agent;
|
|
16
|
+
readonly users?: UserClients;
|
|
15
17
|
connect(endpoint: PortEndpoint, options?: {
|
|
16
18
|
readOnly?: boolean;
|
|
17
19
|
}): void;
|
|
@@ -29,4 +31,5 @@ export declare function hostAgent(agent: Agent, options?: {
|
|
|
29
31
|
freezer?: FreezerRuntime;
|
|
30
32
|
changes?: ChangesRuntime;
|
|
31
33
|
mcp?: Pick<McpRuntime, 'close'>;
|
|
34
|
+
users?: UserClients;
|
|
32
35
|
}): Promise<AgentHost>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -6,10 +6,11 @@ export { CREDENTIALS_DATABASE, EncryptedCredentialStore } from './credentials.ts
|
|
|
6
6
|
export { type AgentHost, hostAgent } from './host.ts';
|
|
7
7
|
export type { KernelClient, KernelFs, KernelProcess, KernelStat, SpawnOptions, } from './kernel/client.ts';
|
|
8
8
|
export { HOME, type KernelEnvOptions, kernelEnvironment, SliccKernelEnv } from './kernel/env.ts';
|
|
9
|
+
export { adminOver, type KernelAdmin, type KernelUser, type KernelUsers, serveAdmin, type UserClient, type UserClients, type UserConnect, type UserSpec, userClients, } from './kernel/users.ts';
|
|
9
10
|
export { PortListener } from './listener.ts';
|
|
10
11
|
export { type AgentWorkerOptions, type AgentWorkerScope, type KernelAttach, runAgentWorker, } from './main.ts';
|
|
11
12
|
export { type Transport, type TransportResponse, transportFetch } from './net.ts';
|
|
12
|
-
export { AGENT_LOCK, type AgentOwner, type AgentWorker, type OwnerOptions, startAgent, } from './owner.ts';
|
|
13
|
+
export { AGENT_LOCK, type AgentOwner, type AgentWorker, type KernelSource, type OwnerOptions, startAgent, } from './owner.ts';
|
|
13
14
|
export { applyPatches, patchServerAccept } from './patches.ts';
|
|
14
15
|
export { SliccPrompt, sliccPrompt } from './prompt.ts';
|
|
15
16
|
export { type AccountState, AGENT_SESSION, AgentControl, AgentSessions, AgentSettings, type AgentSettingsChange, AgentTranscript, type BudgetState, type ModelChoice, type OperationError, type PromptResult, type SendMode, type SendRequest, type SendResponse, type SettingsState, type SignIn, } from './services.ts';
|
|
@@ -17,4 +18,4 @@ export { BEDROCK, createAgentSettings, createSliccModels, DEFAULT_MODEL, DEFAULT
|
|
|
17
18
|
export { AGENT_DIRECTORY, type OpfsSqliteOptions, openMemorySqliteStorage, openOpfsSqliteStorage, WasmSqliteDatabase, } from './sqlite.ts';
|
|
18
19
|
export { type SystemFacts, systemSection } from './system.ts';
|
|
19
20
|
export { PortChannel, type PortEndpoint, withUnrefTimers } from './wire.ts';
|
|
20
|
-
export { kernelPort, serveConnections, type WorkerScope } from './worker.ts';
|
|
21
|
+
export { type KernelPorts, kernelPort, kernelPorts, serveConnections, type WorkerScope, } from './worker.ts';
|