@agentconnect.md/daemon 1.0.0-rc.239 → 1.0.0-rc.240
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/dist/{acp-host-BADva9E0.js → acp-host-M9PGQrVJ.js} +4 -47
- package/dist/acp-host-M9PGQrVJ.js.map +1 -0
- package/dist/{chat-C1jdOMwG.js → chat-CeThir-Y.js} +2 -2
- package/dist/{chat-C1jdOMwG.js.map → chat-CeThir-Y.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/{login-DAAg53hd.js → login-CoeR7Gr0.js} +3 -3
- package/dist/{login-DAAg53hd.js.map → login-CoeR7Gr0.js.map} +1 -1
- package/dist/run-foreground-B8NoERhV.js +2 -0
- package/dist/{run-foreground-C4Ip8lzS.js → run-foreground-Cdxkfe7g.js} +149 -107
- package/dist/{run-foreground-C4Ip8lzS.js.map → run-foreground-Cdxkfe7g.js.map} +1 -1
- package/package.json +1 -1
- package/dist/acp-host-BADva9E0.js.map +0 -1
- package/dist/run-foreground-Dd5XN9F6.js +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as agentChildEnv, i as selectAgent, o as loadConfig } from "./load-agents-C3pJSVeT.js";
|
|
2
2
|
import { l as resolveRoot } from "./paths-DEcUO8lC.js";
|
|
3
|
-
import { C as resolveRuntimes, i as prepareWorkspace, t as AcpHost } from "./acp-host-
|
|
3
|
+
import { C as resolveRuntimes, i as prepareWorkspace, t as AcpHost } from "./acp-host-M9PGQrVJ.js";
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
5
|
//#region src/cli/chat.ts
|
|
6
6
|
function renderUpdate(out) {
|
|
@@ -76,4 +76,4 @@ async function runChat(opts) {
|
|
|
76
76
|
//#endregion
|
|
77
77
|
export { renderUpdate, runChat };
|
|
78
78
|
|
|
79
|
-
//# sourceMappingURL=chat-
|
|
79
|
+
//# sourceMappingURL=chat-CeThir-Y.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-
|
|
1
|
+
{"version":3,"file":"chat-CeThir-Y.js","names":[],"sources":["../src/cli/chat.ts"],"sourcesContent":["import { createInterface } from 'node:readline'\nimport type { ContentBlock, SessionUpdate } from '@agentclientprotocol/sdk'\nimport { loadConfig } from '../config/load-config.js'\nimport { resolveRuntimes } from '../runtimes/registry.js'\nimport { selectAgent } from '../agents/load-agents.js'\nimport { agentChildEnv } from '../agents/agent-env.js'\nimport { prepareWorkspace } from '../workspace/workspace-manager.js'\nimport { AcpHost } from '../acp/acp-host.js'\nimport { resolveRoot } from '../paths.js'\n\nexport function renderUpdate(out: NodeJS.WritableStream) {\n return (_sessionId: string, update: SessionUpdate): void => {\n if (update.sessionUpdate === 'agent_message_chunk' && update.content.type === 'text') {\n out.write(update.content.text)\n } else if (update.sessionUpdate === 'tool_call') {\n const title = ('title' in update && update.title) || update.toolCallId || 'tool'\n out.write(`\\n[tool] ${title}\\n`)\n }\n }\n}\n\nexport interface RunChatOpts {\n agentsDir?: string\n agentName?: string\n message?: string\n configPath?: string\n root?: string\n out?: NodeJS.WritableStream\n input?: NodeJS.ReadableStream\n}\n\nexport async function runChat(opts: RunChatOpts): Promise<void> {\n const out = opts.out ?? process.stdout\n const root = resolveRoot(opts.root)\n const cfg = loadConfig({\n root: opts.root,\n configPath: opts.configPath,\n optional: true,\n overrides: { agentsDir: opts.agentsDir }\n })\n const agent = selectAgent(cfg.agentsDir!, opts.agentName)\n\n const runtimes = await resolveRuntimes(cfg, root, { neededRuntimes: [agent.runtime], mode: 'cache-first' })\n const runtime = runtimes[agent.runtime]\n if (!runtime) {\n const available = Object.keys(runtimes).sort().join(', ') || '(none)'\n throw new Error(`runtime \"${agent.runtime}\" not found. Available: ${available}`)\n }\n\n const host = new AcpHost(runtime, {\n onUpdate: renderUpdate(out),\n env: agentChildEnv(agent),\n configPrefs: {\n model: agent.runtimeOverrides?.model,\n permissionMode: agent.permissionMode,\n reasoningEffort: agent.reasoningEffort,\n fastMode: agent.fastMode\n }\n })\n await host.start()\n try {\n const cwd = await prepareWorkspace(agent)\n const sessionId = await host.newSession(cwd)\n\n const send = async (text: string) => {\n const blocks: ContentBlock[] = [{ type: 'text', text }]\n await host.prompt(sessionId, blocks)\n out.write('\\n')\n }\n\n if (typeof opts.message === 'string' && opts.message.length > 0) {\n await send(opts.message)\n return\n }\n\n const rl = createInterface({ input: opts.input ?? process.stdin })\n out.write(`Chatting with ${agent.name} (${agent.id}). Type .exit to quit.\\n> `)\n try {\n for await (const line of rl) {\n const text = line.trim()\n if (text === '.exit' || text === '.quit') break\n if (text.length > 0) await send(text)\n out.write('> ')\n }\n } finally {\n rl.close()\n }\n } finally {\n await host.stop()\n }\n}\n"],"mappings":";;;;;AAUA,SAAgB,aAAa,KAA4B;CACvD,QAAQ,YAAoB,WAAgC;EAC1D,IAAI,OAAO,kBAAkB,yBAAyB,OAAO,QAAQ,SAAS,QAC5E,IAAI,MAAM,OAAO,QAAQ,IAAI;OACxB,IAAI,OAAO,kBAAkB,aAAa;GAC/C,MAAM,QAAS,WAAW,UAAU,OAAO,SAAU,OAAO,cAAc;GAC1E,IAAI,MAAM,YAAY,MAAM,GAAG;EACjC;CACF;AACF;AAYA,eAAsB,QAAQ,MAAkC;CAC9D,MAAM,MAAM,KAAK,OAAO,QAAQ;CAChC,MAAM,OAAO,YAAY,KAAK,IAAI;CAClC,MAAM,MAAM,WAAW;EACrB,MAAM,KAAK;EACX,YAAY,KAAK;EACjB,UAAU;EACV,WAAW,EAAE,WAAW,KAAK,UAAU;CACzC,CAAC;CACD,MAAM,QAAQ,YAAY,IAAI,WAAY,KAAK,SAAS;CAExD,MAAM,WAAW,MAAM,gBAAgB,KAAK,MAAM;EAAE,gBAAgB,CAAC,MAAM,OAAO;EAAG,MAAM;CAAc,CAAC;CAC1G,MAAM,UAAU,SAAS,MAAM;CAC/B,IAAI,CAAC,SAAS;EACZ,MAAM,YAAY,OAAO,KAAK,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,KAAK;EAC7D,MAAM,IAAI,MAAM,YAAY,MAAM,QAAQ,0BAA0B,WAAW;CACjF;CAEA,MAAM,OAAO,IAAI,QAAQ,SAAS;EAChC,UAAU,aAAa,GAAG;EAC1B,KAAK,cAAc,KAAK;EACxB,aAAa;GACX,OAAO,MAAM,kBAAkB;GAC/B,gBAAgB,MAAM;GACtB,iBAAiB,MAAM;GACvB,UAAU,MAAM;EAClB;CACF,CAAC;CACD,MAAM,KAAK,MAAM;CACjB,IAAI;EACF,MAAM,MAAM,MAAM,iBAAiB,KAAK;EACxC,MAAM,YAAY,MAAM,KAAK,WAAW,GAAG;EAE3C,MAAM,OAAO,OAAO,SAAiB;GACnC,MAAM,SAAyB,CAAC;IAAE,MAAM;IAAQ;GAAK,CAAC;GACtD,MAAM,KAAK,OAAO,WAAW,MAAM;GACnC,IAAI,MAAM,IAAI;EAChB;EAEA,IAAI,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,SAAS,GAAG;GAC/D,MAAM,KAAK,KAAK,OAAO;GACvB;EACF;EAEA,MAAM,KAAK,gBAAgB,EAAE,OAAO,KAAK,SAAS,QAAQ,MAAM,CAAC;EACjE,IAAI,MAAM,iBAAiB,MAAM,KAAK,IAAI,MAAM,GAAG,2BAA2B;EAC9E,IAAI;GACF,WAAW,MAAM,QAAQ,IAAI;IAC3B,MAAM,OAAO,KAAK,KAAK;IACvB,IAAI,SAAS,WAAW,SAAS,SAAS;IAC1C,IAAI,KAAK,SAAS,GAAG,MAAM,KAAK,IAAI;IACpC,IAAI,MAAM,IAAI;GAChB;EACF,UAAU;GACR,GAAG,MAAM;EACX;CACF,UAAU;EACR,MAAM,KAAK,KAAK;CAClB;AACF"}
|
package/dist/index.js
CHANGED
|
@@ -68492,9 +68492,9 @@ const telemetry = startDaemonOpenTelemetry({ serviceVersion: DAEMON_VERSION });
|
|
|
68492
68492
|
const [{ Command }, { fileURLToPath }, { runChat }, { runLogin }, { runForeground }, { resolveController }, { acquireSingletonLock }, { resolveRoot }] = await Promise.all([
|
|
68493
68493
|
import("./commander-B5QVEFzH.js"),
|
|
68494
68494
|
import("node:url"),
|
|
68495
|
-
import("./chat-
|
|
68496
|
-
import("./login-
|
|
68497
|
-
import("./run-foreground-
|
|
68495
|
+
import("./chat-CeThir-Y.js"),
|
|
68496
|
+
import("./login-CoeR7Gr0.js"),
|
|
68497
|
+
import("./run-foreground-B8NoERhV.js"),
|
|
68498
68498
|
import("./service-6w0WKhdx.js"),
|
|
68499
68499
|
import("./lock-CA9Bm8_s.js"),
|
|
68500
68500
|
import("./paths-CcRUjFjy.js")
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as DAEMON_VERSION } from "./version-DGaRXjBK.js";
|
|
2
|
-
import { i as ClientTransport, t as runForeground } from "./run-foreground-
|
|
2
|
+
import { i as ClientTransport, t as runForeground } from "./run-foreground-Cdxkfe7g.js";
|
|
3
3
|
import { c as ConfigSchema } from "./load-agents-C3pJSVeT.js";
|
|
4
4
|
import { l as resolveRoot, t as configPath } from "./paths-DEcUO8lC.js";
|
|
5
|
-
import { _ as encode, g as decodeEnvelope, h as buildEnvelope, l as isFrame } from "./acp-host-
|
|
5
|
+
import { _ as encode, g as decodeEnvelope, h as buildEnvelope, l as isFrame } from "./acp-host-M9PGQrVJ.js";
|
|
6
6
|
import { n as resolveController } from "./service-BQVw7wbz.js";
|
|
7
7
|
import { dirname } from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
@@ -229,4 +229,4 @@ async function runLogin(opts, partial = {}) {
|
|
|
229
229
|
//#endregion
|
|
230
230
|
export { buildInstallOpts, persistCredentials, runLogin };
|
|
231
231
|
|
|
232
|
-
//# sourceMappingURL=login-
|
|
232
|
+
//# sourceMappingURL=login-CoeR7Gr0.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-DAAg53hd.js","names":["realRunForeground"],"sources":["../src/cp/auth-probe.ts","../src/cli/login.ts"],"sourcesContent":["/**\n * `probeAuth` — a one-shot CP auth check used by `agentconnect login`. It dials\n * the CP, sends ONLY the `auth` frame (no `register`), and resolves with the\n * authoritative daemonId from `auth/ok`, or a human-readable failure reason on\n * a `4401` close, a correlated `error`, a dial failure, or a timeout. It always\n * closes the socket and never leaves a connection open.\n */\nimport { buildEnvelope, decodeEnvelope, encode, isFrame } from '@agentconnect.md/protocol'\nimport { ClientTransport, type Transport } from '@agentconnect.md/connection'\nimport { CP_SUBPROTOCOL, CP_WS_PATH } from './client.js'\n\nexport interface ProbeResult {\n ok: boolean\n daemonId?: string\n reason?: string\n}\n\nexport interface ProbeOpts {\n url: string\n token: string\n daemonId?: string\n agentVersion?: string\n timeoutMs?: number\n /** Injectable for tests; defaults to dialing the real WebSocket. */\n connect?: () => Promise<Transport>\n}\n\nexport async function probeAuth(opts: ProbeOpts): Promise<ProbeResult> {\n const timeoutMs = opts.timeoutMs ?? 10_000\n const dial = opts.connect ?? (() => ClientTransport.dial(opts.url, { subprotocol: CP_SUBPROTOCOL, path: CP_WS_PATH }))\n\n let transport: Transport\n try {\n transport = await dial()\n } catch (err) {\n return { ok: false, reason: `cannot reach ${opts.url}: ${(err as Error).message}` }\n }\n\n const authPayload: Record<string, unknown> = {\n apiKey: opts.token,\n agentVersion: opts.agentVersion ?? 'probe'\n }\n if (opts.daemonId) authPayload.daemonId = opts.daemonId\n const frame = buildEnvelope('auth', authPayload)\n\n return await new Promise<ProbeResult>((resolve) => {\n let settled = false\n const done = (r: ProbeResult): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n try {\n transport.close(1000, 'probe done')\n } catch {\n // socket may already be closed\n }\n resolve(r)\n }\n\n const timer = setTimeout(\n () => done({ ok: false, reason: `timed out after ${timeoutMs}ms waiting for auth/ok` }),\n timeoutMs\n )\n\n transport.onMessage((text) => {\n const decoded = decodeEnvelope(text)\n if (!decoded.ok) return\n const f = decoded.frame\n if (f.corr !== frame.id) return\n if (f.type === 'error') {\n const e = f.payload as { code: string; message: string }\n done({ ok: false, reason: `${e.code}: ${e.message}` })\n return\n }\n if (isFrame('auth/ok')(f)) {\n const ok = f.payload as { daemonId: string }\n done({ ok: true, daemonId: ok.daemonId })\n }\n })\n\n transport.onClose((code) => {\n if (code === 4401) done({ ok: false, reason: 'authentication failed (4401) — check the daemon token' })\n else done({ ok: false, reason: `connection closed (${code}) before auth/ok` })\n })\n\n transport.send(encode(frame))\n })\n}\n","/**\n * `agentconnect login` — interactive onboarding. It tests the Control Plane auth\n * flow, persists credentials only on success, then offers to install the OS\n * service. If installed it starts the service (`up`) and returns; otherwise it\n * runs the daemon in the foreground (the same path as `agentconnect run`).\n *\n * `persistCredentials` is the pure config-merge half (token-only onboarding:\n * `daemonId` is omitted unless given — the first connect adopts it from the\n * token's `sub`). `runLogin` is the orchestrator, with injectable deps for tests.\n */\nimport { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport { fileURLToPath } from 'node:url'\nimport { ConfigSchema } from '../config/config-schema.js'\nimport { resolveRoot, configPath } from '../paths.js'\nimport { DAEMON_VERSION } from '../version.js'\nimport { probeAuth, type ProbeResult } from '../cp/auth-probe.js'\nimport { resolveController, type InstallOpts } from '../service/index.js'\nimport { runForeground as realRunForeground } from './run-foreground.js'\n\nexport interface PersistCredsOpts {\n cpUrl: string\n cpKey: string\n daemonId?: string\n root?: string\n configPath?: string\n}\n\n/** Merge url/token into config.json (validated), returning the written path. */\nexport function persistCredentials(opts: PersistCredsOpts): string {\n const root = resolveRoot(opts.root)\n const file = opts.configPath ?? configPath(root)\n const raw: Record<string, unknown> = existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : { version: 1 }\n\n const cp = (raw.controlPlane as Record<string, unknown> | undefined) ?? {}\n raw.controlPlane = { ...cp, url: opts.cpUrl, key: opts.cpKey, enabled: true }\n if (opts.daemonId) raw.daemonId = opts.daemonId\n\n ConfigSchema.parse(raw) // fail before writing if the merge is invalid\n\n mkdirSync(dirname(file), { recursive: true })\n writeFileSync(file, JSON.stringify(raw, null, 2) + '\\n')\n return file\n}\n\nexport interface RunLoginOpts {\n cpUrl?: string\n cpKey?: string\n daemonId?: string\n root?: string\n configPath?: string\n /** The resolved CLI entry path. Must be supplied by the CLI entry point\n * (index.ts) so the correct bundle path is used rather than inferring it\n * from login.ts's own import.meta.url (which is the same bundle but the\n * `../` path calculation would be wrong). Falls back to import.meta.url\n * for the pure test path where login.ts is loaded standalone. */\n cliEntry?: string\n}\n\n/**\n * Build the InstallOpts for the OS service installer.\n *\n * Exported as a pure helper so it can be unit-tested independently of the\n * full `runLogin` orchestration. The caller (index.ts) passes `cliEntry` so\n * the correct bundle path always flows through; if omitted we fall back to\n * `import.meta.url` (correct only when login.ts is the entry, e.g. in tests).\n */\nexport function buildInstallOpts(opts: { root?: string; cliEntry?: string }): InstallOpts {\n return {\n execPath: process.execPath,\n cliEntry: opts.cliEntry ?? fileURLToPath(import.meta.url),\n includeRootEnv: resolveRoot(opts.root) !== resolveRoot(undefined)\n }\n}\n\nexport interface LoginDeps {\n probe: (o: { url: string; token: string }) => Promise<ProbeResult>\n installService: () => Promise<void>\n runForeground: () => Promise<void>\n out: NodeJS.WritableStream\n input: NodeJS.ReadableStream\n isTTY: boolean\n}\n\nfunction realDeps(opts: RunLoginOpts): LoginDeps {\n return {\n probe: (o) => probeAuth({ url: o.url, token: o.token, agentVersion: DAEMON_VERSION }),\n installService: async () => {\n const controller = resolveController({ root: opts.root })\n await controller.install(buildInstallOpts(opts))\n await controller.up()\n },\n runForeground: () =>\n realRunForeground({\n root: opts.root,\n overrides: { cpUrl: opts.cpUrl, cpKey: opts.cpKey, daemonId: opts.daemonId }\n }),\n out: process.stdout,\n input: process.stdin,\n isTTY: Boolean(process.stdin.isTTY)\n }\n}\n\n/** Read the next line from a readline interface via async iterator. */\nasync function nextLine(\n iter: AsyncIterableIterator<string>,\n prompt: string,\n out: NodeJS.WritableStream\n): Promise<string> {\n out.write(prompt)\n const { value, done } = await iter.next()\n if (done) throw new Error(`unexpected end of input waiting for: ${prompt}`)\n return (value as string).trim()\n}\n\nexport async function runLogin(opts: RunLoginOpts, partial: Partial<LoginDeps> = {}): Promise<void> {\n const deps: LoginDeps = { ...realDeps(opts), ...partial }\n const { out } = deps\n\n // ── Non-interactive: flags required; probe; persist. No prompts, no handoff. ──\n if (!deps.isTTY) {\n if (!opts.cpUrl) throw new Error('login requires --cp-url <url>')\n if (!opts.cpKey) throw new Error('login requires --cp-key <key>')\n const r = await deps.probe({ url: opts.cpUrl, token: opts.cpKey })\n if (!r.ok) throw new Error(`authentication failed: ${r.reason}`)\n persistCredentials({ ...opts, cpUrl: opts.cpUrl, cpKey: opts.cpKey })\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''} — credentials saved\\n`)\n return\n }\n\n // Both interactive handoffs read `<root>/config.json`: the installed service\n // runs `… run` (no `--config`), and the foreground `Daemon` loads by root. A\n // custom `--config` would persist credentials the daemon never reads, so the\n // install/run branch would look successful but start without them. Reject it;\n // `--root` is the knob that keeps persist + service + foreground in sync.\n if (opts.configPath) {\n throw new Error(\n 'interactive login does not support --config — use --root <dir> so the daemon and the installed service read the same config'\n )\n }\n\n // ── Interactive ──\n const rl = createInterface({ input: deps.input, output: out })\n const iter = rl[Symbol.asyncIterator]()\n let url = opts.cpUrl\n let token = opts.cpKey\n try {\n if (!url) url = await nextLine(iter, 'Control Plane URL: ', out)\n\n for (let attempt = 0; ; attempt++) {\n if (!token) token = await nextLine(iter, 'Daemon API key: ', out)\n out.write(`Testing connection to ${url}…\\n`)\n const r = await deps.probe({ url: url!, token: token! })\n if (r.ok) {\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''}\\n`)\n break\n }\n out.write(`✗ ${r.reason}\\n`)\n if (attempt >= 1) throw new Error('authentication failed')\n token = undefined // re-prompt on retry\n }\n\n persistCredentials({ ...opts, cpUrl: url!, cpKey: token! })\n\n const ans = (await nextLine(iter, 'Install AgentConnect as a background service? (y/N) ', out)).toLowerCase()\n if (ans === 'y' || ans === 'yes') {\n await deps.installService()\n out.write('Service installed and started. Manage it with `agentconnect up` / `down` / `status`.\\n')\n return\n }\n out.write('Starting in the foreground (Ctrl-C to stop)…\\n')\n } finally {\n rl.close()\n }\n\n await deps.runForeground()\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"login-CoeR7Gr0.js","names":["realRunForeground"],"sources":["../src/cp/auth-probe.ts","../src/cli/login.ts"],"sourcesContent":["/**\n * `probeAuth` — a one-shot CP auth check used by `agentconnect login`. It dials\n * the CP, sends ONLY the `auth` frame (no `register`), and resolves with the\n * authoritative daemonId from `auth/ok`, or a human-readable failure reason on\n * a `4401` close, a correlated `error`, a dial failure, or a timeout. It always\n * closes the socket and never leaves a connection open.\n */\nimport { buildEnvelope, decodeEnvelope, encode, isFrame } from '@agentconnect.md/protocol'\nimport { ClientTransport, type Transport } from '@agentconnect.md/connection'\nimport { CP_SUBPROTOCOL, CP_WS_PATH } from './client.js'\n\nexport interface ProbeResult {\n ok: boolean\n daemonId?: string\n reason?: string\n}\n\nexport interface ProbeOpts {\n url: string\n token: string\n daemonId?: string\n agentVersion?: string\n timeoutMs?: number\n /** Injectable for tests; defaults to dialing the real WebSocket. */\n connect?: () => Promise<Transport>\n}\n\nexport async function probeAuth(opts: ProbeOpts): Promise<ProbeResult> {\n const timeoutMs = opts.timeoutMs ?? 10_000\n const dial = opts.connect ?? (() => ClientTransport.dial(opts.url, { subprotocol: CP_SUBPROTOCOL, path: CP_WS_PATH }))\n\n let transport: Transport\n try {\n transport = await dial()\n } catch (err) {\n return { ok: false, reason: `cannot reach ${opts.url}: ${(err as Error).message}` }\n }\n\n const authPayload: Record<string, unknown> = {\n apiKey: opts.token,\n agentVersion: opts.agentVersion ?? 'probe'\n }\n if (opts.daemonId) authPayload.daemonId = opts.daemonId\n const frame = buildEnvelope('auth', authPayload)\n\n return await new Promise<ProbeResult>((resolve) => {\n let settled = false\n const done = (r: ProbeResult): void => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n try {\n transport.close(1000, 'probe done')\n } catch {\n // socket may already be closed\n }\n resolve(r)\n }\n\n const timer = setTimeout(\n () => done({ ok: false, reason: `timed out after ${timeoutMs}ms waiting for auth/ok` }),\n timeoutMs\n )\n\n transport.onMessage((text) => {\n const decoded = decodeEnvelope(text)\n if (!decoded.ok) return\n const f = decoded.frame\n if (f.corr !== frame.id) return\n if (f.type === 'error') {\n const e = f.payload as { code: string; message: string }\n done({ ok: false, reason: `${e.code}: ${e.message}` })\n return\n }\n if (isFrame('auth/ok')(f)) {\n const ok = f.payload as { daemonId: string }\n done({ ok: true, daemonId: ok.daemonId })\n }\n })\n\n transport.onClose((code) => {\n if (code === 4401) done({ ok: false, reason: 'authentication failed (4401) — check the daemon token' })\n else done({ ok: false, reason: `connection closed (${code}) before auth/ok` })\n })\n\n transport.send(encode(frame))\n })\n}\n","/**\n * `agentconnect login` — interactive onboarding. It tests the Control Plane auth\n * flow, persists credentials only on success, then offers to install the OS\n * service. If installed it starts the service (`up`) and returns; otherwise it\n * runs the daemon in the foreground (the same path as `agentconnect run`).\n *\n * `persistCredentials` is the pure config-merge half (token-only onboarding:\n * `daemonId` is omitted unless given — the first connect adopts it from the\n * token's `sub`). `runLogin` is the orchestrator, with injectable deps for tests.\n */\nimport { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport { fileURLToPath } from 'node:url'\nimport { ConfigSchema } from '../config/config-schema.js'\nimport { resolveRoot, configPath } from '../paths.js'\nimport { DAEMON_VERSION } from '../version.js'\nimport { probeAuth, type ProbeResult } from '../cp/auth-probe.js'\nimport { resolveController, type InstallOpts } from '../service/index.js'\nimport { runForeground as realRunForeground } from './run-foreground.js'\n\nexport interface PersistCredsOpts {\n cpUrl: string\n cpKey: string\n daemonId?: string\n root?: string\n configPath?: string\n}\n\n/** Merge url/token into config.json (validated), returning the written path. */\nexport function persistCredentials(opts: PersistCredsOpts): string {\n const root = resolveRoot(opts.root)\n const file = opts.configPath ?? configPath(root)\n const raw: Record<string, unknown> = existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : { version: 1 }\n\n const cp = (raw.controlPlane as Record<string, unknown> | undefined) ?? {}\n raw.controlPlane = { ...cp, url: opts.cpUrl, key: opts.cpKey, enabled: true }\n if (opts.daemonId) raw.daemonId = opts.daemonId\n\n ConfigSchema.parse(raw) // fail before writing if the merge is invalid\n\n mkdirSync(dirname(file), { recursive: true })\n writeFileSync(file, JSON.stringify(raw, null, 2) + '\\n')\n return file\n}\n\nexport interface RunLoginOpts {\n cpUrl?: string\n cpKey?: string\n daemonId?: string\n root?: string\n configPath?: string\n /** The resolved CLI entry path. Must be supplied by the CLI entry point\n * (index.ts) so the correct bundle path is used rather than inferring it\n * from login.ts's own import.meta.url (which is the same bundle but the\n * `../` path calculation would be wrong). Falls back to import.meta.url\n * for the pure test path where login.ts is loaded standalone. */\n cliEntry?: string\n}\n\n/**\n * Build the InstallOpts for the OS service installer.\n *\n * Exported as a pure helper so it can be unit-tested independently of the\n * full `runLogin` orchestration. The caller (index.ts) passes `cliEntry` so\n * the correct bundle path always flows through; if omitted we fall back to\n * `import.meta.url` (correct only when login.ts is the entry, e.g. in tests).\n */\nexport function buildInstallOpts(opts: { root?: string; cliEntry?: string }): InstallOpts {\n return {\n execPath: process.execPath,\n cliEntry: opts.cliEntry ?? fileURLToPath(import.meta.url),\n includeRootEnv: resolveRoot(opts.root) !== resolveRoot(undefined)\n }\n}\n\nexport interface LoginDeps {\n probe: (o: { url: string; token: string }) => Promise<ProbeResult>\n installService: () => Promise<void>\n runForeground: () => Promise<void>\n out: NodeJS.WritableStream\n input: NodeJS.ReadableStream\n isTTY: boolean\n}\n\nfunction realDeps(opts: RunLoginOpts): LoginDeps {\n return {\n probe: (o) => probeAuth({ url: o.url, token: o.token, agentVersion: DAEMON_VERSION }),\n installService: async () => {\n const controller = resolveController({ root: opts.root })\n await controller.install(buildInstallOpts(opts))\n await controller.up()\n },\n runForeground: () =>\n realRunForeground({\n root: opts.root,\n overrides: { cpUrl: opts.cpUrl, cpKey: opts.cpKey, daemonId: opts.daemonId }\n }),\n out: process.stdout,\n input: process.stdin,\n isTTY: Boolean(process.stdin.isTTY)\n }\n}\n\n/** Read the next line from a readline interface via async iterator. */\nasync function nextLine(\n iter: AsyncIterableIterator<string>,\n prompt: string,\n out: NodeJS.WritableStream\n): Promise<string> {\n out.write(prompt)\n const { value, done } = await iter.next()\n if (done) throw new Error(`unexpected end of input waiting for: ${prompt}`)\n return (value as string).trim()\n}\n\nexport async function runLogin(opts: RunLoginOpts, partial: Partial<LoginDeps> = {}): Promise<void> {\n const deps: LoginDeps = { ...realDeps(opts), ...partial }\n const { out } = deps\n\n // ── Non-interactive: flags required; probe; persist. No prompts, no handoff. ──\n if (!deps.isTTY) {\n if (!opts.cpUrl) throw new Error('login requires --cp-url <url>')\n if (!opts.cpKey) throw new Error('login requires --cp-key <key>')\n const r = await deps.probe({ url: opts.cpUrl, token: opts.cpKey })\n if (!r.ok) throw new Error(`authentication failed: ${r.reason}`)\n persistCredentials({ ...opts, cpUrl: opts.cpUrl, cpKey: opts.cpKey })\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''} — credentials saved\\n`)\n return\n }\n\n // Both interactive handoffs read `<root>/config.json`: the installed service\n // runs `… run` (no `--config`), and the foreground `Daemon` loads by root. A\n // custom `--config` would persist credentials the daemon never reads, so the\n // install/run branch would look successful but start without them. Reject it;\n // `--root` is the knob that keeps persist + service + foreground in sync.\n if (opts.configPath) {\n throw new Error(\n 'interactive login does not support --config — use --root <dir> so the daemon and the installed service read the same config'\n )\n }\n\n // ── Interactive ──\n const rl = createInterface({ input: deps.input, output: out })\n const iter = rl[Symbol.asyncIterator]()\n let url = opts.cpUrl\n let token = opts.cpKey\n try {\n if (!url) url = await nextLine(iter, 'Control Plane URL: ', out)\n\n for (let attempt = 0; ; attempt++) {\n if (!token) token = await nextLine(iter, 'Daemon API key: ', out)\n out.write(`Testing connection to ${url}…\\n`)\n const r = await deps.probe({ url: url!, token: token! })\n if (r.ok) {\n out.write(`✓ authenticated${r.daemonId ? ` (daemon ${r.daemonId})` : ''}\\n`)\n break\n }\n out.write(`✗ ${r.reason}\\n`)\n if (attempt >= 1) throw new Error('authentication failed')\n token = undefined // re-prompt on retry\n }\n\n persistCredentials({ ...opts, cpUrl: url!, cpKey: token! })\n\n const ans = (await nextLine(iter, 'Install AgentConnect as a background service? (y/N) ', out)).toLowerCase()\n if (ans === 'y' || ans === 'yes') {\n await deps.installService()\n out.write('Service installed and started. Manage it with `agentconnect up` / `down` / `status`.\\n')\n return\n }\n out.write('Starting in the foreground (Ctrl-C to stop)…\\n')\n } finally {\n rl.close()\n }\n\n await deps.runForeground()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2BA,eAAsB,UAAU,MAAuC;CACrE,MAAM,YAAY,KAAK,aAAa;CACpC,MAAM,OAAO,KAAK,kBAAkB,gBAAgB,KAAK,KAAK,KAAK;EAAE,aAAA;EAA6B,MAAA;CAAiB,CAAC;CAEpH,IAAI;CACJ,IAAI;EACF,YAAY,MAAM,KAAK;CACzB,SAAS,KAAK;EACZ,OAAO;GAAE,IAAI;GAAO,QAAQ,gBAAgB,KAAK,IAAI,IAAK,IAAc;EAAU;CACpF;CAEA,MAAM,cAAuC;EAC3C,QAAQ,KAAK;EACb,cAAc,KAAK,gBAAgB;CACrC;CACA,IAAI,KAAK,UAAU,YAAY,WAAW,KAAK;CAC/C,MAAM,QAAQ,cAAc,QAAQ,WAAW;CAE/C,OAAO,MAAM,IAAI,SAAsB,YAAY;EACjD,IAAI,UAAU;EACd,MAAM,QAAQ,MAAyB;GACrC,IAAI,SAAS;GACb,UAAU;GACV,aAAa,KAAK;GAClB,IAAI;IACF,UAAU,MAAM,KAAM,YAAY;GACpC,QAAQ,CAER;GACA,QAAQ,CAAC;EACX;EAEA,MAAM,QAAQ,iBACN,KAAK;GAAE,IAAI;GAAO,QAAQ,mBAAmB,UAAU;EAAwB,CAAC,GACtF,SACF;EAEA,UAAU,WAAW,SAAS;GAC5B,MAAM,UAAU,eAAe,IAAI;GACnC,IAAI,CAAC,QAAQ,IAAI;GACjB,MAAM,IAAI,QAAQ;GAClB,IAAI,EAAE,SAAS,MAAM,IAAI;GACzB,IAAI,EAAE,SAAS,SAAS;IACtB,MAAM,IAAI,EAAE;IACZ,KAAK;KAAE,IAAI;KAAO,QAAQ,GAAG,EAAE,KAAK,IAAI,EAAE;IAAU,CAAC;IACrD;GACF;GACA,IAAI,QAAQ,SAAS,CAAC,CAAC,CAAC,GAAG;IACzB,MAAM,KAAK,EAAE;IACb,KAAK;KAAE,IAAI;KAAM,UAAU,GAAG;IAAS,CAAC;GAC1C;EACF,CAAC;EAED,UAAU,SAAS,SAAS;GAC1B,IAAI,SAAS,MAAM,KAAK;IAAE,IAAI;IAAO,QAAQ;GAAwD,CAAC;QACjG,KAAK;IAAE,IAAI;IAAO,QAAQ,sBAAsB,KAAK;GAAkB,CAAC;EAC/E,CAAC;EAED,UAAU,KAAK,OAAO,KAAK,CAAC;CAC9B,CAAC;AACH;;;;;;;;;;;;;;ACzDA,SAAgB,mBAAmB,MAAgC;CACjE,MAAM,OAAO,YAAY,KAAK,IAAI;CAClC,MAAM,OAAO,KAAK,cAAc,WAAW,IAAI;CAC/C,MAAM,MAA+B,WAAW,IAAI,IAAI,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE;CAG9G,IAAI,eAAe;EAAE,GADT,IAAI,gBAAwD,CAAC;EAC7C,KAAK,KAAK;EAAO,KAAK,KAAK;EAAO,SAAS;CAAK;CAC5E,IAAI,KAAK,UAAU,IAAI,WAAW,KAAK;CAEvC,aAAa,MAAM,GAAG;CAEtB,UAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CAC5C,cAAc,MAAM,KAAK,UAAU,KAAK,MAAM,CAAC,IAAI,IAAI;CACvD,OAAO;AACT;;;;;;;;;AAwBA,SAAgB,iBAAiB,MAAyD;CACxF,OAAO;EACL,UAAU,QAAQ;EAClB,UAAU,KAAK,YAAY,cAAc,OAAO,KAAK,GAAG;EACxD,gBAAgB,YAAY,KAAK,IAAI,MAAM,YAAY,KAAA,CAAS;CAClE;AACF;AAWA,SAAS,SAAS,MAA+B;CAC/C,OAAO;EACL,QAAQ,MAAM,UAAU;GAAE,KAAK,EAAE;GAAK,OAAO,EAAE;GAAO,cAAc;EAAe,CAAC;EACpF,gBAAgB,YAAY;GAC1B,MAAM,aAAa,kBAAkB,EAAE,MAAM,KAAK,KAAK,CAAC;GACxD,MAAM,WAAW,QAAQ,iBAAiB,IAAI,CAAC;GAC/C,MAAM,WAAW,GAAG;EACtB;EACA,qBACEA,cAAkB;GAChB,MAAM,KAAK;GACX,WAAW;IAAE,OAAO,KAAK;IAAO,OAAO,KAAK;IAAO,UAAU,KAAK;GAAS;EAC7E,CAAC;EACH,KAAK,QAAQ;EACb,OAAO,QAAQ;EACf,OAAO,QAAQ,QAAQ,MAAM,KAAK;CACpC;AACF;;AAGA,eAAe,SACb,MACA,QACA,KACiB;CACjB,IAAI,MAAM,MAAM;CAChB,MAAM,EAAE,OAAO,SAAS,MAAM,KAAK,KAAK;CACxC,IAAI,MAAM,MAAM,IAAI,MAAM,wCAAwC,QAAQ;CAC1E,OAAQ,MAAiB,KAAK;AAChC;AAEA,eAAsB,SAAS,MAAoB,UAA8B,CAAC,GAAkB;CAClG,MAAM,OAAkB;EAAE,GAAG,SAAS,IAAI;EAAG,GAAG;CAAQ;CACxD,MAAM,EAAE,QAAQ;CAGhB,IAAI,CAAC,KAAK,OAAO;EACf,IAAI,CAAC,KAAK,OAAO,MAAM,IAAI,MAAM,+BAA+B;EAChE,IAAI,CAAC,KAAK,OAAO,MAAM,IAAI,MAAM,+BAA+B;EAChE,MAAM,IAAI,MAAM,KAAK,MAAM;GAAE,KAAK,KAAK;GAAO,OAAO,KAAK;EAAM,CAAC;EACjE,IAAI,CAAC,EAAE,IAAI,MAAM,IAAI,MAAM,0BAA0B,EAAE,QAAQ;EAC/D,mBAAmB;GAAE,GAAG;GAAM,OAAO,KAAK;GAAO,OAAO,KAAK;EAAM,CAAC;EACpE,IAAI,MAAM,kBAAkB,EAAE,WAAW,YAAY,EAAE,SAAS,KAAK,GAAG,uBAAuB;EAC/F;CACF;CAOA,IAAI,KAAK,YACP,MAAM,IAAI,MACR,6HACF;CAIF,MAAM,KAAK,gBAAgB;EAAE,OAAO,KAAK;EAAO,QAAQ;CAAI,CAAC;CAC7D,MAAM,OAAO,GAAG,OAAO,cAAc,CAAC;CACtC,IAAI,MAAM,KAAK;CACf,IAAI,QAAQ,KAAK;CACjB,IAAI;EACF,IAAI,CAAC,KAAK,MAAM,MAAM,SAAS,MAAM,uBAAuB,GAAG;EAE/D,KAAK,IAAI,UAAU,IAAK,WAAW;GACjC,IAAI,CAAC,OAAO,QAAQ,MAAM,SAAS,MAAM,oBAAoB,GAAG;GAChE,IAAI,MAAM,yBAAyB,IAAI,IAAI;GAC3C,MAAM,IAAI,MAAM,KAAK,MAAM;IAAO;IAAa;GAAO,CAAC;GACvD,IAAI,EAAE,IAAI;IACR,IAAI,MAAM,kBAAkB,EAAE,WAAW,YAAY,EAAE,SAAS,KAAK,GAAG,GAAG;IAC3E;GACF;GACA,IAAI,MAAM,KAAK,EAAE,OAAO,GAAG;GAC3B,IAAI,WAAW,GAAG,MAAM,IAAI,MAAM,uBAAuB;GACzD,QAAQ,KAAA;EACV;EAEA,mBAAmB;GAAE,GAAG;GAAM,OAAO;GAAM,OAAO;EAAO,CAAC;EAE1D,MAAM,OAAO,MAAM,SAAS,MAAM,wDAAwD,GAAG,EAAA,CAAG,YAAY;EAC5G,IAAI,QAAQ,OAAO,QAAQ,OAAO;GAChC,MAAM,KAAK,eAAe;GAC1B,IAAI,MAAM,wFAAwF;GAClG;EACF;EACA,IAAI,MAAM,gDAAgD;CAC5D,UAAU;EACR,GAAG,MAAM;CACX;CAEA,MAAM,KAAK,cAAc;AAC3B"}
|
|
@@ -5,7 +5,7 @@ import { t as DAEMON_VERSION } from "./version-DGaRXjBK.js";
|
|
|
5
5
|
import { C as _coercedNumber, T as NEVER, a as array, d as literal, f as looseObject, i as any, m as object, o as boolean, p as number$1, t as ZodNumber, v as string, x as url$4 } from "./schemas-CQkO9hC5.js";
|
|
6
6
|
import { a as agentChildEnv, i as selectAgent, n as findAgentFiles, o as loadConfig, r as loadAgents, s as persistDaemonId } from "./load-agents-C3pJSVeT.js";
|
|
7
7
|
import { l as resolveRoot, o as mcpSocketPath, u as statePath } from "./paths-DEcUO8lC.js";
|
|
8
|
-
import { C as resolveRuntimes, S as cachedRuntimeVersions, _ as encode, a as initGitInjection, b as RESERVED_MCP_SERVER_NAME, c as simpleGit, d as RELAY_DAEMON_SUBPROTOCOL, f as RELAY_DAEMON_WS_PATH, g as decodeEnvelope, h as buildEnvelope, i as prepareWorkspace, m as decodeRelayDaemonFrame, n as installedRuntimes, o as probeGitVersion, p as buildRelayDaemonFrame, r as prefetchWorkspace, s as sessionGitEnv, t as AcpHost, u as normalizeGitUrl, v as MAX_FRAME_BYTES, x as cachedRuntimeNames, y as MEMORY_INDEX } from "./acp-host-
|
|
8
|
+
import { C as resolveRuntimes, S as cachedRuntimeVersions, _ as encode, a as initGitInjection, b as RESERVED_MCP_SERVER_NAME, c as simpleGit, d as RELAY_DAEMON_SUBPROTOCOL, f as RELAY_DAEMON_WS_PATH, g as decodeEnvelope, h as buildEnvelope, i as prepareWorkspace, m as decodeRelayDaemonFrame, n as installedRuntimes, o as probeGitVersion, p as buildRelayDaemonFrame, r as prefetchWorkspace, s as sessionGitEnv, t as AcpHost, u as normalizeGitUrl, v as MAX_FRAME_BYTES, x as cachedRuntimeNames, y as MEMORY_INDEX } from "./acp-host-M9PGQrVJ.js";
|
|
9
9
|
import { i as GitCredentialCache, n as gitcredSocketPath, r as writeGitcredShim, t as GitCredServer } from "./gitcred-server-Dcsq6QJe.js";
|
|
10
10
|
import { B as ToolListChangedNotificationSchema, D as ListPromptsResultSchema, E as ListChangedOptionsBaseSchema, F as PromptListChangedNotificationSchema, G as isZ4Schema, H as isJSONRPCRequest, I as ReadResourceResultSchema, J as encodeFrame, K as safeParse, L as ResourceListChangedNotificationSchema, M as ListToolsResultSchema, O as ListResourceTemplatesResultSchema, P as McpError, R as SUPPORTED_PROTOCOL_VERSIONS, S as InitializeResultSchema, T as LATEST_PROTOCOL_VERSION, U as isJSONRPCResultResponse, V as isInitializedNotification, W as getObjectShape, _ as ElicitResultSchema, a as AjvJsonSchemaValidator, b as GetPromptResultSchema, c as mergeCapabilities, d as CompleteResultSchema, f as CreateMessageRequestSchema, g as ElicitRequestSchema, h as CreateTaskResultSchema, i as assertToolsCallTaskCapability, k as ListResourcesResultSchema, m as CreateMessageResultWithToolsSchema, n as serializeMessage, o as require_fast_deep_equal, p as CreateMessageResultSchema, q as decodeFrames, r as assertClientRequestTaskCapability, s as Protocol, t as ReadBuffer, u as CallToolResultSchema, v as EmptyResultSchema, w as JSONRPCMessageSchema, y as ErrorCode } from "./stdio-DnS8WcXi.js";
|
|
11
11
|
import { URL as URL$1 } from "url";
|
|
@@ -4529,22 +4529,6 @@ var CpClient = class {
|
|
|
4529
4529
|
if (this.state !== "READY" && this.state !== "DRAINING") return;
|
|
4530
4530
|
this.transport?.send(encode(buildEnvelope("cron/report", report)));
|
|
4531
4531
|
}
|
|
4532
|
-
/**
|
|
4533
|
-
* Emit one chunk of a webchat turn's reply stream (D→C `webchat/output` EVT).
|
|
4534
|
-
* Ordered per-connection (TCP); `output.index` is the per-turn assembly counter.
|
|
4535
|
-
* No-op unless READY/DRAINING — a dropped chunk is lost (unlike latest-wins
|
|
4536
|
-
* telemetry), so the daemon only emits while connected. Content is inline, bounded
|
|
4537
|
-
* by the 256 KiB frame cap; the caller chunks any oversize single event.
|
|
4538
|
-
*/
|
|
4539
|
-
emitWebchatOutput(output) {
|
|
4540
|
-
if (this.state !== "READY" && this.state !== "DRAINING") return;
|
|
4541
|
-
this.transport?.send(encode(buildEnvelope("webchat/output", output)));
|
|
4542
|
-
}
|
|
4543
|
-
/** Emit a webchat turn's completion (D→C `webchat/done` EVT). No-op unless READY/DRAINING. */
|
|
4544
|
-
emitWebchatDone(done) {
|
|
4545
|
-
if (this.state !== "READY" && this.state !== "DRAINING") return;
|
|
4546
|
-
this.transport?.send(encode(buildEnvelope("webchat/done", done)));
|
|
4547
|
-
}
|
|
4548
4532
|
request(type, payload) {
|
|
4549
4533
|
const frame = buildEnvelope(type, payload);
|
|
4550
4534
|
return this.correlator.request(frame, (e) => this.transport.send(e));
|
|
@@ -4753,35 +4737,6 @@ var CpClient = class {
|
|
|
4753
4737
|
case "memory/write":
|
|
4754
4738
|
this.deps.memoryReader.write(frame.payload).then((ok) => this.reply(frame, "memory/write/ok", ok)).catch((err) => this.memoryError(frame.id, "memory/write", err));
|
|
4755
4739
|
return;
|
|
4756
|
-
case "webchat/message":
|
|
4757
|
-
if (!this.deps.onWebchatMessage) {
|
|
4758
|
-
this.sendError(frame.id, "INTERNAL", "webchat not supported", false);
|
|
4759
|
-
return;
|
|
4760
|
-
}
|
|
4761
|
-
try {
|
|
4762
|
-
this.reply(frame, "webchat/ack", this.deps.onWebchatMessage(frame.payload));
|
|
4763
|
-
} catch (err) {
|
|
4764
|
-
this.sendError(frame.id, "INTERNAL", `webchat/message failed: ${err.message}`, false);
|
|
4765
|
-
}
|
|
4766
|
-
return;
|
|
4767
|
-
case "webchat/close":
|
|
4768
|
-
this.deps.onWebchatClose?.(frame.payload);
|
|
4769
|
-
return;
|
|
4770
|
-
case "webchat/set-model":
|
|
4771
|
-
this.deps.onWebchatSetModel?.(frame.payload);
|
|
4772
|
-
return;
|
|
4773
|
-
case "webchat/set-effort":
|
|
4774
|
-
this.deps.onWebchatSetEffort?.(frame.payload);
|
|
4775
|
-
return;
|
|
4776
|
-
case "webchat/set-permission-mode":
|
|
4777
|
-
this.deps.onWebchatSetPermissionMode?.(frame.payload);
|
|
4778
|
-
return;
|
|
4779
|
-
case "webchat/set-fast":
|
|
4780
|
-
this.deps.onWebchatSetFast?.(frame.payload);
|
|
4781
|
-
return;
|
|
4782
|
-
case "webchat/cancel":
|
|
4783
|
-
this.deps.onWebchatCancel?.(frame.payload);
|
|
4784
|
-
return;
|
|
4785
4740
|
default:
|
|
4786
4741
|
this.deps.log.debug(`cp: ignoring ${frame.type}`);
|
|
4787
4742
|
return;
|
|
@@ -197033,6 +196988,7 @@ var RelayClient = class {
|
|
|
197033
196988
|
stopped = false;
|
|
197034
196989
|
fatal = false;
|
|
197035
196990
|
reconnectTimer;
|
|
196991
|
+
seqByChat = /* @__PURE__ */ new Map();
|
|
197036
196992
|
constructor(relayId, url, deps) {
|
|
197037
196993
|
this.relayId = relayId;
|
|
197038
196994
|
this.url = url;
|
|
@@ -197105,8 +197061,28 @@ var RelayClient = class {
|
|
|
197105
197061
|
if (!decoded.ok) return;
|
|
197106
197062
|
const frame = decoded.frame;
|
|
197107
197063
|
if (frame.corr && this.correlator.settle(frame)) return;
|
|
197064
|
+
if (frame.type === "rd/msg") {
|
|
197065
|
+
this.handleMsg(frame.id, frame.payload);
|
|
197066
|
+
return;
|
|
197067
|
+
}
|
|
197108
197068
|
this.deps.log.debug(`relay(${this.relayId}): ignoring ${frame.type}`);
|
|
197109
197069
|
}
|
|
197070
|
+
/** An inbound webchat op: dispatch it, reply `rd/ack`, and let the daemon stream `rd/chat`. */
|
|
197071
|
+
handleMsg(reqId, msg) {
|
|
197072
|
+
const ack = this.deps.onRelayMsg(msg, (event) => this.sendChat(msg.chatId, event));
|
|
197073
|
+
this.transport?.send(JSON.stringify(buildRelayDaemonFrame("rd/ack", ack, { corr: reqId })));
|
|
197074
|
+
}
|
|
197075
|
+
/** Send one reply chunk back over THIS relay's socket, stamping the per-chat `seq`. */
|
|
197076
|
+
sendChat(chatId, event) {
|
|
197077
|
+
const seq = (this.seqByChat.get(chatId) ?? 0) + 1;
|
|
197078
|
+
this.seqByChat.set(chatId, seq);
|
|
197079
|
+
this.transport?.send(JSON.stringify(buildRelayDaemonFrame("rd/chat", {
|
|
197080
|
+
chatId,
|
|
197081
|
+
seq,
|
|
197082
|
+
event
|
|
197083
|
+
})));
|
|
197084
|
+
if (event.kind === "done") this.seqByChat.delete(chatId);
|
|
197085
|
+
}
|
|
197110
197086
|
onClose(code, _reason) {
|
|
197111
197087
|
this.transport = void 0;
|
|
197112
197088
|
this.correlator.rejectAll(new WireError("INTERNAL", "connection closed", true));
|
|
@@ -214547,24 +214523,19 @@ var Daemon = class Daemon {
|
|
|
214547
214523
|
await this.dispatch(agentId, msg, integrationId);
|
|
214548
214524
|
}
|
|
214549
214525
|
/**
|
|
214550
|
-
*
|
|
214551
|
-
*
|
|
214552
|
-
*
|
|
214553
|
-
*
|
|
214554
|
-
* this normalizes the turn and hands it to the same dispatch path as any session:
|
|
214555
|
-
* the turn is a REAL session (recorded to the transcript, visible in session/list),
|
|
214556
|
-
* only its transport differs. Returns the ack: accepted + a fresh turnId that
|
|
214557
|
-
* correlates the streamed webchat/output, or accepted:false / no_agent when the
|
|
214558
|
-
* named agent isn't runnable here.
|
|
214526
|
+
* Dispatch one webchat turn onto the named agent and return the ack — transport-neutral:
|
|
214527
|
+
* the reply stream flows to `sink`. A webchat turn is a REAL session (recorded to the
|
|
214528
|
+
* transcript, visible in session/list); only its transport differs. The op names its
|
|
214529
|
+
* target agent explicitly (no trigger matching). Fed by the relay path (`rd/msg`).
|
|
214559
214530
|
*/
|
|
214560
|
-
|
|
214531
|
+
dispatchWebchatTurn(agentId, chatId, text, user, sink) {
|
|
214561
214532
|
const turnId = randomUUID();
|
|
214562
214533
|
const result = routeRules({
|
|
214563
214534
|
platform: "webchat",
|
|
214564
|
-
channel:
|
|
214565
|
-
}, this.mergedRules(), () => null,
|
|
214535
|
+
channel: chatId
|
|
214536
|
+
}, this.mergedRules(), () => null, agentId);
|
|
214566
214537
|
if (!result || !this.agents.has(result.agentId)) {
|
|
214567
|
-
this.log.warn(`webchat: no agent "${
|
|
214538
|
+
this.log.warn(`webchat: no agent "${agentId}" on this daemon — rejecting turn`);
|
|
214568
214539
|
return {
|
|
214569
214540
|
accepted: false,
|
|
214570
214541
|
turnId,
|
|
@@ -214579,24 +214550,33 @@ var Daemon = class Daemon {
|
|
|
214579
214550
|
reason: "paused"
|
|
214580
214551
|
};
|
|
214581
214552
|
}
|
|
214553
|
+
if (this.draining || this.drainingAgents.has(result.agentId)) {
|
|
214554
|
+
this.log.info(`webchat: agent "${result.agentId}" is draining — rejecting turn`);
|
|
214555
|
+
return {
|
|
214556
|
+
accepted: false,
|
|
214557
|
+
turnId,
|
|
214558
|
+
reason: "draining"
|
|
214559
|
+
};
|
|
214560
|
+
}
|
|
214582
214561
|
const msg = {
|
|
214583
|
-
msgId: `webchat:${
|
|
214562
|
+
msgId: `webchat:${chatId}`,
|
|
214584
214563
|
traceId: turnId,
|
|
214585
214564
|
source: "user",
|
|
214586
214565
|
platform: "webchat",
|
|
214587
|
-
channel:
|
|
214566
|
+
channel: chatId,
|
|
214588
214567
|
sender: {
|
|
214589
|
-
id:
|
|
214568
|
+
id: user,
|
|
214590
214569
|
isBot: false
|
|
214591
214570
|
},
|
|
214592
|
-
text
|
|
214571
|
+
text,
|
|
214593
214572
|
mentionedBots: [],
|
|
214594
214573
|
isDm: true,
|
|
214595
214574
|
trigger: "dm"
|
|
214596
214575
|
};
|
|
214597
214576
|
this.dispatch(result.agentId, msg, void 0, {
|
|
214598
|
-
conversationId:
|
|
214599
|
-
turnId
|
|
214577
|
+
conversationId: chatId,
|
|
214578
|
+
turnId,
|
|
214579
|
+
sink
|
|
214600
214580
|
}).catch((err) => this.log.error(`webchat dispatch failed for agent "${result.agentId}": ${formatErr(err)}`));
|
|
214601
214581
|
return {
|
|
214602
214582
|
accepted: true,
|
|
@@ -214606,10 +214586,10 @@ var Daemon = class Daemon {
|
|
|
214606
214586
|
/** Handle a webchat conversation close (C→D `webchat/close`). No live resources are
|
|
214607
214587
|
* bound per-conversation (the session TTL-closes like any other), so this is
|
|
214608
214588
|
* currently just observability — the in-flight turn, if any, runs to completion. */
|
|
214609
|
-
handleWebchatClose(
|
|
214610
|
-
this.log.debug(`webchat: conversation ${
|
|
214589
|
+
handleWebchatClose(conversationId) {
|
|
214590
|
+
this.log.debug(`webchat: conversation ${conversationId} closed by client`);
|
|
214611
214591
|
}
|
|
214612
|
-
/** The local session key a webchat conversation maps to — mirrors `
|
|
214592
|
+
/** The local session key a webchat conversation maps to — mirrors `dispatchWebchatTurn`
|
|
214613
214593
|
* (channel = conversationId, statusThread = the stable `webchat:<id>` msgId, no thread). */
|
|
214614
214594
|
webchatSessionKey(conversationId, agentId) {
|
|
214615
214595
|
return sessionKey("webchat", conversationId, `webchat:${conversationId}`, agentId);
|
|
@@ -214703,31 +214683,100 @@ var Daemon = class Daemon {
|
|
|
214703
214683
|
this.log.info(`session ${key} output-mode override → "${mode}"`);
|
|
214704
214684
|
this.refreshStatusBarForKey(key);
|
|
214705
214685
|
}
|
|
214706
|
-
/** Handle a webchat
|
|
214707
|
-
handleWebchatSetModel(m) {
|
|
214708
|
-
this.setModelByKey(this.webchatSessionKey(m.conversationId, m.agentId), m.model);
|
|
214709
|
-
}
|
|
214710
|
-
/** Handle a webchat in-session effort switch (C→D `webchat/set-effort`). */
|
|
214711
|
-
handleWebchatSetEffort(m) {
|
|
214712
|
-
this.setEffortByKey(this.webchatSessionKey(m.conversationId, m.agentId), m.effort);
|
|
214713
|
-
}
|
|
214714
|
-
/** Handle a webchat in-session permission-mode switch (C→D `webchat/set-permission-mode`). */
|
|
214715
|
-
handleWebchatSetPermissionMode(m) {
|
|
214716
|
-
this.setPermissionModeByKey(this.webchatSessionKey(m.conversationId, m.agentId), m.permissionMode);
|
|
214717
|
-
}
|
|
214718
|
-
/** Handle a webchat in-session fast-mode toggle (C→D `webchat/set-fast`). */
|
|
214719
|
-
handleWebchatSetFast(m) {
|
|
214720
|
-
this.setFastByKey(this.webchatSessionKey(m.conversationId, m.agentId), m.fastMode);
|
|
214721
|
-
}
|
|
214722
|
-
/** Handle a webchat cancel (C→D `webchat/cancel`) — the status-bar "Cancel". Interrupts
|
|
214686
|
+
/** Handle a webchat cancel (the relay `cancel` op / status-bar "Cancel"). Interrupts
|
|
214723
214687
|
* the conversation's in-flight turn like `!cancel` (no mute; follow-ups still dispatch).
|
|
214724
|
-
* Resolved by conversationId (the
|
|
214725
|
-
handleWebchatCancel(
|
|
214726
|
-
for (const [acpSessionId, p] of this.pending) if (p.webchat?.conversationId ===
|
|
214688
|
+
* Resolved by conversationId (the op carries no agentId). No-op when idle. */
|
|
214689
|
+
handleWebchatCancel(conversationId) {
|
|
214690
|
+
for (const [acpSessionId, p] of this.pending) if (p.webchat?.conversationId === conversationId) {
|
|
214727
214691
|
this.interruptTurn(p.agentId, acpSessionId, p.sessionKey, "cancel");
|
|
214728
214692
|
return;
|
|
214729
214693
|
}
|
|
214730
|
-
this.log.debug(`webchat cancel: no in-flight turn for conversation ${
|
|
214694
|
+
this.log.debug(`webchat cancel: no in-flight turn for conversation ${conversationId}`);
|
|
214695
|
+
}
|
|
214696
|
+
relayMsgAcks = /* @__PURE__ */ new Map();
|
|
214697
|
+
/**
|
|
214698
|
+
* Dispatch one inbound relay webchat op (`rd/msg`) and return the `rd/ack` verdict —
|
|
214699
|
+
* the relay-path entry, reusing the SAME turn engine + by-key cores as the (retiring)
|
|
214700
|
+
* CP path. The `chat` callback streams the reply back as `rd/chat` over the relay
|
|
214701
|
+
* socket the op arrived on (wrapped into the sink).
|
|
214702
|
+
*
|
|
214703
|
+
* Deduped by the relay-minted (sessionKey, msgId): the wire is at-least-once, so a
|
|
214704
|
+
* retransmitted rd/msg (identical msgId) must NOT run the user's turn a second time —
|
|
214705
|
+
* replay the original ack (so the relay settles) without re-dispatching.
|
|
214706
|
+
*/
|
|
214707
|
+
handleRelayMsg(msg, chat) {
|
|
214708
|
+
const dedupKey = `${msg.sessionKey}:${msg.msgId}`;
|
|
214709
|
+
const prior = this.relayMsgAcks.get(dedupKey);
|
|
214710
|
+
if (prior) {
|
|
214711
|
+
this.log.debug(`relay: duplicate rd/msg ${dedupKey} — replaying ack (no re-dispatch)`);
|
|
214712
|
+
return prior;
|
|
214713
|
+
}
|
|
214714
|
+
const ack = this.dispatchRelayOp(msg, chat);
|
|
214715
|
+
if (this.relayMsgAcks.size >= 2e3) this.relayMsgAcks.clear();
|
|
214716
|
+
this.relayMsgAcks.set(dedupKey, ack);
|
|
214717
|
+
return ack;
|
|
214718
|
+
}
|
|
214719
|
+
/** The op-switch behind {@link handleRelayMsg} (dedup handled by the caller). */
|
|
214720
|
+
dispatchRelayOp(msg, chat) {
|
|
214721
|
+
const sink = {
|
|
214722
|
+
output: (o) => chat({
|
|
214723
|
+
kind: "output",
|
|
214724
|
+
output: o
|
|
214725
|
+
}),
|
|
214726
|
+
done: (d) => chat({
|
|
214727
|
+
kind: "done",
|
|
214728
|
+
done: d
|
|
214729
|
+
})
|
|
214730
|
+
};
|
|
214731
|
+
const op = msg.payload;
|
|
214732
|
+
const key = () => this.webchatSessionKey(msg.chatId, msg.agentId);
|
|
214733
|
+
switch (op.op) {
|
|
214734
|
+
case "turn": {
|
|
214735
|
+
const ack = this.dispatchWebchatTurn(msg.agentId, msg.chatId, op.text, op.user ?? "webchat", sink);
|
|
214736
|
+
return {
|
|
214737
|
+
msgId: msg.msgId,
|
|
214738
|
+
accepted: ack.accepted,
|
|
214739
|
+
turnId: ack.turnId,
|
|
214740
|
+
...ack.reason ? { reason: ack.reason } : {}
|
|
214741
|
+
};
|
|
214742
|
+
}
|
|
214743
|
+
case "set_model":
|
|
214744
|
+
this.setModelByKey(key(), op.model);
|
|
214745
|
+
return {
|
|
214746
|
+
msgId: msg.msgId,
|
|
214747
|
+
accepted: true
|
|
214748
|
+
};
|
|
214749
|
+
case "set_effort":
|
|
214750
|
+
this.setEffortByKey(key(), op.effort);
|
|
214751
|
+
return {
|
|
214752
|
+
msgId: msg.msgId,
|
|
214753
|
+
accepted: true
|
|
214754
|
+
};
|
|
214755
|
+
case "set_permission_mode":
|
|
214756
|
+
this.setPermissionModeByKey(key(), op.permissionMode);
|
|
214757
|
+
return {
|
|
214758
|
+
msgId: msg.msgId,
|
|
214759
|
+
accepted: true
|
|
214760
|
+
};
|
|
214761
|
+
case "set_fast":
|
|
214762
|
+
this.setFastByKey(key(), op.fastMode);
|
|
214763
|
+
return {
|
|
214764
|
+
msgId: msg.msgId,
|
|
214765
|
+
accepted: true
|
|
214766
|
+
};
|
|
214767
|
+
case "cancel":
|
|
214768
|
+
this.handleWebchatCancel(msg.chatId);
|
|
214769
|
+
return {
|
|
214770
|
+
msgId: msg.msgId,
|
|
214771
|
+
accepted: true
|
|
214772
|
+
};
|
|
214773
|
+
case "close":
|
|
214774
|
+
this.handleWebchatClose(msg.chatId);
|
|
214775
|
+
return {
|
|
214776
|
+
msgId: msg.msgId,
|
|
214777
|
+
accepted: true
|
|
214778
|
+
};
|
|
214779
|
+
}
|
|
214731
214780
|
}
|
|
214732
214781
|
/** Route a Slack status-bar Block Kit interaction (model / effort / fast select or the
|
|
214733
214782
|
* Cancel button) to the shared key-based cores. `sessionKey` rides the block; no-op on
|
|
@@ -215151,7 +215200,7 @@ var Daemon = class Daemon {
|
|
|
215151
215200
|
*/
|
|
215152
215201
|
surfaceTurnFailure(err, ctx) {
|
|
215153
215202
|
const reason = err?.message ?? String(err);
|
|
215154
|
-
if (ctx.webchat)
|
|
215203
|
+
if (ctx.webchat) ctx.webchat.sink.done({
|
|
215155
215204
|
conversationId: ctx.webchat.conversationId,
|
|
215156
215205
|
turnId: ctx.webchat.turnId,
|
|
215157
215206
|
error: reason
|
|
@@ -215273,7 +215322,7 @@ var Daemon = class Daemon {
|
|
|
215273
215322
|
kind: "text",
|
|
215274
215323
|
text: p.webchat.replyText
|
|
215275
215324
|
});
|
|
215276
|
-
|
|
215325
|
+
p.webchat.sink.done({
|
|
215277
215326
|
conversationId: p.webchat.conversationId,
|
|
215278
215327
|
turnId: p.webchat.turnId,
|
|
215279
215328
|
...stopReason ? { stopReason } : {},
|
|
@@ -215699,7 +215748,7 @@ var Daemon = class Daemon {
|
|
|
215699
215748
|
if (!Object.entries(info).some(([k, v]) => k !== "sessionId" && v !== void 0)) return;
|
|
215700
215749
|
p.lastStatusBar = key;
|
|
215701
215750
|
const wc = p.webchat;
|
|
215702
|
-
|
|
215751
|
+
wc.sink.output({
|
|
215703
215752
|
conversationId: wc.conversationId,
|
|
215704
215753
|
turnId: wc.turnId,
|
|
215705
215754
|
index: wc.index++,
|
|
@@ -215776,16 +215825,15 @@ var Daemon = class Daemon {
|
|
|
215776
215825
|
for (const ev of p.rec.onUpdate(update)) this.recordEvent(p.agentId, p.channel, p.statusThread, ev);
|
|
215777
215826
|
}
|
|
215778
215827
|
/**
|
|
215779
|
-
* Map one ACP SessionUpdate to a WebchatEvent and stream it
|
|
215780
|
-
* `
|
|
215781
|
-
*
|
|
215782
|
-
*
|
|
215783
|
-
* each with its own monotonic `index`.
|
|
215828
|
+
* Map one ACP SessionUpdate to a WebchatEvent and stream it through the sink (→ relay
|
|
215829
|
+
* `rd/chat`, webchat's "send"). Only the streamable chunk kinds map; usage/plan/
|
|
215830
|
+
* session_info are handled elsewhere or dropped. A single event whose inline text would
|
|
215831
|
+
* blow the 256 KiB frame cap is split across multiple chunks, each with its own `index`.
|
|
215784
215832
|
*/
|
|
215785
215833
|
emitWebchatUpdate(p, update) {
|
|
215786
215834
|
const wc = p.webchat;
|
|
215787
215835
|
const emit = (event) => {
|
|
215788
|
-
|
|
215836
|
+
wc.sink.output({
|
|
215789
215837
|
conversationId: wc.conversationId,
|
|
215790
215838
|
turnId: wc.turnId,
|
|
215791
215839
|
index: wc.index++,
|
|
@@ -216251,7 +216299,8 @@ var Daemon = class Daemon {
|
|
|
216251
216299
|
subprotocol: RELAY_DAEMON_SUBPROTOCOL,
|
|
216252
216300
|
path: RELAY_DAEMON_WS_PATH
|
|
216253
216301
|
}),
|
|
216254
|
-
log: this.log
|
|
216302
|
+
log: this.log,
|
|
216303
|
+
onRelayMsg: (msg, chat) => this.handleRelayMsg(msg, chat)
|
|
216255
216304
|
});
|
|
216256
216305
|
this.cpClient = new CpClient({
|
|
216257
216306
|
url,
|
|
@@ -216321,13 +216370,6 @@ var Daemon = class Daemon {
|
|
|
216321
216370
|
workspaceRead: createWorkspaceReader((id) => this.agents.get(id)?.workspace.path),
|
|
216322
216371
|
workspaceGit: createWorkspaceGit((id) => this.agents.get(id)?.workspace.path),
|
|
216323
216372
|
memoryReader: createMemoryReader((id) => this.agents.get(id)?.dir),
|
|
216324
|
-
onWebchatMessage: (m) => this.handleWebchatMessage(m),
|
|
216325
|
-
onWebchatClose: (m) => this.handleWebchatClose(m),
|
|
216326
|
-
onWebchatSetModel: (m) => this.handleWebchatSetModel(m),
|
|
216327
|
-
onWebchatSetEffort: (m) => this.handleWebchatSetEffort(m),
|
|
216328
|
-
onWebchatSetPermissionMode: (m) => this.handleWebchatSetPermissionMode(m),
|
|
216329
|
-
onWebchatSetFast: (m) => this.handleWebchatSetFast(m),
|
|
216330
|
-
onWebchatCancel: (m) => this.handleWebchatCancel(m),
|
|
216331
216373
|
clock: systemClock,
|
|
216332
216374
|
connect: () => ClientTransport.dial(url, {
|
|
216333
216375
|
subprotocol: CP_SUBPROTOCOL,
|
|
@@ -216459,4 +216501,4 @@ async function runForeground(opts, deps = {}) {
|
|
|
216459
216501
|
//#endregion
|
|
216460
216502
|
export { ClientTransport as i, CP_SUBPROTOCOL as n, CP_WS_PATH as r, runForeground as t };
|
|
216461
216503
|
|
|
216462
|
-
//# sourceMappingURL=run-foreground-
|
|
216504
|
+
//# sourceMappingURL=run-foreground-Cdxkfe7g.js.map
|