appduct 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/README.md +121 -51
  2. package/dist/artifact-inspect.d.ts +0 -1
  3. package/dist/bin.d.ts +0 -1
  4. package/dist/bin.js +1250 -2
  5. package/dist/cli/command-options.d.ts +8 -1
  6. package/dist/cli/create-cli.d.ts +0 -1
  7. package/dist/cli/dispatch.d.ts +10 -1
  8. package/dist/cli/envelope.d.ts +19 -0
  9. package/dist/cli/global-flags.d.ts +30 -0
  10. package/dist/cli/open-target.d.ts +25 -8
  11. package/dist/cli/result-types.d.ts +30 -5
  12. package/dist/cli/router.d.ts +78 -0
  13. package/dist/cli/routes/daemon/index.d.ts +9 -0
  14. package/dist/cli/routes/daemon/index.js +848 -0
  15. package/dist/cli/routes/daemon/run.d.ts +3 -0
  16. package/dist/cli/routes/daemon/run.js +3246 -0
  17. package/dist/cli/routes/daemon/start.d.ts +3 -0
  18. package/dist/cli/routes/daemon/start.js +1668 -0
  19. package/dist/cli/routes/daemon/status.d.ts +4 -0
  20. package/dist/cli/routes/daemon/status.js +1676 -0
  21. package/dist/cli/routes/daemon/stop.d.ts +4 -0
  22. package/dist/cli/routes/daemon/stop.js +1646 -0
  23. package/dist/cli/routes/doctor.d.ts +3 -0
  24. package/dist/cli/routes/doctor.js +1075 -0
  25. package/dist/cli/routes/events.d.ts +3 -0
  26. package/dist/cli/routes/events.js +1906 -0
  27. package/dist/cli/routes/init.d.ts +3 -0
  28. package/dist/cli/routes/init.js +1486 -0
  29. package/dist/cli/routes/invoke.d.ts +3 -0
  30. package/dist/cli/routes/invoke.js +1884 -0
  31. package/dist/cli/routes/keygen.d.ts +3 -0
  32. package/dist/cli/routes/keygen.js +928 -0
  33. package/dist/cli/routes/link.d.ts +3 -0
  34. package/dist/cli/routes/link.js +2705 -0
  35. package/dist/cli/routes/ls.d.ts +3 -0
  36. package/dist/cli/routes/ls.js +1659 -0
  37. package/dist/cli/routes/mcp.d.ts +5 -0
  38. package/dist/cli/routes/mcp.js +3917 -0
  39. package/dist/cli/routes/revoke.d.ts +3 -0
  40. package/dist/cli/routes/revoke.js +1675 -0
  41. package/dist/cli/routes/tools.d.ts +3 -0
  42. package/dist/cli/routes/tools.js +1851 -0
  43. package/dist/cli/runner.d.ts +3 -11
  44. package/dist/cli/types.d.ts +9 -6
  45. package/dist/cli/version-guard.d.ts +20 -0
  46. package/dist/cli.d.ts +0 -1
  47. package/dist/client/app-client.d.ts +0 -1
  48. package/dist/client/bootstrap.d.ts +4 -4
  49. package/dist/client/connect.d.ts +0 -1
  50. package/dist/client/errors.d.ts +0 -1
  51. package/dist/client/index.d.ts +0 -1
  52. package/dist/client/index.js +2379 -16
  53. package/dist/commands/daemon/context.d.ts +14 -0
  54. package/dist/commands/daemon/run.d.ts +11 -0
  55. package/dist/commands/daemon/start.d.ts +5 -0
  56. package/dist/commands/daemon/status.d.ts +5 -0
  57. package/dist/commands/daemon/stop.d.ts +5 -0
  58. package/dist/commands/doctor.d.ts +0 -1
  59. package/dist/commands/events.d.ts +0 -1
  60. package/dist/commands/init.d.ts +17 -4
  61. package/dist/commands/invoke.d.ts +0 -1
  62. package/dist/commands/keygen.d.ts +0 -1
  63. package/dist/commands/link.d.ts +1 -2
  64. package/dist/commands/ls.d.ts +0 -1
  65. package/dist/commands/mcp.d.ts +2 -4
  66. package/dist/commands/revoke.d.ts +0 -1
  67. package/dist/commands/tools.d.ts +19 -3
  68. package/dist/daemon/address.d.ts +0 -1
  69. package/dist/daemon/audit.d.ts +6 -11
  70. package/dist/daemon/calls.d.ts +0 -1
  71. package/dist/daemon/config.d.ts +13 -16
  72. package/dist/daemon/daemon.d.ts +0 -1
  73. package/dist/daemon/event-bus.d.ts +0 -1
  74. package/dist/daemon/links.d.ts +0 -1
  75. package/dist/daemon/listener.d.ts +0 -1
  76. package/dist/daemon/log-rotation.d.ts +0 -1
  77. package/dist/daemon/pidfile.d.ts +14 -8
  78. package/dist/daemon/policy.d.ts +0 -1
  79. package/dist/daemon/registry.d.ts +0 -1
  80. package/dist/daemon/rpc-errors.d.ts +16 -0
  81. package/dist/daemon/rpc-server.d.ts +0 -11
  82. package/dist/daemon/sessions.d.ts +0 -1
  83. package/dist/daemon/socket-probe.d.ts +0 -1
  84. package/dist/daemon/state-dir.d.ts +0 -1
  85. package/dist/daemon/timers.d.ts +0 -1
  86. package/dist/daemon/tls.d.ts +0 -1
  87. package/dist/errors.d.ts +0 -1
  88. package/dist/host-certificate.d.ts +0 -1
  89. package/dist/index.d.ts +0 -1
  90. package/dist/index.js +1307 -3
  91. package/dist/key-material.d.ts +0 -1
  92. package/dist/link.d.ts +8 -7
  93. package/dist/mcp/app-tools.d.ts +153 -0
  94. package/dist/mcp/connect-tool.d.ts +14 -8
  95. package/dist/mcp/daemon-tools.d.ts +2 -11
  96. package/dist/mcp/events-tool.d.ts +0 -1
  97. package/dist/mcp/server.d.ts +33 -14
  98. package/dist/native-scheme.d.ts +0 -1
  99. package/dist/output.d.ts +8 -11
  100. package/dist/package-root.d.ts +11 -0
  101. package/dist/package-version.d.ts +0 -1
  102. package/dist/qr-terminal.d.ts +0 -1
  103. package/dist/rpc/client.d.ts +0 -1
  104. package/dist/scheme.d.ts +60 -2
  105. package/dist/spki-pin.d.ts +0 -1
  106. package/package.json +4 -3
  107. package/dist/artifact-inspect.d.ts.map +0 -1
  108. package/dist/artifact-inspect.js +0 -334
  109. package/dist/bin.d.ts.map +0 -1
  110. package/dist/cli/command-options.d.ts.map +0 -1
  111. package/dist/cli/command-options.js +0 -95
  112. package/dist/cli/create-cli.d.ts.map +0 -1
  113. package/dist/cli/create-cli.js +0 -56
  114. package/dist/cli/dispatch.d.ts.map +0 -1
  115. package/dist/cli/dispatch.js +0 -275
  116. package/dist/cli/open-target.d.ts.map +0 -1
  117. package/dist/cli/open-target.js +0 -438
  118. package/dist/cli/result-types.d.ts.map +0 -1
  119. package/dist/cli/result-types.js +0 -6
  120. package/dist/cli/runner.d.ts.map +0 -1
  121. package/dist/cli/runner.js +0 -111
  122. package/dist/cli/types.d.ts.map +0 -1
  123. package/dist/cli/types.js +0 -10
  124. package/dist/cli.d.ts.map +0 -1
  125. package/dist/cli.js +0 -2
  126. package/dist/client/app-client.d.ts.map +0 -1
  127. package/dist/client/app-client.js +0 -223
  128. package/dist/client/bootstrap.d.ts.map +0 -1
  129. package/dist/client/bootstrap.js +0 -108
  130. package/dist/client/connect.d.ts.map +0 -1
  131. package/dist/client/connect.js +0 -38
  132. package/dist/client/errors.d.ts.map +0 -1
  133. package/dist/client/errors.js +0 -40
  134. package/dist/client/index.d.ts.map +0 -1
  135. package/dist/commands/daemon.d.ts +0 -22
  136. package/dist/commands/daemon.d.ts.map +0 -1
  137. package/dist/commands/daemon.js +0 -128
  138. package/dist/commands/doctor.d.ts.map +0 -1
  139. package/dist/commands/doctor.js +0 -42
  140. package/dist/commands/events.d.ts.map +0 -1
  141. package/dist/commands/events.js +0 -76
  142. package/dist/commands/init.d.ts.map +0 -1
  143. package/dist/commands/init.js +0 -231
  144. package/dist/commands/invoke.d.ts.map +0 -1
  145. package/dist/commands/invoke.js +0 -54
  146. package/dist/commands/keygen.d.ts.map +0 -1
  147. package/dist/commands/keygen.js +0 -46
  148. package/dist/commands/link.d.ts.map +0 -1
  149. package/dist/commands/link.js +0 -43
  150. package/dist/commands/ls.d.ts.map +0 -1
  151. package/dist/commands/ls.js +0 -7
  152. package/dist/commands/mcp.d.ts.map +0 -1
  153. package/dist/commands/mcp.js +0 -98
  154. package/dist/commands/revoke.d.ts.map +0 -1
  155. package/dist/commands/revoke.js +0 -7
  156. package/dist/commands/tools.d.ts.map +0 -1
  157. package/dist/commands/tools.js +0 -52
  158. package/dist/daemon/address.d.ts.map +0 -1
  159. package/dist/daemon/address.js +0 -71
  160. package/dist/daemon/audit.d.ts.map +0 -1
  161. package/dist/daemon/audit.js +0 -237
  162. package/dist/daemon/calls.d.ts.map +0 -1
  163. package/dist/daemon/calls.js +0 -158
  164. package/dist/daemon/config.d.ts.map +0 -1
  165. package/dist/daemon/config.js +0 -170
  166. package/dist/daemon/daemon.d.ts.map +0 -1
  167. package/dist/daemon/daemon.js +0 -560
  168. package/dist/daemon/event-bus.d.ts.map +0 -1
  169. package/dist/daemon/event-bus.js +0 -111
  170. package/dist/daemon/links.d.ts.map +0 -1
  171. package/dist/daemon/links.js +0 -118
  172. package/dist/daemon/listener.d.ts.map +0 -1
  173. package/dist/daemon/listener.js +0 -132
  174. package/dist/daemon/log-rotation.d.ts.map +0 -1
  175. package/dist/daemon/log-rotation.js +0 -136
  176. package/dist/daemon/pidfile.d.ts.map +0 -1
  177. package/dist/daemon/pidfile.js +0 -90
  178. package/dist/daemon/policy.d.ts.map +0 -1
  179. package/dist/daemon/policy.js +0 -24
  180. package/dist/daemon/registry.d.ts.map +0 -1
  181. package/dist/daemon/registry.js +0 -31
  182. package/dist/daemon/rpc-server.d.ts.map +0 -1
  183. package/dist/daemon/rpc-server.js +0 -203
  184. package/dist/daemon/sessions.d.ts.map +0 -1
  185. package/dist/daemon/sessions.js +0 -429
  186. package/dist/daemon/socket-probe.d.ts.map +0 -1
  187. package/dist/daemon/socket-probe.js +0 -28
  188. package/dist/daemon/state-dir.d.ts.map +0 -1
  189. package/dist/daemon/state-dir.js +0 -43
  190. package/dist/daemon/timers.d.ts.map +0 -1
  191. package/dist/daemon/timers.js +0 -12
  192. package/dist/daemon/tls.d.ts.map +0 -1
  193. package/dist/daemon/tls.js +0 -79
  194. package/dist/errors.d.ts.map +0 -1
  195. package/dist/errors.js +0 -162
  196. package/dist/host-certificate.d.ts.map +0 -1
  197. package/dist/host-certificate.js +0 -111
  198. package/dist/index.d.ts.map +0 -1
  199. package/dist/key-material.d.ts.map +0 -1
  200. package/dist/key-material.js +0 -42
  201. package/dist/link.d.ts.map +0 -1
  202. package/dist/link.js +0 -117
  203. package/dist/mcp/connect-tool.d.ts.map +0 -1
  204. package/dist/mcp/connect-tool.js +0 -396
  205. package/dist/mcp/daemon-tools.d.ts.map +0 -1
  206. package/dist/mcp/daemon-tools.js +0 -29
  207. package/dist/mcp/events-tool.d.ts.map +0 -1
  208. package/dist/mcp/events-tool.js +0 -322
  209. package/dist/mcp/server.d.ts.map +0 -1
  210. package/dist/mcp/server.js +0 -538
  211. package/dist/mcp/tool-mapping.d.ts +0 -58
  212. package/dist/mcp/tool-mapping.d.ts.map +0 -1
  213. package/dist/mcp/tool-mapping.js +0 -143
  214. package/dist/mcp/tool-namespace.d.ts +0 -40
  215. package/dist/mcp/tool-namespace.d.ts.map +0 -1
  216. package/dist/mcp/tool-namespace.js +0 -65
  217. package/dist/native-scheme.d.ts.map +0 -1
  218. package/dist/native-scheme.js +0 -465
  219. package/dist/output.d.ts.map +0 -1
  220. package/dist/output.js +0 -342
  221. package/dist/package-version.d.ts.map +0 -1
  222. package/dist/package-version.js +0 -47
  223. package/dist/qr-terminal.d.ts.map +0 -1
  224. package/dist/qr-terminal.js +0 -45
  225. package/dist/rpc/client.d.ts.map +0 -1
  226. package/dist/rpc/client.js +0 -819
  227. package/dist/scheme.d.ts.map +0 -1
  228. package/dist/scheme.js +0 -321
  229. package/dist/spki-pin.d.ts.map +0 -1
  230. package/dist/spki-pin.js +0 -14
@@ -1,31 +0,0 @@
1
- /**
2
- * Per-session tool registry (ARCHITECTURE.md §7). Callers (sessions.ts/listener.ts) must validate
3
- * incoming `tool_registry_snapshot`/`tool_registry_delta` wire messages with the shared guards
4
- * *before* calling into this module — v1 crashed by indexing into an unvalidated `tools: [null]`
5
- * snapshot; this module only ever stores already-validated {@link ToolDescriptor}s.
6
- */
7
- /** `onChange` fires after every mutation (snapshot/upsert/remove) — used to emit `tools_changed`. */
8
- export const createToolRegistry = (onChange) => {
9
- let tools = new Map();
10
- const notify = () => {
11
- onChange?.();
12
- };
13
- return {
14
- snapshot: (incoming) => {
15
- tools = new Map(incoming.map((tool) => [tool.name, tool]));
16
- notify();
17
- },
18
- upsert: (tool) => {
19
- tools.set(tool.name, tool);
20
- notify();
21
- },
22
- remove: (name) => {
23
- if (tools.delete(name)) {
24
- notify();
25
- }
26
- },
27
- list: () => Array.from(tools.values()),
28
- get: (name) => tools.get(name),
29
- count: () => tools.size,
30
- };
31
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"rpc-server.d.ts","sourceRoot":"","sources":["../../src/daemon/rpc-server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAgB,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,uGAAuG;AACvG,eAAO,MAAM,cAAc,QAAc,CAAC;AAE1C;iGACiG;AACjG,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AAEzD,qBAAa,mBAAoB,SAAQ,KAAK;IAE1C,QAAQ,CAAC,IAAI,EAAE,SAAS;IAExB,wEAAwE;IACxE,QAAQ,CAAC,IAAI;IACb,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO;gBAJjB,IAAI,EAAE,SAAS,EACxB,OAAO,EAAE,MAAM;IACf,wEAAwE;IAC/D,IAAI,SAAS,EACb,OAAO,CAAC,EAAE,OAAO,YAAA;CAK7B;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,aAAa,CAAC;IAC1B,8FAA8F;IAC9F,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAC1C;;;;2FAIuF;IACvF,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,iBAAiB,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAErG,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AA2C1D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,MAAM,EAAE,CAAC,UAAU,EAAE,aAAa,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9D,WAAW,EAAE,MAAM,aAAa,EAAE,CAAC;IACnC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAsEF,eAAO,MAAM,cAAc,GAAU,SAAS,gBAAgB,KAAG,OAAO,CAAC,SAAS,CAiIjF,CAAC"}
@@ -1,203 +0,0 @@
1
- /**
2
- * The control-plane UDS JSON-RPC server (ARCHITECTURE.md §5). Framing: one JSON-RPC 2.0 message
3
- * per line (`\n`-delimited). Server→client notifications use method `"event"` and are pushed via
4
- * {@link notify} on a targeted connection — this module only exposes the primitive.
5
- */
6
- import { createServer } from "node:net";
7
- import { chmod, rm } from "node:fs/promises";
8
- /** 1 MiB — lines beyond this are dropped by destroying the connection (ARCHITECTURE.md task notes). */
9
- export const MAX_LINE_BYTES = 1024 * 1024;
10
- /** 4 MiB — a subscriber connection (`events.subscribe`) whose outbound buffer grows past this
11
- * (slow/dead reader) is dropped outright rather than left to back up the daemon indefinitely. */
12
- export const MAX_NOTIFY_BUFFERED_BYTES = 4 * 1024 * 1024;
13
- export class RpcApplicationError extends Error {
14
- type;
15
- code;
16
- details;
17
- constructor(type, message,
18
- /** JSON-RPC error code; defaults to the shared "server error" range. */
19
- code = -32000, details) {
20
- super(message);
21
- this.type = type;
22
- this.code = code;
23
- this.details = details;
24
- this.name = "RpcApplicationError";
25
- }
26
- }
27
- const isPlainObject = (value) => {
28
- return typeof value === "object" && value !== null && !Array.isArray(value);
29
- };
30
- const hasRequestId = (value) => {
31
- return "id" in value;
32
- };
33
- const writeErrorLine = (socket, id, code, message, data) => {
34
- writeLine(socket, {
35
- jsonrpc: "2.0",
36
- id,
37
- error: { code, message, ...(data ? { data } : {}) },
38
- });
39
- };
40
- const writeLine = (socket, payload, onFlushed) => {
41
- if (socket.destroyed) {
42
- return;
43
- }
44
- socket.write(`${JSON.stringify(payload)}\n`, (error) => {
45
- if (!error) {
46
- onFlushed?.();
47
- }
48
- });
49
- };
50
- const handleLine = async (line, connection, dispatch, registerOnClose) => {
51
- const { socket } = connection;
52
- let request;
53
- try {
54
- const parsed = JSON.parse(line);
55
- if (!isPlainObject(parsed)) {
56
- writeErrorLine(socket, null, -32600, "Invalid Request: expected a JSON object.");
57
- return;
58
- }
59
- request = parsed;
60
- }
61
- catch {
62
- writeErrorLine(socket, null, -32700, "Parse error: invalid JSON.");
63
- return;
64
- }
65
- const id = hasRequestId(request) ? request.id : null;
66
- if (typeof request.method !== "string" || request.method.length === 0) {
67
- writeErrorLine(socket, id, -32600, 'Invalid Request: "method" must be a non-empty string.');
68
- return;
69
- }
70
- const handler = dispatch[request.method];
71
- if (!handler) {
72
- writeErrorLine(socket, id, -32601, `Method not found: "${request.method}".`);
73
- return;
74
- }
75
- const afterSendCallbacks = [];
76
- const context = {
77
- connection,
78
- afterSend: (callback) => {
79
- afterSendCallbacks.push(callback);
80
- },
81
- onClose: registerOnClose,
82
- };
83
- try {
84
- const result = await handler(request.params, context);
85
- writeLine(socket, { jsonrpc: "2.0", id, result: result ?? null }, () => {
86
- for (const callback of afterSendCallbacks) {
87
- callback();
88
- }
89
- });
90
- }
91
- catch (error) {
92
- if (error instanceof RpcApplicationError) {
93
- writeErrorLine(socket, id, error.code, error.message, {
94
- type: error.type,
95
- ...(error.details !== undefined ? { details: error.details } : {}),
96
- });
97
- return;
98
- }
99
- const message = error instanceof Error ? error.message : "Internal error.";
100
- writeErrorLine(socket, id, -32603, message, { type: "invalid_request" });
101
- }
102
- };
103
- export const startRpcServer = async (options) => {
104
- const maxLineBytes = options.maxLineBytes ?? MAX_LINE_BYTES;
105
- const connections = new Map();
106
- let nextConnectionId = 1;
107
- await rm(options.socketPath, { force: true });
108
- const server = createServer((socket) => {
109
- socket.on("error", () => {
110
- // A dropped/reset client connection must never crash the daemon.
111
- });
112
- const id = nextConnectionId;
113
- nextConnectionId += 1;
114
- const connection = { id, socket, state: {} };
115
- connections.set(id, connection);
116
- const closeCallbacks = new Set();
117
- const registerOnClose = (callback) => {
118
- closeCallbacks.add(callback);
119
- return () => {
120
- closeCallbacks.delete(callback);
121
- };
122
- };
123
- let buffer = "";
124
- socket.on("data", (chunk) => {
125
- buffer += chunk.toString("utf8");
126
- if (Buffer.byteLength(buffer, "utf8") > maxLineBytes && !buffer.includes("\n")) {
127
- socket.destroy();
128
- return;
129
- }
130
- let newlineIndex = buffer.indexOf("\n");
131
- while (newlineIndex !== -1) {
132
- const line = buffer.slice(0, newlineIndex).replace(/\r$/u, "");
133
- buffer = buffer.slice(newlineIndex + 1);
134
- if (line.length > 0) {
135
- if (Buffer.byteLength(line, "utf8") > maxLineBytes) {
136
- // ARCHITECTURE.md task notes: cap line length at 1 MiB, dropping the connection beyond.
137
- writeErrorLine(socket, null, -32600, `Invalid Request: line exceeds the ${maxLineBytes}-byte limit.`);
138
- socket.destroy();
139
- return;
140
- }
141
- void handleLine(line, connection, options.dispatch, registerOnClose);
142
- }
143
- newlineIndex = buffer.indexOf("\n");
144
- }
145
- });
146
- socket.on("close", () => {
147
- connections.delete(id);
148
- const callbacks = Array.from(closeCallbacks);
149
- closeCallbacks.clear();
150
- for (const callback of callbacks) {
151
- try {
152
- callback();
153
- }
154
- catch {
155
- // A close callback must never crash the daemon.
156
- }
157
- }
158
- });
159
- });
160
- server.on("error", () => {
161
- // Never let a listener-level error (e.g. EMFILE after startup) crash the process. Startup
162
- // failures are additionally surfaced via the one-shot listener below, which rejects `listen()`.
163
- // Surfacing post-startup errors would require a caller-supplied sink; the daemon composition
164
- // root owns observability wiring in a later task.
165
- });
166
- await new Promise((resolve, reject) => {
167
- const onError = (error) => {
168
- server.off("listening", onListening);
169
- reject(error);
170
- };
171
- const onListening = () => {
172
- server.off("error", onError);
173
- resolve();
174
- };
175
- server.once("error", onError);
176
- server.once("listening", onListening);
177
- server.listen(options.socketPath);
178
- });
179
- await chmod(options.socketPath, 0o600);
180
- return {
181
- server,
182
- notify: (connection, payload) => {
183
- if (connection.socket.destroyed) {
184
- return;
185
- }
186
- // Backpressure guard: a slow/dead subscriber must never block the daemon or other
187
- // connections. `writableLength` reflects bytes already queued but not yet flushed to the
188
- // kernel; once it crosses the cap the connection is beyond saving and gets dropped.
189
- if (connection.socket.writableLength > MAX_NOTIFY_BUFFERED_BYTES) {
190
- connection.socket.destroy();
191
- return;
192
- }
193
- writeLine(connection.socket, { jsonrpc: "2.0", method: "event", params: payload });
194
- },
195
- connections: () => Array.from(connections.values()),
196
- close: () => new Promise((resolve) => {
197
- for (const connection of connections.values()) {
198
- connection.socket.destroy();
199
- }
200
- server.close(() => resolve());
201
- }),
202
- };
203
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/daemon/sessions.ts"],"names":[],"mappings":"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"}
@@ -1,429 +0,0 @@
1
- /**
2
- * The session state machine (ARCHITECTURE.md §6, exactly): PENDING (owned by links.ts) →
3
- * ACTIVE ⇄ SUSPENDED → EXPIRED, with REVOKED reachable from any live state. This module owns the
4
- * live-session map, claim/resume handling (including the pre-auth hardening in the task's
5
- * rejection matrix), alias assignment, keepalive-driven suspend, and grace-timer expiry.
6
- *
7
- * Pending links never enter `sessions` — they live in links.ts's `PendingLinkRegistry` and are
8
- * only ever resolved during claim. `sessions` therefore only ever holds live (active/suspended)
9
- * sessions; terminal transitions (revoked/expired) remove the entry immediately (ARCHITECTURE.md
10
- * §6: "terminal states free the alias" — there is no persisted history, matching §3/§13's "no
11
- * per-session files, all state in-daemon-memory").
12
- */
13
- import { randomBytes, timingSafeEqual } from "node:crypto";
14
- import { isEventMessage, isToolCallProgressMessage, isToolErrorMessage, isToolRegistryDeltaMessage, isToolRegistrySnapshotMessage, isToolResultMessage, parseSessionClaimDeviceFields, } from "@appduct/shared";
15
- import { createPendingLinkRegistry } from "./links.js";
16
- import { RpcApplicationError } from "./rpc-server.js";
17
- import { createToolRegistry } from "./registry.js";
18
- import { systemTimers } from "./timers.js";
19
- const RESUME_TOKEN_BYTES = 32;
20
- /** Wire message types allowed *after* claim (session_claim/session_resume are pre-claim only). */
21
- export const POST_CLAIM_MESSAGE_TYPES = new Set([
22
- "tool_registry_snapshot",
23
- "tool_registry_delta",
24
- "tool_result",
25
- "tool_error",
26
- "tool_call_progress",
27
- "event",
28
- ]);
29
- export const isPostClaimMessageType = (type) => {
30
- return typeof type === "string" && POST_CLAIM_MESSAGE_TYPES.has(type);
31
- };
32
- export const slugifyDeviceModel = (model) => {
33
- if (!model) {
34
- return "device";
35
- }
36
- const slug = model
37
- .toLowerCase()
38
- .replaceAll(/[^a-z0-9]+/gu, "-")
39
- .replaceAll(/^-+|-+$/gu, "");
40
- return slug.length > 0 ? slug : "device";
41
- };
42
- export const dedupeAlias = (base, existingAliases) => {
43
- if (!existingAliases.has(base)) {
44
- return base;
45
- }
46
- let suffix = 2;
47
- while (existingAliases.has(`${base}-${suffix}`)) {
48
- suffix += 1;
49
- }
50
- return `${base}-${suffix}`;
51
- };
52
- const decodeFixedLengthToken = (base64url, expectedLength) => {
53
- let decoded;
54
- try {
55
- decoded = Buffer.from(base64url, "base64url");
56
- }
57
- catch {
58
- return null;
59
- }
60
- return decoded.length === expectedLength ? decoded : null;
61
- };
62
- /** Constant-time-safe comparison: never calls `timingSafeEqual` on mismatched lengths (it throws). */
63
- const tokensMatch = (candidate, expected) => {
64
- if (!candidate || candidate.length !== expected.length) {
65
- return false;
66
- }
67
- return timingSafeEqual(candidate, expected);
68
- };
69
- const MAX_FAILED_CLAIM_ATTEMPTS = 5;
70
- const closeSocket = (socket, code, reason) => {
71
- try {
72
- socket.close(code, reason);
73
- }
74
- catch {
75
- // The socket may already be closing/closed; never let a double-close crash the daemon.
76
- socket.terminate();
77
- }
78
- };
79
- export const createSessionManager = (options) => {
80
- const clock = options.clock ?? { now: () => new Date() };
81
- const timers = options.timers ?? systemTimers;
82
- const sessions = new Map();
83
- const pendingLinks = createPendingLinkRegistry({
84
- getEndpoint: options.getEndpoint,
85
- clock,
86
- timers,
87
- eventBus: options.eventBus,
88
- });
89
- const emit = (kind, sessionId, alias, data) => {
90
- options.eventBus.emit({ kind, sessionId, alias, data });
91
- };
92
- const toSummary = (session) => {
93
- return {
94
- sessionId: session.sessionId,
95
- alias: session.alias,
96
- state: session.state,
97
- device: session.device,
98
- createdAt: session.createdAt.toISOString(),
99
- claimedAt: session.claimedAt.toISOString(),
100
- ...(session.suspendedAt ? { suspendedAt: session.suspendedAt.toISOString() } : {}),
101
- toolCount: session.registry.count(),
102
- };
103
- };
104
- const resolveSession = (selector) => {
105
- const live = Array.from(sessions.values());
106
- if (selector !== undefined) {
107
- const match = live.find((session) => session.sessionId === selector || session.alias === selector);
108
- if (!match) {
109
- throw new RpcApplicationError("unknown_session", `No session matches "${selector}".`);
110
- }
111
- return match;
112
- }
113
- if (live.length === 0) {
114
- throw new RpcApplicationError("no_session", "No active or suspended session, and none was specified.");
115
- }
116
- if (live.length > 1) {
117
- throw new RpcApplicationError("ambiguous_session", `Multiple sessions are live (${live.map((session) => session.alias).join(", ")}); specify a selector.`);
118
- }
119
- return live[0];
120
- };
121
- const assignAlias = (model) => {
122
- const base = slugifyDeviceModel(model);
123
- const existing = new Set(Array.from(sessions.values(), (session) => session.alias));
124
- return dedupeAlias(base, existing);
125
- };
126
- const sendAck = (socket, session) => {
127
- const ack = {
128
- type: "session_ack",
129
- session_id: session.sessionId,
130
- status: "ok",
131
- alias: session.alias,
132
- resume_token: session.resumeToken.toString("base64url"),
133
- keepalive_interval_s: options.keepaliveIntervalSeconds,
134
- grace_s: options.graceSeconds,
135
- };
136
- socket.send(JSON.stringify(ack), (error) => {
137
- if (error) {
138
- // The 'close'/'error' listeners (attached below) own recovery; a failed send must never
139
- // throw into the socket library's event loop turn (v1's exact defect).
140
- closeSocket(socket, 1011, "send_failed");
141
- }
142
- });
143
- };
144
- const suspend = (sessionId) => {
145
- const session = sessions.get(sessionId);
146
- if (!session || session.state !== "active") {
147
- return;
148
- }
149
- session.state = "suspended";
150
- session.suspendedAt = clock.now();
151
- session.socket = undefined;
152
- session.missedPongs = 0;
153
- session.graceTimer = timers.setTimeout(() => expire(sessionId), options.graceSeconds * 1000);
154
- emit("session_suspended", session.sessionId, session.alias, {});
155
- };
156
- const expire = (sessionId) => {
157
- const session = sessions.get(sessionId);
158
- if (!session || session.state !== "suspended") {
159
- return;
160
- }
161
- sessions.delete(sessionId);
162
- emit("session_expired", session.sessionId, session.alias, {});
163
- };
164
- const attachSocketHandlers = (session) => {
165
- const socket = session.socket;
166
- socket.on("error", () => {
167
- // Never let an unhandled 'error' crash the daemon (v1's fatal defect) — 'close' still fires
168
- // after 'error' and drives the suspend transition.
169
- });
170
- socket.on("pong", () => {
171
- session.missedPongs = 0;
172
- });
173
- socket.on("close", () => {
174
- if (session.socket === socket) {
175
- suspend(session.sessionId);
176
- }
177
- });
178
- };
179
- // Server-side keepalive (ARCHITECTURE.md §7): ping every `keepaliveIntervalSeconds`; two missed
180
- // pongs in a row is treated as socket loss and suspends the session (never crashes the daemon).
181
- const keepaliveInterval = timers.setInterval(() => {
182
- for (const session of sessions.values()) {
183
- if (session.state !== "active" || !session.socket) {
184
- continue;
185
- }
186
- if (session.missedPongs >= 2) {
187
- const staleSocket = session.socket;
188
- session.socket = undefined;
189
- suspend(session.sessionId);
190
- staleSocket.terminate();
191
- continue;
192
- }
193
- session.missedPongs += 1;
194
- try {
195
- session.socket.ping();
196
- }
197
- catch {
198
- // A ping failure is surfaced via the socket's own 'error'/'close' handlers.
199
- }
200
- }
201
- }, options.keepaliveIntervalSeconds * 1000);
202
- const createLink = (ttlSeconds, addressOverride) => {
203
- const { link, deepLinkPayload, endpoint } = pendingLinks.create(ttlSeconds ?? options.linkTtlSeconds, addressOverride);
204
- return {
205
- sessionId: link.sessionId,
206
- deepLinkPayload,
207
- endpoint,
208
- expiresAt: Math.floor(link.expiresAt.getTime() / 1000),
209
- };
210
- };
211
- const handleClaim = (socket, message) => {
212
- const pending = pendingLinks.get(message.session_id);
213
- if (!pending) {
214
- if (sessions.has(message.session_id)) {
215
- closeSocket(socket, 1008, "already_claimed");
216
- }
217
- else {
218
- closeSocket(socket, 1008, "unknown_session");
219
- }
220
- return null;
221
- }
222
- const nowMs = clock.now().getTime();
223
- if (pending.expiresAt.getTime() <= nowMs) {
224
- pendingLinks.discard(pending.sessionId);
225
- closeSocket(socket, 1008, "link_expired");
226
- return null;
227
- }
228
- const candidateToken = decodeFixedLengthToken(message.token, pending.token.length);
229
- if (!tokensMatch(candidateToken, pending.token)) {
230
- // ARCHITECTURE.md §6: the token is invalidated "after 5 failed claim attempts" — the 5th
231
- // failure itself invalidates the link (a correct token on a would-be 6th attempt must not
232
- // still claim).
233
- const attempts = pendingLinks.recordFailedAttempt(pending.sessionId);
234
- if (attempts >= MAX_FAILED_CLAIM_ATTEMPTS) {
235
- pendingLinks.discard(pending.sessionId);
236
- closeSocket(socket, 1008, "claim_attempts_exceeded");
237
- }
238
- else {
239
- closeSocket(socket, 1008, "invalid_token");
240
- }
241
- return null;
242
- }
243
- pendingLinks.consume(pending.sessionId);
244
- const deviceFields = parseSessionClaimDeviceFields(message);
245
- const device = deviceFields && deviceFields !== "invalid" ? deviceFields : {};
246
- const alias = assignAlias(device.model);
247
- const sessionId = pending.sessionId;
248
- const session = {
249
- sessionId,
250
- alias,
251
- state: "active",
252
- device,
253
- createdAt: pending.createdAt,
254
- claimedAt: clock.now(),
255
- resumeToken: randomBytes(RESUME_TOKEN_BYTES),
256
- socket,
257
- missedPongs: 0,
258
- registry: createToolRegistry(() => {
259
- emit("tools_changed", sessionId, alias, { toolCount: session.registry.count() });
260
- }),
261
- };
262
- sessions.set(sessionId, session);
263
- attachSocketHandlers(session);
264
- sendAck(socket, session);
265
- emit("session_claimed", sessionId, alias, { device });
266
- return sessionId;
267
- };
268
- const handleResume = (socket, message) => {
269
- const session = sessions.get(message.session_id);
270
- if (!session) {
271
- closeSocket(socket, 1008, "unknown_session");
272
- return null;
273
- }
274
- const candidateToken = decodeFixedLengthToken(message.resume_token, session.resumeToken.length);
275
- if (!tokensMatch(candidateToken, session.resumeToken)) {
276
- closeSocket(socket, 1008, "invalid_resume_token");
277
- return null;
278
- }
279
- // Resuming an ACTIVE session is a socket replacement (e.g. app reconnected before the old
280
- // socket's close event was observed) rather than an error: adopt the new socket, drop the old.
281
- if (session.state === "active" && session.socket && session.socket !== socket) {
282
- const staleSocket = session.socket;
283
- session.socket = undefined; // prevents the stale socket's 'close' handler from suspending us
284
- closeSocket(staleSocket, 1000, "session_replaced");
285
- }
286
- if (session.graceTimer) {
287
- timers.clearTimeout(session.graceTimer);
288
- session.graceTimer = undefined;
289
- }
290
- session.resumeToken = randomBytes(RESUME_TOKEN_BYTES);
291
- session.state = "active";
292
- session.suspendedAt = undefined;
293
- session.socket = socket;
294
- session.missedPongs = 0;
295
- attachSocketHandlers(session);
296
- sendAck(socket, session);
297
- emit("session_resumed", session.sessionId, session.alias, {});
298
- return session.sessionId;
299
- };
300
- const handlePostClaimMessage = (sessionId, socket, message) => {
301
- const session = sessions.get(sessionId);
302
- if (!session) {
303
- closeSocket(socket, 1008, "unknown_session");
304
- return;
305
- }
306
- switch (message.type) {
307
- case "tool_registry_snapshot": {
308
- if (!isToolRegistrySnapshotMessage(message)) {
309
- closeSocket(socket, 1008, "invalid_registry");
310
- return;
311
- }
312
- session.registry.snapshot(message.tools);
313
- return;
314
- }
315
- case "tool_registry_delta": {
316
- if (!isToolRegistryDeltaMessage(message)) {
317
- closeSocket(socket, 1008, "invalid_registry");
318
- return;
319
- }
320
- if (message.operation === "upsert") {
321
- session.registry.upsert(message.tool);
322
- }
323
- else {
324
- session.registry.remove(message.name);
325
- }
326
- return;
327
- }
328
- case "tool_result": {
329
- if (!isToolResultMessage(message)) {
330
- closeSocket(socket, 1008, "invalid_message");
331
- return;
332
- }
333
- options.onToolFrame?.(message);
334
- return;
335
- }
336
- case "tool_error": {
337
- if (!isToolErrorMessage(message)) {
338
- closeSocket(socket, 1008, "invalid_message");
339
- return;
340
- }
341
- options.onToolFrame?.(message);
342
- return;
343
- }
344
- case "tool_call_progress": {
345
- if (!isToolCallProgressMessage(message)) {
346
- closeSocket(socket, 1008, "invalid_message");
347
- return;
348
- }
349
- options.onToolFrame?.(message);
350
- return;
351
- }
352
- case "event": {
353
- if (!isEventMessage(message)) {
354
- closeSocket(socket, 1008, "invalid_message");
355
- return;
356
- }
357
- options.onAppEvent?.(sessionId, session.alias, message);
358
- return;
359
- }
360
- default:
361
- closeSocket(socket, 1008, "unknown_message_type");
362
- }
363
- };
364
- const revoke = (selector) => {
365
- // sessions.revoke is reachable from any state (ARCHITECTURE.md §6), including an unclaimed
366
- // pending link — but only when explicitly selected by sessionId (pending links have no alias
367
- // and are never eligible for the "exactly one live session" implicit-selector default).
368
- if (selector !== undefined && !sessions.has(selector) && pendingLinks.get(selector)) {
369
- pendingLinks.discard(selector);
370
- emit("session_revoked", selector, undefined, {});
371
- return;
372
- }
373
- const session = resolveSession(selector);
374
- if (session.graceTimer) {
375
- timers.clearTimeout(session.graceTimer);
376
- }
377
- if (session.socket) {
378
- closeSocket(session.socket, 1000, "revoked");
379
- }
380
- sessions.delete(session.sessionId);
381
- emit("session_revoked", session.sessionId, session.alias, {});
382
- };
383
- const disposeAll = (code, reason) => {
384
- timers.clearInterval(keepaliveInterval);
385
- pendingLinks.disposeAll();
386
- for (const session of sessions.values()) {
387
- if (session.graceTimer) {
388
- timers.clearTimeout(session.graceTimer);
389
- }
390
- if (session.socket) {
391
- closeSocket(session.socket, code, reason);
392
- }
393
- }
394
- sessions.clear();
395
- };
396
- const resolveForTools = (selector) => {
397
- const session = resolveSession(selector);
398
- return { sessionId: session.sessionId, alias: session.alias, state: session.state, registry: session.registry };
399
- };
400
- const sendToApp = (sessionId, message) => {
401
- const session = sessions.get(sessionId);
402
- if (!session || session.state !== "active" || !session.socket) {
403
- return false;
404
- }
405
- const socket = session.socket;
406
- socket.send(JSON.stringify(message), (error) => {
407
- if (error) {
408
- // A failed send must never throw into the socket library's event loop turn (v1's exact
409
- // defect); the resulting 'close'/'error' drives suspend, which rejects the pending call.
410
- closeSocket(socket, 1011, "send_failed");
411
- }
412
- });
413
- return true;
414
- };
415
- return {
416
- createLink,
417
- handleClaim,
418
- handleResume,
419
- handlePostClaimMessage,
420
- list: () => Array.from(sessions.values(), toSummary),
421
- pendingLinkCount: () => pendingLinks.claimableCount(),
422
- describe: (selector) => toSummary(resolveSession(selector)),
423
- revoke,
424
- resolveForTools,
425
- sendToolCall: sendToApp,
426
- sendToolCancel: sendToApp,
427
- disposeAll,
428
- };
429
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"socket-probe.d.ts","sourceRoot":"","sources":["../../src/daemon/socket-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,YAAY,MAAM,KAAG,OAAO,CAAC,OAAO,CAcvE,CAAC"}