@parlor/agent-host 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/acp.d.ts +21 -0
  2. package/dist/acp.d.ts.map +1 -1
  3. package/dist/acp.js +138 -12
  4. package/dist/acp.js.map +1 -1
  5. package/dist/agent-options.d.ts +22 -0
  6. package/dist/agent-options.d.ts.map +1 -0
  7. package/dist/agent-options.js +105 -0
  8. package/dist/agent-options.js.map +1 -0
  9. package/dist/agent-survey.d.ts +15 -0
  10. package/dist/agent-survey.d.ts.map +1 -0
  11. package/dist/agent-survey.js +51 -0
  12. package/dist/agent-survey.js.map +1 -0
  13. package/dist/agent-tools.d.ts +30 -0
  14. package/dist/agent-tools.d.ts.map +1 -0
  15. package/dist/agent-tools.js +71 -0
  16. package/dist/agent-tools.js.map +1 -0
  17. package/dist/codex-app-server.d.ts +7 -0
  18. package/dist/codex-app-server.d.ts.map +1 -0
  19. package/dist/codex-app-server.js +46 -0
  20. package/dist/codex-app-server.js.map +1 -0
  21. package/dist/control.d.ts +15 -0
  22. package/dist/control.d.ts.map +1 -1
  23. package/dist/control.js.map +1 -1
  24. package/dist/daemon.d.ts +10 -2
  25. package/dist/daemon.d.ts.map +1 -1
  26. package/dist/daemon.js +217 -16
  27. package/dist/daemon.js.map +1 -1
  28. package/dist/fold.d.ts.map +1 -1
  29. package/dist/fold.js +2 -0
  30. package/dist/fold.js.map +1 -1
  31. package/dist/grants.d.ts +9 -0
  32. package/dist/grants.d.ts.map +1 -1
  33. package/dist/grants.js.map +1 -1
  34. package/dist/learned.d.ts +25 -0
  35. package/dist/learned.d.ts.map +1 -0
  36. package/dist/learned.js +37 -0
  37. package/dist/learned.js.map +1 -0
  38. package/dist/link.d.ts +3 -1
  39. package/dist/link.d.ts.map +1 -1
  40. package/dist/link.js +23 -1
  41. package/dist/link.js.map +1 -1
  42. package/dist/main.js +105 -9
  43. package/dist/main.js.map +1 -1
  44. package/dist/mcp-proxy.d.ts +26 -3
  45. package/dist/mcp-proxy.d.ts.map +1 -1
  46. package/dist/mcp-proxy.js +288 -25
  47. package/dist/mcp-proxy.js.map +1 -1
  48. package/dist/pairing.d.ts +2 -0
  49. package/dist/pairing.d.ts.map +1 -1
  50. package/dist/pairing.js +25 -3
  51. package/dist/pairing.js.map +1 -1
  52. package/dist/paths.d.ts +2 -0
  53. package/dist/paths.d.ts.map +1 -1
  54. package/dist/paths.js +1 -0
  55. package/dist/paths.js.map +1 -1
  56. package/dist/policy.d.ts +12 -2
  57. package/dist/policy.d.ts.map +1 -1
  58. package/dist/policy.js +13 -3
  59. package/dist/policy.js.map +1 -1
  60. package/dist/prompter.d.ts +5 -0
  61. package/dist/prompter.d.ts.map +1 -1
  62. package/dist/prompter.js +15 -0
  63. package/dist/prompter.js.map +1 -1
  64. package/dist/spec-kit.d.ts +4 -1
  65. package/dist/spec-kit.d.ts.map +1 -1
  66. package/dist/spec-kit.js +12 -2
  67. package/dist/spec-kit.js.map +1 -1
  68. package/dist/testing/fake-agent.d.ts +12 -0
  69. package/dist/testing/fake-agent.d.ts.map +1 -1
  70. package/dist/testing/fake-agent.js +11 -1
  71. package/dist/testing/fake-agent.js.map +1 -1
  72. package/dist/turn.d.ts +7 -1
  73. package/dist/turn.d.ts.map +1 -1
  74. package/dist/turn.js +16 -3
  75. package/dist/turn.js.map +1 -1
  76. package/package.json +9 -9
@@ -0,0 +1,71 @@
1
+ import { execFile } from "node:child_process";
2
+ import { logEvent } from "./log.js";
3
+ import { appServerOf } from "./naming.js";
4
+ const LOCAL_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
5
+ /**
6
+ * The app's name, with its host and port when it is not a deployed site on the default
7
+ * port: `coursekit`, or `coursekit-localhost-7001` beside it.
8
+ */
9
+ export function agentToolsName(appName, appOrigin) {
10
+ const url = new URL(appOrigin);
11
+ const base = appServerOf(appName);
12
+ if (!LOCAL_HOSTS.has(url.hostname) && url.port === "")
13
+ return base;
14
+ const where = url.host
15
+ .toLowerCase()
16
+ .replace(/[^a-z0-9]+/g, "-")
17
+ .replace(/^-+|-+$/g, "");
18
+ return `${base}-${where}`;
19
+ }
20
+ const REGISTRARS = {
21
+ claude: {
22
+ add: (name, command) => ["mcp", "add", "--scope", "user", name, "--", ...command],
23
+ remove: (name) => ["mcp", "remove", "--scope", "user", name],
24
+ },
25
+ codex: {
26
+ add: (name, command) => ["mcp", "add", name, "--", ...command],
27
+ remove: (name) => ["mcp", "remove", name],
28
+ },
29
+ };
30
+ function run(binary, args, env) {
31
+ return new Promise((resolve) => {
32
+ execFile(binary, [...args], { env, timeout: 30_000 }, (error) => resolve(!error));
33
+ });
34
+ }
35
+ /** Registers `appOrigin` with every installed agent that has a CLI for it; returns those that took it. */
36
+ export async function registerAgentTools(deps, app) {
37
+ const name = agentToolsName(app.appName, app.appOrigin);
38
+ const command = [deps.hostCommand, "mcp-proxy", "--app", app.appOrigin];
39
+ const env = await deps.env();
40
+ const agents = [];
41
+ for (const profile of deps.profiles) {
42
+ const registrar = REGISTRARS[profile.id];
43
+ if (!registrar)
44
+ continue;
45
+ await run(profile.binary, registrar.remove(name), env);
46
+ if (await run(profile.binary, registrar.add(name, command), env))
47
+ agents.push(profile.id);
48
+ }
49
+ logEvent("agent_tools_registered", { appOrigin: app.appOrigin, name, agents });
50
+ return { name, agents };
51
+ }
52
+ /** Removes the app from the agents it was registered with; an agent already rid of it is fine. */
53
+ export async function unregisterAgentTools(deps, tools) {
54
+ const env = await deps.env();
55
+ for (const id of tools.agents) {
56
+ const registrar = REGISTRARS[id];
57
+ const profile = deps.profiles.find((candidate) => candidate.id === id);
58
+ if (!registrar || !profile)
59
+ continue;
60
+ await run(profile.binary, registrar.remove(tools.name), env);
61
+ }
62
+ logEvent("agent_tools_removed", { name: tools.name, agents: tools.agents });
63
+ }
64
+ /** The agents an `AgentTools` names, as people know them: "Claude Code and Codex". */
65
+ export function agentNames(profiles, tools) {
66
+ const names = tools.agents.map((id) => profiles.find((profile) => profile.id === id)?.name ?? id);
67
+ return names.length <= 1
68
+ ? (names[0] ?? "")
69
+ : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
70
+ }
71
+ //# sourceMappingURL=agent-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-tools.js","sourceRoot":"","sources":["../src/agent-tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\n\nimport type { AgentProfile } from \"./agents.js\";\nimport { logEvent } from \"./log.js\";\nimport { appServerOf } from \"./naming.js\";\n\n/** What a grant hands the coding agents on this computer, outside the app's sidebar. */\nexport interface AgentTools {\n /** The MCP server name the agents know the app by, and the name the user asks them with. */\n readonly name: string;\n /** The agents it is registered with, by profile id. */\n readonly agents: readonly string[];\n}\n\nconst LOCAL_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/**\n * The app's name, with its host and port when it is not a deployed site on the default\n * port: `coursekit`, or `coursekit-localhost-7001` beside it.\n */\nexport function agentToolsName(appName: string, appOrigin: string): string {\n const url = new URL(appOrigin);\n const base = appServerOf(appName);\n if (!LOCAL_HOSTS.has(url.hostname) && url.port === \"\") return base;\n const where = url.host\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return `${base}-${where}`;\n}\n\n/** How one coding agent's own CLI adds and removes a user-wide stdio MCP server. */\ninterface Registrar {\n add(name: string, command: readonly string[]): readonly string[];\n remove(name: string): readonly string[];\n}\n\nconst REGISTRARS: Readonly<Record<string, Registrar>> = {\n claude: {\n add: (name, command) => [\"mcp\", \"add\", \"--scope\", \"user\", name, \"--\", ...command],\n remove: (name) => [\"mcp\", \"remove\", \"--scope\", \"user\", name],\n },\n codex: {\n add: (name, command) => [\"mcp\", \"add\", name, \"--\", ...command],\n remove: (name) => [\"mcp\", \"remove\", name],\n },\n};\n\nexport interface AgentToolsDeps {\n /** The installed agents; only those with a known CLI are registered with. */\n readonly profiles: readonly AgentProfile[];\n /** The absolute path of `parlor-host`, which the agents launch as the MCP server. */\n readonly hostCommand: string;\n readonly env: () => Promise<Record<string, string>>;\n}\n\nfunction run(\n binary: string,\n args: readonly string[],\n env: Record<string, string>,\n): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(binary, [...args], { env, timeout: 30_000 }, (error) => resolve(!error));\n });\n}\n\n/** Registers `appOrigin` with every installed agent that has a CLI for it; returns those that took it. */\nexport async function registerAgentTools(\n deps: AgentToolsDeps,\n app: { readonly appName: string; readonly appOrigin: string },\n): Promise<AgentTools> {\n const name = agentToolsName(app.appName, app.appOrigin);\n const command = [deps.hostCommand, \"mcp-proxy\", \"--app\", app.appOrigin];\n const env = await deps.env();\n const agents: string[] = [];\n for (const profile of deps.profiles) {\n const registrar = REGISTRARS[profile.id];\n if (!registrar) continue;\n await run(profile.binary, registrar.remove(name), env);\n if (await run(profile.binary, registrar.add(name, command), env))\n agents.push(profile.id);\n }\n logEvent(\"agent_tools_registered\", { appOrigin: app.appOrigin, name, agents });\n return { name, agents };\n}\n\n/** Removes the app from the agents it was registered with; an agent already rid of it is fine. */\nexport async function unregisterAgentTools(\n deps: AgentToolsDeps,\n tools: AgentTools,\n): Promise<void> {\n const env = await deps.env();\n for (const id of tools.agents) {\n const registrar = REGISTRARS[id];\n const profile = deps.profiles.find((candidate) => candidate.id === id);\n if (!registrar || !profile) continue;\n await run(profile.binary, registrar.remove(tools.name), env);\n }\n logEvent(\"agent_tools_removed\", { name: tools.name, agents: tools.agents });\n}\n\n/** The agents an `AgentTools` names, as people know them: \"Claude Code and Codex\". */\nexport function agentNames(profiles: readonly AgentProfile[], tools: AgentTools): string {\n const names = tools.agents.map(\n (id) => profiles.find((profile) => profile.id === id)?.name ?? id,\n );\n return names.length <= 1\n ? (names[0] ?? \"\")\n : `${names.slice(0, -1).join(\", \")} and ${names.at(-1)}`;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * One JSON-RPC call to a Codex app-server of its own, started for it and stopped after. For
3
+ * what Codex keeps but `codex-acp` drops, such as the account's rate limits; it costs no
4
+ * model turn. Undefined when anything goes wrong: Codex is missing, slow, or answers oddly.
5
+ */
6
+ export declare function askCodex(binary: string, method: string, params: unknown, env: Readonly<Record<string, string>>): Promise<unknown>;
7
+ //# sourceMappingURL=codex-app-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-app-server.d.ts","sourceRoot":"","sources":["../src/codex-app-server.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GACpC,OAAO,CAAC,OAAO,CAAC,CA+BlB"}
@@ -0,0 +1,46 @@
1
+ import { spawn } from "node:child_process";
2
+ import { onLines } from "./lines.js";
3
+ const INITIALIZE = 1;
4
+ const CALL = 2;
5
+ const TIMEOUT_MS = 30_000;
6
+ /** Codex only echoes it back inside a user agent. */
7
+ const CLIENT_INFO = { name: "parlor-host", version: "1" };
8
+ /**
9
+ * One JSON-RPC call to a Codex app-server of its own, started for it and stopped after. For
10
+ * what Codex keeps but `codex-acp` drops, such as the account's rate limits; it costs no
11
+ * model turn. Undefined when anything goes wrong: Codex is missing, slow, or answers oddly.
12
+ */
13
+ export function askCodex(binary, method, params, env) {
14
+ return new Promise((resolve) => {
15
+ let answer;
16
+ const child = spawn(binary, ["app-server"], {
17
+ env,
18
+ stdio: ["pipe", "pipe", "ignore"],
19
+ });
20
+ const timer = setTimeout(() => child.kill("SIGKILL"), TIMEOUT_MS);
21
+ const send = (message) => child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", ...message })}\n`);
22
+ onLines(child.stdout, (line) => {
23
+ let message;
24
+ try {
25
+ message = JSON.parse(line);
26
+ }
27
+ catch {
28
+ return;
29
+ }
30
+ if (message.id === INITIALIZE)
31
+ send({ id: CALL, method, params });
32
+ else if (message.id === CALL) {
33
+ answer = message.result;
34
+ child.kill();
35
+ }
36
+ });
37
+ child.stdin.on("error", () => undefined);
38
+ child.once("error", () => resolve(undefined));
39
+ child.once("close", () => {
40
+ clearTimeout(timer);
41
+ resolve(answer);
42
+ });
43
+ send({ id: INITIALIZE, method: "initialize", params: { clientInfo: CLIENT_INFO } });
44
+ });
45
+ }
46
+ //# sourceMappingURL=codex-app-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-app-server.js","sourceRoot":"","sources":["../src/codex-app-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC,MAAM,UAAU,GAAG,CAAC,CAAC;AACrB,MAAM,IAAI,GAAG,CAAC,CAAC;AACf,MAAM,UAAU,GAAG,MAAM,CAAC;AAC1B,qDAAqD;AACrD,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;AAE1D;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CACtB,MAAc,EACd,MAAc,EACd,MAAe,EACf,GAAqC;IAErC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,MAAe,CAAC;QACpB,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,EAAE;YAC1C,GAAG;YACH,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;SAClC,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC,CAAC;QAClE,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,EAAE,CAC/B,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;QAC3E,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC7B,IAAI,OAA6D,CAAC;YAClE,IAAI,CAAC;gBACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO;YACT,CAAC;YACD,IAAI,OAAO,CAAC,EAAE,KAAK,UAAU;gBAAE,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;iBAC7D,IAAI,OAAO,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC7B,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;gBACxB,KAAK,CAAC,IAAI,EAAE,CAAC;YACf,CAAC;QACH,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;QAC9C,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { spawn } from \"node:child_process\";\n\nimport { onLines } from \"./lines.js\";\n\nconst INITIALIZE = 1;\nconst CALL = 2;\nconst TIMEOUT_MS = 30_000;\n/** Codex only echoes it back inside a user agent. */\nconst CLIENT_INFO = { name: \"parlor-host\", version: \"1\" };\n\n/**\n * One JSON-RPC call to a Codex app-server of its own, started for it and stopped after. For\n * what Codex keeps but `codex-acp` drops, such as the account's rate limits; it costs no\n * model turn. Undefined when anything goes wrong: Codex is missing, slow, or answers oddly.\n */\nexport function askCodex(\n binary: string,\n method: string,\n params: unknown,\n env: Readonly<Record<string, string>>,\n): Promise<unknown> {\n return new Promise((resolve) => {\n let answer: unknown;\n const child = spawn(binary, [\"app-server\"], {\n env,\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n });\n const timer = setTimeout(() => child.kill(\"SIGKILL\"), TIMEOUT_MS);\n const send = (message: object) =>\n child.stdin.write(`${JSON.stringify({ jsonrpc: \"2.0\", ...message })}\\n`);\n onLines(child.stdout, (line) => {\n let message: { readonly id?: unknown; readonly result?: unknown };\n try {\n message = JSON.parse(line) as typeof message;\n } catch {\n return;\n }\n if (message.id === INITIALIZE) send({ id: CALL, method, params });\n else if (message.id === CALL) {\n answer = message.result;\n child.kill();\n }\n });\n child.stdin.on(\"error\", () => undefined);\n child.once(\"error\", () => resolve(undefined));\n child.once(\"close\", () => {\n clearTimeout(timer);\n resolve(answer);\n });\n send({ id: INITIALIZE, method: \"initialize\", params: { clientInfo: CLIENT_INFO } });\n });\n}\n"]}
package/dist/control.d.ts CHANGED
@@ -32,6 +32,10 @@ export type ControlRequest = {
32
32
  } | {
33
33
  readonly op: "disconnect";
34
34
  readonly appOrigin: string;
35
+ } | {
36
+ readonly op: "agent_tools";
37
+ readonly appOrigin: string;
38
+ readonly on: boolean;
35
39
  } | {
36
40
  readonly op: "dev_attach";
37
41
  readonly appOrigin: string;
@@ -46,6 +50,11 @@ export interface GrantSummary {
46
50
  readonly appName: string;
47
51
  readonly grantId: string;
48
52
  }
53
+ /** The app's MCP server name in the coding agents on this computer, and which have it. */
54
+ export interface AgentToolsSummary {
55
+ readonly name: string;
56
+ readonly agents: string;
57
+ }
49
58
  export type ControlFailure = {
50
59
  readonly ok: false;
51
60
  readonly error: string;
@@ -68,6 +77,7 @@ interface ControlReplies {
68
77
  };
69
78
  readonly connect: {
70
79
  readonly ok: true;
80
+ readonly agentTools?: AgentToolsSummary;
71
81
  };
72
82
  readonly begin_local_pairing: {
73
83
  readonly ok: true;
@@ -87,6 +97,11 @@ interface ControlReplies {
87
97
  };
88
98
  readonly disconnect: {
89
99
  readonly ok: true;
100
+ readonly agentTools?: AgentToolsSummary;
101
+ };
102
+ readonly agent_tools: {
103
+ readonly ok: true;
104
+ readonly agentTools?: AgentToolsSummary;
90
105
  };
91
106
  readonly dev_attach: {
92
107
  readonly ok: true;
@@ -1 +1 @@
1
- {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGxF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/D,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,EAAE,EAAE,qBAAqB,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClE;IACE,QAAQ,CAAC,EAAE,EAAE,sBAAsB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,GACD;IACE,QAAQ,CAAC,EAAE,EAAE,uBAAuB,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;CACjC,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACrF;IAAE,QAAQ,CAAC,EAAE,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9D,MAAM,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;AAE7C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,UAAU,cAAc;IACtB,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;KAAE,CAAC;IACrE,QAAQ,CAAC,QAAQ,EACb;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,GACrB;QAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAAA;KAAE,CAAC;IACrE,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;QAClB,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;QACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;KAC1C,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IACxC,QAAQ,CAAC,mBAAmB,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAA;KAAE,CAAC;IACnF,QAAQ,CAAC,oBAAoB,EAAE;QAC7B,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;QAClB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;KAC/B,CAAC;IACF,QAAQ,CAAC,qBAAqB,EAC1B;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,GACrB;QAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAA;KAAE,CAAC;IAC/D,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;CAC5C;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,SAAS,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC;AAEtF,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,CAAC,SAAS,cAAc,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9E,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wDAAwD;AACxD,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CA8BpC"}
1
+ {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAInC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAsElC,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAkB;IAElB,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACvD,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,OAAO,GAA2C,EAAE,CAAC;IAC3D,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACtB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3C,OAAO;QACL,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAChB,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACtB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CACpB,OAAO,CACL,IAAI,KAAK,SAAS;gBAChB,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oCAAoC,EAAE;gBAC5D,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CACrB,CACF,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC,CAAC;QACJ,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE;KAC1B,CAAC;AACJ,CAAC","sourcesContent":["import { connect } from \"node:net\";\n\nimport type { HostPairing, LocalHostStatus, PairingDevice } from \"@parlor/capabilities\";\n\nimport { onLines } from \"./lines.js\";\nimport type { HostRelease, ServiceClient } from \"./service.js\";\n\nexport const CONTROL_PROTOCOL = 1;\n\n/**\n * Newline-delimited JSON on a 0600 Unix socket (a named pipe on Windows), spoken by the\n * `parlor-host` CLI and the desktop shell's Rust side. No TCP listener exists.\n */\nexport type ControlRequest =\n | { readonly op: \"hello\"; readonly client: ServiceClient }\n | { readonly op: \"handover\"; readonly binary: string; readonly signature: string }\n | { readonly op: \"status\" }\n | { readonly op: \"connect\"; readonly appOrigin: string }\n | { readonly op: \"begin_local_pairing\"; readonly appOrigin: string }\n | {\n readonly op: \"finish_local_pairing\";\n readonly appOrigin: string;\n readonly code: string;\n }\n | {\n readonly op: \"confirm_local_pairing\";\n readonly appOrigin: string;\n readonly connect: boolean;\n readonly device?: PairingDevice;\n }\n | { readonly op: \"disconnect\"; readonly appOrigin: string }\n | { readonly op: \"dev_attach\"; readonly appOrigin: string; readonly hostToken: string }\n | { readonly op: \"dev_detach\"; readonly appOrigin: string };\n\nexport type ControlOp = ControlRequest[\"op\"];\n\nexport interface GrantSummary {\n readonly appOrigin: string;\n readonly appName: string;\n readonly grantId: string;\n}\n\nexport type ControlFailure = { readonly ok: false; readonly error: string };\n\ninterface ControlReplies {\n readonly hello: { readonly ok: true; readonly release: HostRelease };\n readonly handover:\n | { readonly ok: true }\n | { readonly ok: false; readonly error: \"unsigned\" | \"downgrade\" };\n readonly status: {\n readonly ok: true;\n readonly status: LocalHostStatus;\n readonly grants: readonly GrantSummary[];\n };\n readonly connect: { readonly ok: true };\n readonly begin_local_pairing: { readonly ok: true; readonly pairing: HostPairing };\n readonly finish_local_pairing: {\n readonly ok: true;\n readonly account: string;\n readonly appName: string;\n readonly matchingCode: string;\n };\n readonly confirm_local_pairing:\n | { readonly ok: true }\n | { readonly ok: false; readonly error: \"declined_locally\" };\n readonly disconnect: { readonly ok: true };\n readonly dev_attach: { readonly ok: true };\n readonly dev_detach: { readonly ok: true };\n}\n\nexport type ControlResponse<O extends ControlOp> = ControlReplies[O] | ControlFailure;\n\nexport interface ControlClient {\n send<R extends ControlRequest>(request: R): Promise<ControlResponse<R[\"op\"]>>;\n close(): void;\n}\n\n/** `undefined` when no daemon answers on the socket. */\nexport async function connectControl(\n socketPath: string,\n): Promise<ControlClient | undefined> {\n const socket = connect(socketPath);\n const connected = await new Promise<boolean>((resolve) => {\n socket.once(\"connect\", () => resolve(true));\n socket.once(\"error\", () => resolve(false));\n });\n if (!connected) {\n socket.destroy();\n return undefined;\n }\n const waiting: ((line: string | undefined) => void)[] = [];\n onLines(socket, (line) => waiting.shift()?.(line));\n socket.on(\"close\", () => {\n for (const reply of waiting.splice(0)) reply(undefined);\n });\n socket.on(\"error\", () => socket.destroy());\n return {\n send: (request) =>\n new Promise((resolve) => {\n waiting.push((line) =>\n resolve(\n line === undefined\n ? { ok: false, error: \"Parlor Host closed the connection.\" }\n : JSON.parse(line),\n ),\n );\n socket.write(`${JSON.stringify(request)}\\n`);\n }),\n close: () => socket.end(),\n };\n}\n"]}
1
+ {"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAInC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGrC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AA8ElC,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAkB;IAElB,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,MAAM,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACvD,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IACH,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,OAAO,GAA2C,EAAE,CAAC;IAC3D,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACtB,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3C,OAAO;QACL,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,CAChB,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YACtB,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CACpB,OAAO,CACL,IAAI,KAAK,SAAS;gBAChB,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oCAAoC,EAAE;gBAC5D,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CACrB,CACF,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/C,CAAC,CAAC;QACJ,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE;KAC1B,CAAC;AACJ,CAAC","sourcesContent":["import { connect } from \"node:net\";\n\nimport type { HostPairing, LocalHostStatus, PairingDevice } from \"@parlor/capabilities\";\n\nimport { onLines } from \"./lines.js\";\nimport type { HostRelease, ServiceClient } from \"./service.js\";\n\nexport const CONTROL_PROTOCOL = 1;\n\n/**\n * Newline-delimited JSON on a 0600 Unix socket (a named pipe on Windows), spoken by the\n * `parlor-host` CLI and the desktop shell's Rust side. No TCP listener exists.\n */\nexport type ControlRequest =\n | { readonly op: \"hello\"; readonly client: ServiceClient }\n | { readonly op: \"handover\"; readonly binary: string; readonly signature: string }\n | { readonly op: \"status\" }\n | { readonly op: \"connect\"; readonly appOrigin: string }\n | { readonly op: \"begin_local_pairing\"; readonly appOrigin: string }\n | {\n readonly op: \"finish_local_pairing\";\n readonly appOrigin: string;\n readonly code: string;\n }\n | {\n readonly op: \"confirm_local_pairing\";\n readonly appOrigin: string;\n readonly connect: boolean;\n readonly device?: PairingDevice;\n }\n | { readonly op: \"disconnect\"; readonly appOrigin: string }\n | { readonly op: \"agent_tools\"; readonly appOrigin: string; readonly on: boolean }\n | { readonly op: \"dev_attach\"; readonly appOrigin: string; readonly hostToken: string }\n | { readonly op: \"dev_detach\"; readonly appOrigin: string };\n\nexport type ControlOp = ControlRequest[\"op\"];\n\nexport interface GrantSummary {\n readonly appOrigin: string;\n readonly appName: string;\n readonly grantId: string;\n}\n\n/** The app's MCP server name in the coding agents on this computer, and which have it. */\nexport interface AgentToolsSummary {\n readonly name: string;\n readonly agents: string;\n}\n\nexport type ControlFailure = { readonly ok: false; readonly error: string };\n\ninterface ControlReplies {\n readonly hello: { readonly ok: true; readonly release: HostRelease };\n readonly handover:\n | { readonly ok: true }\n | { readonly ok: false; readonly error: \"unsigned\" | \"downgrade\" };\n readonly status: {\n readonly ok: true;\n readonly status: LocalHostStatus;\n readonly grants: readonly GrantSummary[];\n };\n readonly connect: { readonly ok: true; readonly agentTools?: AgentToolsSummary };\n readonly begin_local_pairing: { readonly ok: true; readonly pairing: HostPairing };\n readonly finish_local_pairing: {\n readonly ok: true;\n readonly account: string;\n readonly appName: string;\n readonly matchingCode: string;\n };\n readonly confirm_local_pairing:\n | { readonly ok: true }\n | { readonly ok: false; readonly error: \"declined_locally\" };\n readonly disconnect: { readonly ok: true; readonly agentTools?: AgentToolsSummary };\n readonly agent_tools: { readonly ok: true; readonly agentTools?: AgentToolsSummary };\n readonly dev_attach: { readonly ok: true };\n readonly dev_detach: { readonly ok: true };\n}\n\nexport type ControlResponse<O extends ControlOp> = ControlReplies[O] | ControlFailure;\n\nexport interface ControlClient {\n send<R extends ControlRequest>(request: R): Promise<ControlResponse<R[\"op\"]>>;\n close(): void;\n}\n\n/** `undefined` when no daemon answers on the socket. */\nexport async function connectControl(\n socketPath: string,\n): Promise<ControlClient | undefined> {\n const socket = connect(socketPath);\n const connected = await new Promise<boolean>((resolve) => {\n socket.once(\"connect\", () => resolve(true));\n socket.once(\"error\", () => resolve(false));\n });\n if (!connected) {\n socket.destroy();\n return undefined;\n }\n const waiting: ((line: string | undefined) => void)[] = [];\n onLines(socket, (line) => waiting.shift()?.(line));\n socket.on(\"close\", () => {\n for (const reply of waiting.splice(0)) reply(undefined);\n });\n socket.on(\"error\", () => socket.destroy());\n return {\n send: (request) =>\n new Promise((resolve) => {\n waiting.push((line) =>\n resolve(\n line === undefined\n ? { ok: false, error: \"Parlor Host closed the connection.\" }\n : JSON.parse(line),\n ),\n );\n socket.write(`${JSON.stringify(request)}\\n`);\n }),\n close: () => socket.end(),\n };\n}\n"]}
package/dist/daemon.d.ts CHANGED
@@ -27,12 +27,20 @@ export interface DaemonDeps {
27
27
  */
28
28
  export interface HostDaemon {
29
29
  start(): Promise<void>;
30
- connect(appOrigin: string): Promise<void>;
31
- disconnect(appOrigin: string): Promise<void>;
30
+ /** What the coding agents here know the app by, when the user let them use it. */
31
+ connect(appOrigin: string): Promise<ConnectedTools | undefined>;
32
+ disconnect(appOrigin: string): Promise<ConnectedTools | undefined>;
33
+ /** Lets the coding agents here use the app outside its sidebar, or stops them. */
34
+ agentTools(appOrigin: string, on: boolean): Promise<ConnectedTools | undefined>;
32
35
  /** Hands links over to a newer release; running turns finish here first. */
33
36
  handover(): Promise<void>;
34
37
  stop(): Promise<void>;
35
38
  }
39
+ /** The app's MCP server name in the coding agents here, and which of them have it. */
40
+ export interface ConnectedTools {
41
+ readonly name: string;
42
+ readonly agents: string;
43
+ }
36
44
  /**
37
45
  * Agents start `parlor-host mcp-proxy` by name. An entry named otherwise, such as the
38
46
  * published `dist/main.js` that `parlor dev` runs with node, gets a shim instead of a link.
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAI9C,OAAO,EAA8B,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAKzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAQ/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAyC,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,eAAe,CAAC;AAI9D,OAAO,EAAE,KAAK,WAAW,EAAoC,MAAM,cAAc,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,6GAA6G;IAC7G,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,4EAA4E;IAC5E,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAeD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,GAAG,SAAuB,GACtC,OAAO,CAAC,IAAI,CAAC,CAqBf;AAWD,6FAA6F;AAC7F,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAkB,IAAI,wBAAwB;IAC9C,cAEC;CACF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,aAAa,CA4fhE"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAW9C,OAAO,EAA8B,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAMzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAQ/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAyC,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,eAAe,CAAC;AAI9D,OAAO,EAAE,KAAK,WAAW,EAAoC,MAAM,cAAc,CAAC;AAElF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,6GAA6G;IAC7G,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,kFAAkF;IAClF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IAChE,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IACnE,kFAAkF;IAClF,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAAC;IAChF,4EAA4E;IAC5E,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,sFAAsF;AACtF,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAiBD;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,GAAG,SAAuB,GACtC,OAAO,CAAC,IAAI,CAAC,CAqBf;AAWD,6FAA6F;AAC7F,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,SAAkB,IAAI,wBAAwB;IAC9C,cAEC;CACF;AAKD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,aAAa,CAssBhE"}