@agentconnect.md/daemon 1.0.0-rc.214 → 1.0.0-rc.216
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-C1MZcqZo.js → acp-host-D4Gc3jWq.js} +36 -16
- package/dist/{acp-host-C1MZcqZo.js.map → acp-host-D4Gc3jWq.js.map} +1 -1
- package/dist/{chat-BjhxExGt.js → chat-IAmHAZsX.js} +2 -2
- package/dist/{chat-BjhxExGt.js.map → chat-IAmHAZsX.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/{login-CmjeJfAo.js → login-CfZuYjo1.js} +3 -3
- package/dist/{login-CmjeJfAo.js.map → login-CfZuYjo1.js.map} +1 -1
- package/dist/{run-foreground-CD2uFFvp.js → run-foreground-BroK115h.js} +111 -17
- package/dist/run-foreground-BroK115h.js.map +1 -0
- package/dist/run-foreground-CXY4t5pU.js +2 -0
- package/package.json +1 -1
- package/dist/run-foreground-CD2uFFvp.js.map +0 -1
- package/dist/run-foreground-CdY92tUb.js +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as agentChildEnv, i as selectAgent, o as loadConfig } from "./load-agents-nWFFmN5-.js";
|
|
2
2
|
import { l as resolveRoot } from "./paths-DEcUO8lC.js";
|
|
3
|
-
import { _ as resolveRuntimes, i as prepareWorkspace, t as AcpHost } from "./acp-host-
|
|
3
|
+
import { _ as resolveRuntimes, i as prepareWorkspace, t as AcpHost } from "./acp-host-D4Gc3jWq.js";
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
5
|
//#region src/cli/chat.ts
|
|
6
6
|
function renderUpdate(out) {
|
|
@@ -75,4 +75,4 @@ async function runChat(opts) {
|
|
|
75
75
|
//#endregion
|
|
76
76
|
export { renderUpdate, runChat };
|
|
77
77
|
|
|
78
|
-
//# sourceMappingURL=chat-
|
|
78
|
+
//# sourceMappingURL=chat-IAmHAZsX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-
|
|
1
|
+
{"version":3,"file":"chat-IAmHAZsX.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 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,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
|
@@ -68501,9 +68501,9 @@ const telemetry = startDaemonOpenTelemetry({ serviceVersion: DAEMON_VERSION });
|
|
|
68501
68501
|
const [{ Command }, { fileURLToPath: fileURLToPath$1 }, { runChat }, { runLogin }, { runForeground }, { resolveController }, { acquireSingletonLock }, { resolveRoot }] = await Promise.all([
|
|
68502
68502
|
import("./commander-B5QVEFzH.js"),
|
|
68503
68503
|
import("node:url"),
|
|
68504
|
-
import("./chat-
|
|
68505
|
-
import("./login-
|
|
68506
|
-
import("./run-foreground-
|
|
68504
|
+
import("./chat-IAmHAZsX.js"),
|
|
68505
|
+
import("./login-CfZuYjo1.js"),
|
|
68506
|
+
import("./run-foreground-CXY4t5pU.js"),
|
|
68507
68507
|
import("./service-6w0WKhdx.js"),
|
|
68508
68508
|
import("./lock-CA9Bm8_s.js"),
|
|
68509
68509
|
import("./paths-CcRUjFjy.js")
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as DAEMON_VERSION } from "./version-DGaRXjBK.js";
|
|
2
2
|
import { c as ConfigSchema } from "./load-agents-nWFFmN5-.js";
|
|
3
3
|
import { l as resolveRoot, t as configPath } from "./paths-DEcUO8lC.js";
|
|
4
|
-
import { f as buildEnvelope, l as isFrame, m as encode, p as decodeEnvelope } from "./acp-host-
|
|
5
|
-
import { n as ClientTransport, t as runForeground } from "./run-foreground-
|
|
4
|
+
import { f as buildEnvelope, l as isFrame, m as encode, p as decodeEnvelope } from "./acp-host-D4Gc3jWq.js";
|
|
5
|
+
import { n as ClientTransport, t as runForeground } from "./run-foreground-BroK115h.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";
|
|
@@ -226,4 +226,4 @@ async function runLogin(opts, partial = {}) {
|
|
|
226
226
|
//#endregion
|
|
227
227
|
export { buildInstallOpts, persistCredentials, runLogin };
|
|
228
228
|
|
|
229
|
-
//# sourceMappingURL=login-
|
|
229
|
+
//# sourceMappingURL=login-CfZuYjo1.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-CmjeJfAo.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 './transport.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))\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-CfZuYjo1.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 './transport.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))\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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"}
|
|
@@ -3,7 +3,7 @@ import { n as require_ms, t as require_src$2 } from "./src-DDtlVutj.js";
|
|
|
3
3
|
import { t as DAEMON_VERSION } from "./version-DGaRXjBK.js";
|
|
4
4
|
import { a as agentChildEnv, i as selectAgent, n as findAgentFiles, o as loadConfig, r as loadAgents, s as persistDaemonId } from "./load-agents-nWFFmN5-.js";
|
|
5
5
|
import { l as resolveRoot, o as mcpSocketPath, u as statePath } from "./paths-DEcUO8lC.js";
|
|
6
|
-
import { _ as resolveRuntimes, a as initGitInjection, c as simpleGit, d as MAX_FRAME_BYTES, f as buildEnvelope, g as cachedRuntimeVersions, h as cachedRuntimeNames, i as prepareWorkspace, m as encode, n as installedRuntimes, o as probeGitVersion, p as decodeEnvelope, r as prefetchWorkspace, s as sessionGitEnv, t as AcpHost, u as normalizeGitUrl } from "./acp-host-
|
|
6
|
+
import { _ as resolveRuntimes, a as initGitInjection, c as simpleGit, d as MAX_FRAME_BYTES, f as buildEnvelope, g as cachedRuntimeVersions, h as cachedRuntimeNames, i as prepareWorkspace, m as encode, n as installedRuntimes, o as probeGitVersion, p as decodeEnvelope, r as prefetchWorkspace, s as sessionGitEnv, t as AcpHost, u as normalizeGitUrl } from "./acp-host-D4Gc3jWq.js";
|
|
7
7
|
import { i as GitCredentialCache, n as gitcredSocketPath, r as writeGitcredShim, t as GitCredServer } from "./gitcred-server-Dcsq6QJe.js";
|
|
8
8
|
import { n as encodeFrame, t as decodeFrames } from "./ipc-2Xbxe7uu.js";
|
|
9
9
|
import * as sp from "node:path";
|
|
@@ -5280,20 +5280,23 @@ function watch$1(paths, options = {}) {
|
|
|
5280
5280
|
/**
|
|
5281
5281
|
* Runtime config surfaced to the ACP child as environment variables, under
|
|
5282
5282
|
* `AGENTCONNECT_*` for runtimes that read them. ACP `session/new`/`initialize`
|
|
5283
|
-
* carry no model / effort
|
|
5284
|
-
*
|
|
5283
|
+
* carry no model / effort field (SDK v1); model + reasoning effort are
|
|
5284
|
+
* additionally applied per session via ACP session config options
|
|
5285
5285
|
* (`session/set_config_option`) when the runtime advertises the selectors —
|
|
5286
5286
|
* see AcpHost.applySessionConfig — which is how claude-acp actually honors
|
|
5287
|
-
* them. The env
|
|
5288
|
-
*
|
|
5289
|
-
*
|
|
5287
|
+
* them. The env stays the fallback for runtimes without config options.
|
|
5288
|
+
*
|
|
5289
|
+
* The system prompt is NOT here: it rides `_meta.systemPrompt` on
|
|
5290
|
+
* session/new|load for Claude runtimes (see claudeSessionMeta), and for other
|
|
5291
|
+
* runtimes it's inlined as the first prompt text block (see AcpHost.inlineSystemPrompt
|
|
5292
|
+
* + SessionManager). (`runtimeOverrides.env` is applied separately by
|
|
5293
|
+
* `agentChildEnv`.) Only emits a key when the value is set.
|
|
5290
5294
|
*/
|
|
5291
5295
|
function cpRuntimeEnv(agent) {
|
|
5292
5296
|
const out = {};
|
|
5293
5297
|
if (agent.runtimeOverrides?.model) out.AGENTCONNECT_MODEL = agent.runtimeOverrides.model;
|
|
5294
5298
|
if (agent.reasoningEffort) out.AGENTCONNECT_REASONING_EFFORT = agent.reasoningEffort;
|
|
5295
5299
|
if (agent.executionMode) out.AGENTCONNECT_EXECUTION_MODE = agent.executionMode;
|
|
5296
|
-
if (agent.description) out.AGENTCONNECT_SYSTEM_PROMPT = agent.description;
|
|
5297
5300
|
return out;
|
|
5298
5301
|
}
|
|
5299
5302
|
//#endregion
|
|
@@ -5925,6 +5928,13 @@ var SessionManager = class {
|
|
|
5925
5928
|
});
|
|
5926
5929
|
blocks.push(...attBlocks);
|
|
5927
5930
|
}
|
|
5931
|
+
if (created) {
|
|
5932
|
+
const inlineSystemPrompt = host.inlineSystemPrompt?.();
|
|
5933
|
+
if (inlineSystemPrompt) blocks.unshift({
|
|
5934
|
+
type: "text",
|
|
5935
|
+
text: inlineSystemPrompt
|
|
5936
|
+
});
|
|
5937
|
+
}
|
|
5928
5938
|
rec.lastDeliveredTs = ts;
|
|
5929
5939
|
rec.state = "prompting";
|
|
5930
5940
|
rec.updatedAt = Date.now();
|
|
@@ -62578,6 +62588,22 @@ function capOutput(s) {
|
|
|
62578
62588
|
const t = s.trim();
|
|
62579
62589
|
return t.length > MAX_TOOL_OUTPUT ? `${t.slice(0, MAX_TOOL_OUTPUT - 1)}…` : t;
|
|
62580
62590
|
}
|
|
62591
|
+
/** The per-turn attribution footer: a Slack `context` block — small, secondary/gray text
|
|
62592
|
+
* reading "sent by agentconnect.md", the name linking to the Web App console (`webAppUrl`).
|
|
62593
|
+
* Context blocks use mrkdwn (`<url|text>`), not the CommonMark of `markdown` blocks. `text`
|
|
62594
|
+
* is the notification/accessibility fallback. */
|
|
62595
|
+
function attributionBlocks(webAppUrl) {
|
|
62596
|
+
return {
|
|
62597
|
+
text: "sent by agentconnect.md",
|
|
62598
|
+
blocks: [{
|
|
62599
|
+
type: "context",
|
|
62600
|
+
elements: [{
|
|
62601
|
+
type: "mrkdwn",
|
|
62602
|
+
text: `sent by <${webAppUrl}|agentconnect.md>`
|
|
62603
|
+
}]
|
|
62604
|
+
}]
|
|
62605
|
+
};
|
|
62606
|
+
}
|
|
62581
62607
|
/** Pull human-readable output text out of an ACP tool_call/_update. Prefers the `content[]`
|
|
62582
62608
|
* text blocks (the tool's reported output); falls back to a string `rawOutput`. diff /
|
|
62583
62609
|
* terminal blocks and non-string rawOutput are skipped — they have no compact inline text. */
|
|
@@ -63017,12 +63043,20 @@ var OutputConverger = class {
|
|
|
63017
63043
|
* — in medium/high — append a footer linking to the Web App session detail. The
|
|
63018
63044
|
* link is omitted entirely when none is configured (no `local://` placeholder).
|
|
63019
63045
|
*/
|
|
63020
|
-
onFinal(link) {
|
|
63046
|
+
onFinal(link, webAppUrl) {
|
|
63021
63047
|
const clear = {
|
|
63022
63048
|
kind: "set-status",
|
|
63023
63049
|
text: ""
|
|
63024
63050
|
};
|
|
63025
|
-
|
|
63051
|
+
const attribution = webAppUrl ? [{
|
|
63052
|
+
kind: "attribution",
|
|
63053
|
+
...attributionBlocks(webAppUrl)
|
|
63054
|
+
}] : [];
|
|
63055
|
+
if (this.mode === "low") return [
|
|
63056
|
+
...this.flush(),
|
|
63057
|
+
clear,
|
|
63058
|
+
...attribution
|
|
63059
|
+
];
|
|
63026
63060
|
const reasoning = this.drainReasoning();
|
|
63027
63061
|
const footer = link ? [{
|
|
63028
63062
|
kind: "notice",
|
|
@@ -63032,7 +63066,8 @@ var OutputConverger = class {
|
|
|
63032
63066
|
...reasoning,
|
|
63033
63067
|
...this.flush(),
|
|
63034
63068
|
clear,
|
|
63035
|
-
...footer
|
|
63069
|
+
...footer,
|
|
63070
|
+
...attribution
|
|
63036
63071
|
];
|
|
63037
63072
|
}
|
|
63038
63073
|
};
|
|
@@ -63252,6 +63287,22 @@ var SlackConnection = class {
|
|
|
63252
63287
|
}))?.ts;
|
|
63253
63288
|
});
|
|
63254
63289
|
}
|
|
63290
|
+
/** Post a one-shot Block Kit `context` message — the per-turn "sent by agentconnect.md"
|
|
63291
|
+
* attribution footer (small secondary/gray text). Fire-and-forget: unlike the status bar
|
|
63292
|
+
* its ts is never kept for edits, so nothing is returned. `unfurl_*` off so the console
|
|
63293
|
+
* link doesn't sprout a preview card. */
|
|
63294
|
+
async postContext(channel, blocks, text, threadTs) {
|
|
63295
|
+
await this.queue.enqueue(async () => {
|
|
63296
|
+
await this.app.client.chat.postMessage({
|
|
63297
|
+
channel,
|
|
63298
|
+
thread_ts: threadTs,
|
|
63299
|
+
text,
|
|
63300
|
+
blocks,
|
|
63301
|
+
unfurl_links: false,
|
|
63302
|
+
unfurl_media: false
|
|
63303
|
+
});
|
|
63304
|
+
});
|
|
63305
|
+
}
|
|
63255
63306
|
/** Edit a previously-posted Block Kit message in place (chat.update). Best-effort.
|
|
63256
63307
|
* `unfurl_links: false` keeps an edit from unfurling the "View session" URL. */
|
|
63257
63308
|
async updateBlocks(channel, ts, blocks, text) {
|
|
@@ -81833,7 +81884,10 @@ var Daemon = class Daemon {
|
|
|
81833
81884
|
const skipped = Object.keys(resolvedRuntimes).filter((id) => !this.runtimes[id]);
|
|
81834
81885
|
if (skipped.length) this.log.info(`runtimes not installed (skipped): ${skipped.join(", ")}`);
|
|
81835
81886
|
this.store = new LocalStore(statePath(root));
|
|
81836
|
-
this.nameResolver = new SlackNameResolver((id, name) =>
|
|
81887
|
+
this.nameResolver = new SlackNameResolver((id, name) => {
|
|
81888
|
+
this.store.setDisplayName(id, name, Date.now());
|
|
81889
|
+
this.emitSessionMetadataSnapshotsForDisplayName(id);
|
|
81890
|
+
}, this.log);
|
|
81837
81891
|
this.cpRouting = new CpRoutingLayer({
|
|
81838
81892
|
load: () => {
|
|
81839
81893
|
const row = this.store.getCpRouting();
|
|
@@ -82125,7 +82179,11 @@ var Daemon = class Daemon {
|
|
|
82125
82179
|
try {
|
|
82126
82180
|
const channels = await conn.listBotChannels();
|
|
82127
82181
|
if (!channels) return;
|
|
82128
|
-
for (const c of channels)
|
|
82182
|
+
for (const c of channels) {
|
|
82183
|
+
if (!c.name) continue;
|
|
82184
|
+
this.store.setDisplayName(c.id, c.name, Date.now());
|
|
82185
|
+
this.emitSessionMetadataSnapshotsForDisplayName(c.id);
|
|
82186
|
+
}
|
|
82129
82187
|
for (const [integrationId, c] of this.connByIntegration) {
|
|
82130
82188
|
if (c !== conn) continue;
|
|
82131
82189
|
this.channelSnapshots.set(integrationId, channels);
|
|
@@ -82158,7 +82216,8 @@ var Daemon = class Daemon {
|
|
|
82158
82216
|
configPrefs: {
|
|
82159
82217
|
model: agent.runtimeOverrides?.model,
|
|
82160
82218
|
reasoningEffort: agent.reasoningEffort,
|
|
82161
|
-
fastMode: agent.fastMode
|
|
82219
|
+
fastMode: agent.fastMode,
|
|
82220
|
+
systemPrompt: agent.description
|
|
82162
82221
|
},
|
|
82163
82222
|
log: this.log
|
|
82164
82223
|
});
|
|
@@ -82656,7 +82715,7 @@ var Daemon = class Daemon {
|
|
|
82656
82715
|
});
|
|
82657
82716
|
} else {
|
|
82658
82717
|
const link = this.sessionLink(sessionId);
|
|
82659
|
-
for (const action of conv.onFinal(link)) this.enqueueApply(p, action);
|
|
82718
|
+
for (const action of conv.onFinal(link, this.webAppBase())) this.enqueueApply(p, action);
|
|
82660
82719
|
}
|
|
82661
82720
|
for (const ev of rec.onFinal()) this.recordEvent(agentId, msg.channel, statusThread, ev);
|
|
82662
82721
|
await p.applyChain;
|
|
@@ -82756,6 +82815,9 @@ var Daemon = class Daemon {
|
|
|
82756
82815
|
case "tool-output":
|
|
82757
82816
|
await conn.postMessage(p.channel, action.text, p.thread);
|
|
82758
82817
|
return;
|
|
82818
|
+
case "attribution":
|
|
82819
|
+
await conn.postContext(p.channel, action.blocks, action.text, p.thread);
|
|
82820
|
+
return;
|
|
82759
82821
|
case "progress":
|
|
82760
82822
|
if (p.progressTs) await conn.updateMessage(p.channel, p.progressTs, action.text);
|
|
82761
82823
|
else if (!p.progressAttempted) {
|
|
@@ -82799,7 +82861,14 @@ var Daemon = class Daemon {
|
|
|
82799
82861
|
* known; without it the link falls back to `<base>/sessions/<id>`. Always resolves, so
|
|
82800
82862
|
* the View-session link is always available. */
|
|
82801
82863
|
sessionLink(acpSessionId) {
|
|
82802
|
-
|
|
82864
|
+
const orgSeg = this.cpOrgSlug ? `/${encodeURIComponent(this.cpOrgSlug)}` : "";
|
|
82865
|
+
return `${this.webAppBase()}${orgSeg}/sessions/${acpSessionId}`;
|
|
82866
|
+
}
|
|
82867
|
+
/** The Web App console origin (trailing slash stripped): the explicit local `webAppUrl`,
|
|
82868
|
+
* else the CP-provided origin, else the public default. Backs both the session deep link
|
|
82869
|
+
* and the per-turn "sent by agentconnect.md" attribution footer. Always resolves. */
|
|
82870
|
+
webAppBase() {
|
|
82871
|
+
return (this.cfg.webAppUrl ?? this.cpWebAppUrl ?? DEFAULT_WEB_APP_URL).replace(/\/$/, "");
|
|
82803
82872
|
}
|
|
82804
82873
|
sessionListProjection(sessionId, agentId) {
|
|
82805
82874
|
return createSessionReader(this.store, (id) => this.replyConnFor(id)?.workspaceUrl).list({ agentId }).sessions.find((s) => s.sessionId === sessionId);
|
|
@@ -82838,6 +82907,21 @@ var Daemon = class Daemon {
|
|
|
82838
82907
|
this.log.debug(`event/session emit failed (session ${input.sessionId}): ${err.message}`);
|
|
82839
82908
|
}
|
|
82840
82909
|
}
|
|
82910
|
+
emitSessionMetadataSnapshotsForDisplayName(id) {
|
|
82911
|
+
if (!this.cpClient) return;
|
|
82912
|
+
for (const row of this.store.listSessions()) {
|
|
82913
|
+
if (!row.acpSessionId) continue;
|
|
82914
|
+
if (row.channel !== id && row.triggeredBy !== id) continue;
|
|
82915
|
+
this.emitSessionMetadataSnapshot({
|
|
82916
|
+
sessionId: row.acpSessionId,
|
|
82917
|
+
agentId: row.agentId,
|
|
82918
|
+
phase: "plan",
|
|
82919
|
+
platform: row.platform,
|
|
82920
|
+
channel: row.channel,
|
|
82921
|
+
thread: row.thread
|
|
82922
|
+
});
|
|
82923
|
+
}
|
|
82924
|
+
}
|
|
82841
82925
|
/** Assemble a status snapshot from the parts (agent config + host model selector +
|
|
82842
82926
|
* folded ACP usage). Shared by `buildStatusInfo` (per-turn Pending) and
|
|
82843
82927
|
* `statusInfoForKey` (the ⚙-modal, keyed by session). */
|
|
@@ -82951,7 +83035,17 @@ var Daemon = class Daemon {
|
|
|
82951
83035
|
});
|
|
82952
83036
|
this.emitStatusBar(p);
|
|
82953
83037
|
}
|
|
82954
|
-
if (update?.sessionUpdate === "session_info_update" && update.title !== void 0)
|
|
83038
|
+
if (update?.sessionUpdate === "session_info_update" && update.title !== void 0) {
|
|
83039
|
+
this.store.setSessionTitle(p.sessionKey, update.title);
|
|
83040
|
+
this.emitSessionMetadataSnapshot({
|
|
83041
|
+
sessionId,
|
|
83042
|
+
agentId: p.agentId,
|
|
83043
|
+
phase: "plan",
|
|
83044
|
+
platform: p.platform,
|
|
83045
|
+
channel: p.channel,
|
|
83046
|
+
thread: p.statusThread
|
|
83047
|
+
});
|
|
83048
|
+
}
|
|
82955
83049
|
if (p.webchat) this.emitWebchatUpdate(p, update);
|
|
82956
83050
|
else {
|
|
82957
83051
|
for (const action of p.conv.onUpdate(update)) this.enqueueApply(p, action);
|
|
@@ -83603,4 +83697,4 @@ async function runForeground(opts, deps = {}) {
|
|
|
83603
83697
|
//#endregion
|
|
83604
83698
|
export { ClientTransport as n, runForeground as t };
|
|
83605
83699
|
|
|
83606
|
-
//# sourceMappingURL=run-foreground-
|
|
83700
|
+
//# sourceMappingURL=run-foreground-BroK115h.js.map
|