loopsy 1.0.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 (262) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +425 -0
  3. package/dist/cli/commands/connect.d.ts +2 -0
  4. package/dist/cli/commands/connect.d.ts.map +1 -0
  5. package/dist/cli/commands/connect.js +120 -0
  6. package/dist/cli/commands/connect.js.map +1 -0
  7. package/dist/cli/commands/context.d.ts +2 -0
  8. package/dist/cli/commands/context.d.ts.map +1 -0
  9. package/dist/cli/commands/context.js +39 -0
  10. package/dist/cli/commands/context.js.map +1 -0
  11. package/dist/cli/commands/daemon.d.ts +4 -0
  12. package/dist/cli/commands/daemon.d.ts.map +1 -0
  13. package/dist/cli/commands/daemon.js +55 -0
  14. package/dist/cli/commands/daemon.js.map +1 -0
  15. package/dist/cli/commands/dashboard.d.ts +2 -0
  16. package/dist/cli/commands/dashboard.d.ts.map +1 -0
  17. package/dist/cli/commands/dashboard.js +24 -0
  18. package/dist/cli/commands/dashboard.js.map +1 -0
  19. package/dist/cli/commands/doctor.d.ts +2 -0
  20. package/dist/cli/commands/doctor.d.ts.map +1 -0
  21. package/dist/cli/commands/doctor.js +130 -0
  22. package/dist/cli/commands/doctor.js.map +1 -0
  23. package/dist/cli/commands/exec.d.ts +2 -0
  24. package/dist/cli/commands/exec.d.ts.map +1 -0
  25. package/dist/cli/commands/exec.js +34 -0
  26. package/dist/cli/commands/exec.js.map +1 -0
  27. package/dist/cli/commands/init.d.ts +2 -0
  28. package/dist/cli/commands/init.d.ts.map +1 -0
  29. package/dist/cli/commands/init.js +71 -0
  30. package/dist/cli/commands/init.js.map +1 -0
  31. package/dist/cli/commands/key.d.ts +2 -0
  32. package/dist/cli/commands/key.d.ts.map +1 -0
  33. package/dist/cli/commands/key.js +39 -0
  34. package/dist/cli/commands/key.js.map +1 -0
  35. package/dist/cli/commands/logs.d.ts +2 -0
  36. package/dist/cli/commands/logs.d.ts.map +1 -0
  37. package/dist/cli/commands/logs.js +26 -0
  38. package/dist/cli/commands/logs.js.map +1 -0
  39. package/dist/cli/commands/mcp.d.ts +4 -0
  40. package/dist/cli/commands/mcp.d.ts.map +1 -0
  41. package/dist/cli/commands/mcp.js +70 -0
  42. package/dist/cli/commands/mcp.js.map +1 -0
  43. package/dist/cli/commands/pair.d.ts +6 -0
  44. package/dist/cli/commands/pair.d.ts.map +1 -0
  45. package/dist/cli/commands/pair.js +208 -0
  46. package/dist/cli/commands/pair.js.map +1 -0
  47. package/dist/cli/commands/peers.d.ts +2 -0
  48. package/dist/cli/commands/peers.d.ts.map +1 -0
  49. package/dist/cli/commands/peers.js +29 -0
  50. package/dist/cli/commands/peers.js.map +1 -0
  51. package/dist/cli/commands/service/linux.d.ts +7 -0
  52. package/dist/cli/commands/service/linux.d.ts.map +1 -0
  53. package/dist/cli/commands/service/linux.js +86 -0
  54. package/dist/cli/commands/service/linux.js.map +1 -0
  55. package/dist/cli/commands/service/macos.d.ts +7 -0
  56. package/dist/cli/commands/service/macos.d.ts.map +1 -0
  57. package/dist/cli/commands/service/macos.js +83 -0
  58. package/dist/cli/commands/service/macos.js.map +1 -0
  59. package/dist/cli/commands/service/windows.d.ts +7 -0
  60. package/dist/cli/commands/service/windows.d.ts.map +1 -0
  61. package/dist/cli/commands/service/windows.js +52 -0
  62. package/dist/cli/commands/service/windows.js.map +1 -0
  63. package/dist/cli/commands/service.d.ts +4 -0
  64. package/dist/cli/commands/service.d.ts.map +1 -0
  65. package/dist/cli/commands/service.js +68 -0
  66. package/dist/cli/commands/service.js.map +1 -0
  67. package/dist/cli/commands/session.d.ts +8 -0
  68. package/dist/cli/commands/session.d.ts.map +1 -0
  69. package/dist/cli/commands/session.js +270 -0
  70. package/dist/cli/commands/session.js.map +1 -0
  71. package/dist/cli/commands/transfer.d.ts +3 -0
  72. package/dist/cli/commands/transfer.d.ts.map +1 -0
  73. package/dist/cli/commands/transfer.js +57 -0
  74. package/dist/cli/commands/transfer.js.map +1 -0
  75. package/dist/cli/index.d.ts +3 -0
  76. package/dist/cli/index.d.ts.map +1 -0
  77. package/dist/cli/index.js +89 -0
  78. package/dist/cli/index.js.map +1 -0
  79. package/dist/cli/package-root.d.ts +27 -0
  80. package/dist/cli/package-root.d.ts.map +1 -0
  81. package/dist/cli/package-root.js +54 -0
  82. package/dist/cli/package-root.js.map +1 -0
  83. package/dist/cli/utils.d.ts +11 -0
  84. package/dist/cli/utils.d.ts.map +1 -0
  85. package/dist/cli/utils.js +48 -0
  86. package/dist/cli/utils.js.map +1 -0
  87. package/dist/daemon/config.d.ts +4 -0
  88. package/dist/daemon/config.d.ts.map +1 -0
  89. package/dist/daemon/config.js +58 -0
  90. package/dist/daemon/config.js.map +1 -0
  91. package/dist/daemon/hooks/permission-hook.mjs +108 -0
  92. package/dist/daemon/index.d.ts +3 -0
  93. package/dist/daemon/index.d.ts.map +1 -0
  94. package/dist/daemon/index.js +3 -0
  95. package/dist/daemon/index.js.map +1 -0
  96. package/dist/daemon/main.d.ts +3 -0
  97. package/dist/daemon/main.d.ts.map +1 -0
  98. package/dist/daemon/main.js +28 -0
  99. package/dist/daemon/main.js.map +1 -0
  100. package/dist/daemon/middleware/auth.d.ts +3 -0
  101. package/dist/daemon/middleware/auth.d.ts.map +1 -0
  102. package/dist/daemon/middleware/auth.js +22 -0
  103. package/dist/daemon/middleware/auth.js.map +1 -0
  104. package/dist/daemon/routes/ai-tasks.d.ts +4 -0
  105. package/dist/daemon/routes/ai-tasks.d.ts.map +1 -0
  106. package/dist/daemon/routes/ai-tasks.js +146 -0
  107. package/dist/daemon/routes/ai-tasks.js.map +1 -0
  108. package/dist/daemon/routes/context.d.ts +4 -0
  109. package/dist/daemon/routes/context.d.ts.map +1 -0
  110. package/dist/daemon/routes/context.js +49 -0
  111. package/dist/daemon/routes/context.js.map +1 -0
  112. package/dist/daemon/routes/execute.d.ts +4 -0
  113. package/dist/daemon/routes/execute.d.ts.map +1 -0
  114. package/dist/daemon/routes/execute.js +74 -0
  115. package/dist/daemon/routes/execute.js.map +1 -0
  116. package/dist/daemon/routes/health.d.ts +15 -0
  117. package/dist/daemon/routes/health.d.ts.map +1 -0
  118. package/dist/daemon/routes/health.js +38 -0
  119. package/dist/daemon/routes/health.js.map +1 -0
  120. package/dist/daemon/routes/pair.d.ts +11 -0
  121. package/dist/daemon/routes/pair.d.ts.map +1 -0
  122. package/dist/daemon/routes/pair.js +149 -0
  123. package/dist/daemon/routes/pair.js.map +1 -0
  124. package/dist/daemon/routes/peers.d.ts +5 -0
  125. package/dist/daemon/routes/peers.d.ts.map +1 -0
  126. package/dist/daemon/routes/peers.js +69 -0
  127. package/dist/daemon/routes/peers.js.map +1 -0
  128. package/dist/daemon/routes/transfer.d.ts +4 -0
  129. package/dist/daemon/routes/transfer.d.ts.map +1 -0
  130. package/dist/daemon/routes/transfer.js +135 -0
  131. package/dist/daemon/routes/transfer.js.map +1 -0
  132. package/dist/daemon/server.d.ts +8 -0
  133. package/dist/daemon/server.d.ts.map +1 -0
  134. package/dist/daemon/server.js +170 -0
  135. package/dist/daemon/server.js.map +1 -0
  136. package/dist/daemon/services/ai-task-manager.d.ts +56 -0
  137. package/dist/daemon/services/ai-task-manager.d.ts.map +1 -0
  138. package/dist/daemon/services/ai-task-manager.js +491 -0
  139. package/dist/daemon/services/ai-task-manager.js.map +1 -0
  140. package/dist/daemon/services/audit-logger.d.ts +16 -0
  141. package/dist/daemon/services/audit-logger.d.ts.map +1 -0
  142. package/dist/daemon/services/audit-logger.js +23 -0
  143. package/dist/daemon/services/audit-logger.js.map +1 -0
  144. package/dist/daemon/services/context-store.d.ts +17 -0
  145. package/dist/daemon/services/context-store.d.ts.map +1 -0
  146. package/dist/daemon/services/context-store.js +97 -0
  147. package/dist/daemon/services/context-store.js.map +1 -0
  148. package/dist/daemon/services/job-manager.d.ts +19 -0
  149. package/dist/daemon/services/job-manager.d.ts.map +1 -0
  150. package/dist/daemon/services/job-manager.js +92 -0
  151. package/dist/daemon/services/job-manager.js.map +1 -0
  152. package/dist/daemon/services/tls-manager.d.ts +33 -0
  153. package/dist/daemon/services/tls-manager.d.ts.map +1 -0
  154. package/dist/daemon/services/tls-manager.js +114 -0
  155. package/dist/daemon/services/tls-manager.js.map +1 -0
  156. package/dist/daemon/utils/which.d.ts +2 -0
  157. package/dist/daemon/utils/which.d.ts.map +1 -0
  158. package/dist/daemon/utils/which.js +18 -0
  159. package/dist/daemon/utils/which.js.map +1 -0
  160. package/dist/dashboard/config.d.ts +8 -0
  161. package/dist/dashboard/config.d.ts.map +1 -0
  162. package/dist/dashboard/config.js +22 -0
  163. package/dist/dashboard/config.js.map +1 -0
  164. package/dist/dashboard/public/app.js +120 -0
  165. package/dist/dashboard/public/icon-192.png +0 -0
  166. package/dist/dashboard/public/icon-512.png +0 -0
  167. package/dist/dashboard/public/index.html +85 -0
  168. package/dist/dashboard/public/manifest.json +12 -0
  169. package/dist/dashboard/public/style.css +784 -0
  170. package/dist/dashboard/public/sw.js +31 -0
  171. package/dist/dashboard/public/views/ai-tasks.js +679 -0
  172. package/dist/dashboard/public/views/context.js +167 -0
  173. package/dist/dashboard/public/views/messages.js +263 -0
  174. package/dist/dashboard/public/views/overview.js +228 -0
  175. package/dist/dashboard/public/views/peers.js +136 -0
  176. package/dist/dashboard/public/views/terminal.js +153 -0
  177. package/dist/dashboard/routes/ai-tasks.d.ts +3 -0
  178. package/dist/dashboard/routes/ai-tasks.d.ts.map +1 -0
  179. package/dist/dashboard/routes/ai-tasks.js +193 -0
  180. package/dist/dashboard/routes/ai-tasks.js.map +1 -0
  181. package/dist/dashboard/routes/messages.d.ts +3 -0
  182. package/dist/dashboard/routes/messages.d.ts.map +1 -0
  183. package/dist/dashboard/routes/messages.js +137 -0
  184. package/dist/dashboard/routes/messages.js.map +1 -0
  185. package/dist/dashboard/routes/peer-utils.d.ts +17 -0
  186. package/dist/dashboard/routes/peer-utils.d.ts.map +1 -0
  187. package/dist/dashboard/routes/peer-utils.js +193 -0
  188. package/dist/dashboard/routes/peer-utils.js.map +1 -0
  189. package/dist/dashboard/routes/peers-all.d.ts +3 -0
  190. package/dist/dashboard/routes/peers-all.d.ts.map +1 -0
  191. package/dist/dashboard/routes/peers-all.js +8 -0
  192. package/dist/dashboard/routes/peers-all.js.map +1 -0
  193. package/dist/dashboard/routes/proxy.d.ts +3 -0
  194. package/dist/dashboard/routes/proxy.d.ts.map +1 -0
  195. package/dist/dashboard/routes/proxy.js +59 -0
  196. package/dist/dashboard/routes/proxy.js.map +1 -0
  197. package/dist/dashboard/routes/sessions.d.ts +3 -0
  198. package/dist/dashboard/routes/sessions.d.ts.map +1 -0
  199. package/dist/dashboard/routes/sessions.js +64 -0
  200. package/dist/dashboard/routes/sessions.js.map +1 -0
  201. package/dist/dashboard/routes/sse.d.ts +3 -0
  202. package/dist/dashboard/routes/sse.d.ts.map +1 -0
  203. package/dist/dashboard/routes/sse.js +49 -0
  204. package/dist/dashboard/routes/sse.js.map +1 -0
  205. package/dist/dashboard/routes/status.d.ts +3 -0
  206. package/dist/dashboard/routes/status.d.ts.map +1 -0
  207. package/dist/dashboard/routes/status.js +38 -0
  208. package/dist/dashboard/routes/status.js.map +1 -0
  209. package/dist/dashboard/server.d.ts +3 -0
  210. package/dist/dashboard/server.d.ts.map +1 -0
  211. package/dist/dashboard/server.js +77 -0
  212. package/dist/dashboard/server.js.map +1 -0
  213. package/dist/dashboard/session-manager.d.ts +17 -0
  214. package/dist/dashboard/session-manager.d.ts.map +1 -0
  215. package/dist/dashboard/session-manager.js +225 -0
  216. package/dist/dashboard/session-manager.js.map +1 -0
  217. package/dist/discovery/health-checker.d.ts +15 -0
  218. package/dist/discovery/health-checker.d.ts.map +1 -0
  219. package/dist/discovery/health-checker.js +47 -0
  220. package/dist/discovery/health-checker.js.map +1 -0
  221. package/dist/discovery/index.d.ts +4 -0
  222. package/dist/discovery/index.d.ts.map +1 -0
  223. package/dist/discovery/index.js +4 -0
  224. package/dist/discovery/index.js.map +1 -0
  225. package/dist/discovery/mdns.d.ts +21 -0
  226. package/dist/discovery/mdns.d.ts.map +1 -0
  227. package/dist/discovery/mdns.js +83 -0
  228. package/dist/discovery/mdns.js.map +1 -0
  229. package/dist/discovery/peer-registry.d.ts +18 -0
  230. package/dist/discovery/peer-registry.d.ts.map +1 -0
  231. package/dist/discovery/peer-registry.js +81 -0
  232. package/dist/discovery/peer-registry.js.map +1 -0
  233. package/dist/mcp-server/daemon-client.d.ts +69 -0
  234. package/dist/mcp-server/daemon-client.d.ts.map +1 -0
  235. package/dist/mcp-server/daemon-client.js +281 -0
  236. package/dist/mcp-server/daemon-client.js.map +1 -0
  237. package/dist/mcp-server/index.d.ts +3 -0
  238. package/dist/mcp-server/index.d.ts.map +1 -0
  239. package/dist/mcp-server/index.js +406 -0
  240. package/dist/mcp-server/index.js.map +1 -0
  241. package/dist/protocol/constants.d.ts +66 -0
  242. package/dist/protocol/constants.d.ts.map +1 -0
  243. package/dist/protocol/constants.js +66 -0
  244. package/dist/protocol/constants.js.map +1 -0
  245. package/dist/protocol/errors.d.ts +47 -0
  246. package/dist/protocol/errors.d.ts.map +1 -0
  247. package/dist/protocol/errors.js +62 -0
  248. package/dist/protocol/errors.js.map +1 -0
  249. package/dist/protocol/index.d.ts +5 -0
  250. package/dist/protocol/index.d.ts.map +1 -0
  251. package/dist/protocol/index.js +5 -0
  252. package/dist/protocol/index.js.map +1 -0
  253. package/dist/protocol/schemas.d.ts +209 -0
  254. package/dist/protocol/schemas.d.ts.map +1 -0
  255. package/dist/protocol/schemas.js +115 -0
  256. package/dist/protocol/schemas.js.map +1 -0
  257. package/dist/protocol/types.d.ts +302 -0
  258. package/dist/protocol/types.d.ts.map +1 -0
  259. package/dist/protocol/types.js +2 -0
  260. package/dist/protocol/types.js.map +1 -0
  261. package/package.json +50 -0
  262. package/scripts/postinstall.mjs +42 -0
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Resolves paths to sibling packages (daemon, mcp-server, dashboard).
3
+ *
4
+ * Supports two layouts:
5
+ *
6
+ * 1. Monorepo (dev):
7
+ * packages/cli/dist/package-root.js → __dirname = packages/cli/dist/
8
+ * Sibling packages at: ../../daemon/dist/, ../../mcp-server/dist/, etc.
9
+ *
10
+ * 2. Flat npm package:
11
+ * dist/cli/package-root.js → __dirname = dist/cli/
12
+ * Sibling packages at: ../daemon/, ../mcp-server/, etc.
13
+ *
14
+ * Detection: check if ../../daemon/dist/main.js exists (monorepo) or
15
+ * ../daemon/main.js exists (flat package).
16
+ */
17
+ /**
18
+ * Root directory containing all package dist outputs.
19
+ * - Monorepo: packages/ (so packages/daemon/dist/main.js works)
20
+ * - Flat: dist/ (so dist/daemon/main.js works)
21
+ */
22
+ export declare const PACKAGES_ROOT: string;
23
+ export declare function daemonMainPath(): string;
24
+ export declare function mcpServerPath(): string;
25
+ export declare function dashboardServerPath(): string;
26
+ export declare function hookScriptPath(): string;
27
+ //# sourceMappingURL=package-root.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-root.d.ts","sourceRoot":"","sources":["../src/package-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAeH;;;;GAIG;AACH,eAAO,MAAM,aAAa,QAEE,CAAC;AAE7B,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAI5C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAIvC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Resolves paths to sibling packages (daemon, mcp-server, dashboard).
3
+ *
4
+ * Supports two layouts:
5
+ *
6
+ * 1. Monorepo (dev):
7
+ * packages/cli/dist/package-root.js → __dirname = packages/cli/dist/
8
+ * Sibling packages at: ../../daemon/dist/, ../../mcp-server/dist/, etc.
9
+ *
10
+ * 2. Flat npm package:
11
+ * dist/cli/package-root.js → __dirname = dist/cli/
12
+ * Sibling packages at: ../daemon/, ../mcp-server/, etc.
13
+ *
14
+ * Detection: check if ../../daemon/dist/main.js exists (monorepo) or
15
+ * ../daemon/main.js exists (flat package).
16
+ */
17
+ import { dirname, join, resolve } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { existsSync } from 'node:fs';
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = dirname(__filename);
22
+ // Detect layout by probing for daemon entry point
23
+ const monorepoCandidate = resolve(__dirname, '..', '..', 'daemon', 'dist', 'main.js');
24
+ const flatCandidate = resolve(__dirname, '..', 'daemon', 'main.js');
25
+ const isMonorepo = existsSync(monorepoCandidate);
26
+ /**
27
+ * Root directory containing all package dist outputs.
28
+ * - Monorepo: packages/ (so packages/daemon/dist/main.js works)
29
+ * - Flat: dist/ (so dist/daemon/main.js works)
30
+ */
31
+ export const PACKAGES_ROOT = isMonorepo
32
+ ? resolve(__dirname, '..', '..') // packages/cli/dist/ → packages/
33
+ : resolve(__dirname, '..'); // dist/cli/ → dist/
34
+ export function daemonMainPath() {
35
+ return isMonorepo
36
+ ? join(PACKAGES_ROOT, 'daemon', 'dist', 'main.js')
37
+ : join(PACKAGES_ROOT, 'daemon', 'main.js');
38
+ }
39
+ export function mcpServerPath() {
40
+ return isMonorepo
41
+ ? join(PACKAGES_ROOT, 'mcp-server', 'dist', 'index.js')
42
+ : join(PACKAGES_ROOT, 'mcp-server', 'index.js');
43
+ }
44
+ export function dashboardServerPath() {
45
+ return isMonorepo
46
+ ? join(PACKAGES_ROOT, 'dashboard', 'dist', 'server.js')
47
+ : join(PACKAGES_ROOT, 'dashboard', 'server.js');
48
+ }
49
+ export function hookScriptPath() {
50
+ return isMonorepo
51
+ ? join(PACKAGES_ROOT, 'daemon', 'dist', 'hooks', 'permission-hook.mjs')
52
+ : join(PACKAGES_ROOT, 'daemon', 'hooks', 'permission-hook.mjs');
53
+ }
54
+ //# sourceMappingURL=package-root.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-root.js","sourceRoot":"","sources":["../src/package-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAEtC,kDAAkD;AAClD,MAAM,iBAAiB,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;AACtF,MAAM,aAAa,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEpE,MAAM,UAAU,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;AAEjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,UAAU;IACrC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAG,iCAAiC;IACpE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAQ,oBAAoB;AAEzD,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU;QACf,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;QAClD,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU;QACf,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,CAAC;QACvD,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,UAAU;QACf,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC;QACvD,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU;QACf,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,CAAC;QACvE,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,CAAC,CAAC;AACpE,CAAC"}
@@ -0,0 +1,11 @@
1
+ export declare function loadCliConfig(dataDir?: string): Promise<{
2
+ apiKey: string;
3
+ port: number;
4
+ }>;
5
+ export declare function loadApiKey(): Promise<string>;
6
+ export declare function parsePeerAddress(peer: string): {
7
+ address: string;
8
+ port: number;
9
+ };
10
+ export declare function daemonRequest(path: string, opts?: RequestInit, dataDir?: string): Promise<any>;
11
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAMA,wBAAsB,aAAa,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAa/F;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAGlD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAMhF;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAexG"}
@@ -0,0 +1,48 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { parse as parseYaml } from 'yaml';
5
+ import { DEFAULT_PORT, CONFIG_DIR, CONFIG_FILE } from '@loopsy/protocol';
6
+ export async function loadCliConfig(dataDir) {
7
+ try {
8
+ const dir = dataDir ?? join(homedir(), CONFIG_DIR);
9
+ const configPath = join(dir, CONFIG_FILE);
10
+ const raw = await readFile(configPath, 'utf-8');
11
+ const config = parseYaml(raw);
12
+ return {
13
+ apiKey: config?.auth?.apiKey ?? '',
14
+ port: config?.server?.port ?? DEFAULT_PORT,
15
+ };
16
+ }
17
+ catch {
18
+ return { apiKey: '', port: DEFAULT_PORT };
19
+ }
20
+ }
21
+ export async function loadApiKey() {
22
+ const { apiKey } = await loadCliConfig();
23
+ return apiKey;
24
+ }
25
+ export function parsePeerAddress(peer) {
26
+ const parts = peer.split(':');
27
+ return {
28
+ address: parts[0],
29
+ port: parts.length > 1 ? parseInt(parts[1], 10) : DEFAULT_PORT,
30
+ };
31
+ }
32
+ export async function daemonRequest(path, opts = {}, dataDir) {
33
+ const { apiKey, port } = await loadCliConfig(dataDir);
34
+ const res = await fetch(`http://127.0.0.1:${port}/api/v1${path}`, {
35
+ ...opts,
36
+ headers: {
37
+ 'Content-Type': 'application/json',
38
+ Authorization: `Bearer ${apiKey}`,
39
+ ...opts.headers,
40
+ },
41
+ });
42
+ if (!res.ok) {
43
+ const body = await res.json().catch(() => ({}));
44
+ throw new Error(body.error?.message ?? `HTTP ${res.status}`);
45
+ }
46
+ return res.json();
47
+ }
48
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEzE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAQ,CAAC;QACrC,OAAO;YACL,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE;YAClC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,YAAY;SAC3C,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC;IACzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QACjB,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY;KAC/D,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,OAAoB,EAAE,EAAE,OAAgB;IACxF,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,oBAAoB,IAAI,UAAU,IAAI,EAAE,EAAE;QAChE,GAAG,IAAI;QACP,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,MAAM,EAAE;YACjC,GAAG,IAAI,CAAC,OAAO;SAChB;KACF,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAQ,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { LoopsyConfig } from '@loopsy/protocol';
2
+ export declare function defaultConfig(): LoopsyConfig;
3
+ export declare function loadConfig(dataDir?: string): Promise<LoopsyConfig>;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKrD,wBAAgB,aAAa,IAAI,YAAY,CAqB5C;AAED,wBAAsB,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAcxE"}
@@ -0,0 +1,58 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { parse as parseYaml } from 'yaml';
5
+ import { randomBytes } from 'node:crypto';
6
+ import { CONFIG_DIR, CONFIG_FILE, DEFAULT_PORT, MAX_FILE_SIZE, MAX_CONCURRENT_JOBS, DEFAULT_EXEC_TIMEOUT, RATE_LIMITS } from '@loopsy/protocol';
7
+ const DEFAULT_DATA_DIR = join(homedir(), CONFIG_DIR);
8
+ export function defaultConfig() {
9
+ return {
10
+ server: { port: DEFAULT_PORT, host: '0.0.0.0' },
11
+ auth: {
12
+ apiKey: randomBytes(32).toString('hex'),
13
+ allowedKeys: {},
14
+ },
15
+ execution: {
16
+ denylist: ['rm', 'rmdir', 'format', 'mkfs', 'dd', 'shutdown', 'reboot'],
17
+ maxConcurrent: MAX_CONCURRENT_JOBS,
18
+ defaultTimeout: DEFAULT_EXEC_TIMEOUT,
19
+ },
20
+ transfer: {
21
+ allowedPaths: [homedir()],
22
+ deniedPaths: [join(homedir(), '.ssh'), join(homedir(), '.gnupg')],
23
+ maxFileSize: MAX_FILE_SIZE,
24
+ },
25
+ rateLimits: { ...RATE_LIMITS },
26
+ discovery: { enabled: true, manualPeers: [] },
27
+ logging: { level: 'info' },
28
+ };
29
+ }
30
+ export async function loadConfig(dataDir) {
31
+ const dir = dataDir ?? DEFAULT_DATA_DIR;
32
+ const configPath = join(dir, CONFIG_FILE);
33
+ const defaults = defaultConfig();
34
+ try {
35
+ const raw = await readFile(configPath, 'utf-8');
36
+ const parsed = parseYaml(raw);
37
+ const config = deepMerge(defaults, parsed);
38
+ config.server.dataDir = dir;
39
+ return config;
40
+ }
41
+ catch {
42
+ defaults.server.dataDir = dir;
43
+ return defaults;
44
+ }
45
+ }
46
+ function deepMerge(target, source) {
47
+ const result = { ...target };
48
+ for (const key of Object.keys(source)) {
49
+ if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
50
+ result[key] = deepMerge(result[key] ?? {}, source[key]);
51
+ }
52
+ else if (source[key] !== undefined) {
53
+ result[key] = source[key];
54
+ }
55
+ }
56
+ return result;
57
+ }
58
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+
3
+ // Loopsy PreToolUse Hook for Claude Code
4
+ //
5
+ // This script is invoked by Claude Code's PreToolUse hook mechanism.
6
+ // It fires before every tool use (including in -p mode), registers the
7
+ // permission request with the Loopsy daemon, and polls until the human
8
+ // approves/denies via the dashboard.
9
+ //
10
+ // Exit codes:
11
+ // 0 + JSON stdout → allow or deny (via permissionDecision in hookSpecificOutput)
12
+ //
13
+ // Usage (command-line args embedded by daemon in per-task settings):
14
+ // node permission-hook.mjs <taskId> <port> <apiKey>
15
+
16
+ // Support both CLI args and env vars
17
+ const taskId = process.argv[2] || process.env.LOOPSY_TASK_ID;
18
+ const port = process.argv[3] || process.env.LOOPSY_DAEMON_PORT || '19532';
19
+ const apiKey = process.argv[4] || process.env.LOOPSY_API_KEY;
20
+ const baseUrl = `http://127.0.0.1:${port}`;
21
+
22
+ function allow() {
23
+ process.stdout.write(JSON.stringify({
24
+ hookSpecificOutput: {
25
+ hookEventName: 'PreToolUse',
26
+ permissionDecision: 'allow',
27
+ permissionDecisionReason: 'Approved via Loopsy dashboard',
28
+ },
29
+ }));
30
+ process.exit(0);
31
+ }
32
+
33
+ function deny(reason) {
34
+ process.stdout.write(JSON.stringify({
35
+ hookSpecificOutput: {
36
+ hookEventName: 'PreToolUse',
37
+ permissionDecision: 'deny',
38
+ permissionDecisionReason: reason || 'Denied via Loopsy dashboard',
39
+ },
40
+ }));
41
+ process.exit(0);
42
+ }
43
+
44
+ // If no task ID, this is a normal Claude session — no-op (allow all)
45
+ if (!taskId) {
46
+ process.stdout.write('{}');
47
+ process.exit(0);
48
+ }
49
+
50
+ let input = '';
51
+ process.stdin.on('data', (chunk) => { input += chunk; });
52
+ process.stdin.on('end', async () => {
53
+ try {
54
+ const hookInput = JSON.parse(input);
55
+ const toolName = hookInput.tool_name || 'unknown';
56
+ const requestId = `${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
57
+
58
+ // Register permission request with the daemon
59
+ const registerRes = await fetch(`${baseUrl}/api/v1/ai-tasks/${taskId}/permission-request`, {
60
+ method: 'POST',
61
+ headers: {
62
+ 'Authorization': `Bearer ${apiKey}`,
63
+ 'Content-Type': 'application/json',
64
+ },
65
+ body: JSON.stringify({
66
+ requestId,
67
+ toolName,
68
+ toolInput: hookInput.tool_input || {},
69
+ description: `Claude wants to use: ${toolName}`,
70
+ }),
71
+ });
72
+
73
+ if (!registerRes.ok) {
74
+ deny('Failed to register permission request with daemon');
75
+ return;
76
+ }
77
+
78
+ // Poll for decision (100ms interval, 5min timeout)
79
+ const deadline = Date.now() + 300_000;
80
+ while (Date.now() < deadline) {
81
+ await new Promise((r) => setTimeout(r, 100));
82
+
83
+ try {
84
+ const res = await fetch(
85
+ `${baseUrl}/api/v1/ai-tasks/${taskId}/permission-response?requestId=${requestId}`,
86
+ { headers: { 'Authorization': `Bearer ${apiKey}` } },
87
+ );
88
+ if (!res.ok) continue;
89
+
90
+ const data = await res.json();
91
+ if (data.resolved) {
92
+ if (data.approved) {
93
+ allow();
94
+ } else {
95
+ deny(data.message || 'Denied by user');
96
+ }
97
+ return;
98
+ }
99
+ } catch {
100
+ // Network error during poll — keep trying
101
+ }
102
+ }
103
+
104
+ deny('Permission request timed out (5 minutes)');
105
+ } catch (err) {
106
+ deny(`Hook error: ${err.message}`);
107
+ }
108
+ });
@@ -0,0 +1,3 @@
1
+ export { createDaemon, type DaemonServer } from './server.js';
2
+ export { loadConfig, defaultConfig } from './config.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { createDaemon } from './server.js';
2
+ export { loadConfig, defaultConfig } from './config.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAqB,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":""}
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ import { loadConfig } from './config.js';
3
+ import { createDaemon } from './server.js';
4
+ function parseArgs() {
5
+ const args = process.argv.slice(2);
6
+ const idx = args.indexOf('--data-dir');
7
+ if (idx !== -1 && args[idx + 1]) {
8
+ return { dataDir: args[idx + 1] };
9
+ }
10
+ return {};
11
+ }
12
+ async function main() {
13
+ const { dataDir } = parseArgs();
14
+ const config = await loadConfig(dataDir);
15
+ const daemon = await createDaemon(config);
16
+ const shutdown = async () => {
17
+ await daemon.stop();
18
+ process.exit(0);
19
+ };
20
+ process.on('SIGINT', shutdown);
21
+ process.on('SIGTERM', shutdown);
22
+ await daemon.start();
23
+ }
24
+ main().catch((err) => {
25
+ console.error('Failed to start Loopsy daemon:', err);
26
+ process.exit(1);
27
+ });
28
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,SAAS,SAAS;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;QAChC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAE1C,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;AACvB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;IACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { FastifyRequest, FastifyReply } from 'fastify';
2
+ export declare function createAuthHook(ownKey: string, allowedKeys: Record<string, string>): (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5D,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAGlE,SAAS,cAAc,EAAE,OAAO,YAAY,mBAkB3D"}
@@ -0,0 +1,22 @@
1
+ import { LoopsyError, LoopsyErrorCode } from '@loopsy/protocol';
2
+ export function createAuthHook(ownKey, allowedKeys) {
3
+ const validKeys = new Set([ownKey, ...Object.values(allowedKeys)]);
4
+ return async (request, reply) => {
5
+ // Skip auth for health endpoint
6
+ if (request.url === '/api/v1/health')
7
+ return;
8
+ const authHeader = request.headers.authorization;
9
+ if (!authHeader) {
10
+ const err = new LoopsyError(LoopsyErrorCode.AUTH_MISSING_KEY, 'Missing Authorization header');
11
+ reply.code(401).send(err.toJSON());
12
+ return;
13
+ }
14
+ const key = authHeader.replace(/^Bearer\s+/i, '');
15
+ if (!validKeys.has(key)) {
16
+ const err = new LoopsyError(LoopsyErrorCode.AUTH_INVALID_KEY, 'Invalid API key');
17
+ reply.code(403).send(err.toJSON());
18
+ return;
19
+ }
20
+ };
21
+ }
22
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,WAAmC;IAChF,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAEnE,OAAO,KAAK,EAAE,OAAuB,EAAE,KAAmB,EAAE,EAAE;QAC5D,gCAAgC;QAChC,IAAI,OAAO,CAAC,GAAG,KAAK,gBAAgB;YAAE,OAAO;QAE7C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QACjD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,eAAe,CAAC,gBAAgB,EAAE,8BAA8B,CAAC,CAAC;YAC9F,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,eAAe,CAAC,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;YACjF,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACnC,OAAO;QACT,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { AiTaskManager } from '../services/ai-task-manager.js';
3
+ export declare function registerAiTaskRoutes(app: FastifyInstance, aiTaskManager: AiTaskManager): void;
4
+ //# sourceMappingURL=ai-tasks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-tasks.d.ts","sourceRoot":"","sources":["../../src/routes/ai-tasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAGpE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,QAyKtF"}
@@ -0,0 +1,146 @@
1
+ import { AiTaskParamsSchema, AiTaskApprovalResponseSchema, PermissionRequestBodySchema } from '@loopsy/protocol';
2
+ export function registerAiTaskRoutes(app, aiTaskManager) {
3
+ // Dispatch a new AI task
4
+ app.post('/api/v1/ai-tasks', async (request, reply) => {
5
+ const params = AiTaskParamsSchema.parse(request.body);
6
+ const fromNodeId = request.headers['x-loopsy-node-id'] || 'remote';
7
+ try {
8
+ const info = await aiTaskManager.dispatch(params, fromNodeId);
9
+ reply.code(201);
10
+ return info;
11
+ }
12
+ catch (err) {
13
+ if (err.code === 6002) {
14
+ reply.code(429);
15
+ return { error: err.message };
16
+ }
17
+ if (err.code === 6006) {
18
+ reply.code(500);
19
+ return { error: err.message };
20
+ }
21
+ throw err;
22
+ }
23
+ });
24
+ // List all tasks (active + recent)
25
+ app.get('/api/v1/ai-tasks', async () => {
26
+ return { tasks: aiTaskManager.getAllTasks() };
27
+ });
28
+ // Get a single task
29
+ app.get('/api/v1/ai-tasks/:taskId', async (request, reply) => {
30
+ const info = aiTaskManager.getTask(request.params.taskId);
31
+ if (!info) {
32
+ reply.code(404);
33
+ return { error: 'Task not found' };
34
+ }
35
+ return info;
36
+ });
37
+ // SSE stream for a task
38
+ app.get('/api/v1/ai-tasks/:taskId/stream', async (request, reply) => {
39
+ const { taskId } = request.params;
40
+ reply.raw.writeHead(200, {
41
+ 'Content-Type': 'text/event-stream',
42
+ 'Cache-Control': 'no-cache',
43
+ 'Connection': 'keep-alive',
44
+ 'X-Accel-Buffering': 'no',
45
+ });
46
+ // Send buffered events first (for reconnecting clients)
47
+ const since = request.query.since ? parseInt(request.query.since, 10) : 0;
48
+ const buffer = aiTaskManager.getEventBuffer(taskId);
49
+ for (const event of buffer) {
50
+ if (event.timestamp > since) {
51
+ reply.raw.write(`data: ${JSON.stringify(event)}\n\n`);
52
+ }
53
+ }
54
+ // Subscribe to live events
55
+ const unsubscribe = aiTaskManager.subscribe(taskId, (event) => {
56
+ if (!reply.raw.destroyed) {
57
+ reply.raw.write(`data: ${JSON.stringify(event)}\n\n`);
58
+ }
59
+ });
60
+ if (!unsubscribe) {
61
+ // Task not active — check if it's a recent completed task
62
+ const info = aiTaskManager.getTask(taskId);
63
+ if (info) {
64
+ reply.raw.write(`data: ${JSON.stringify({ type: 'status', taskId, timestamp: Date.now(), data: { status: info.status } })}\n\n`);
65
+ }
66
+ else {
67
+ reply.raw.write(`data: ${JSON.stringify({ type: 'error', taskId, timestamp: Date.now(), data: 'Task not found' })}\n\n`);
68
+ }
69
+ reply.raw.end();
70
+ return;
71
+ }
72
+ // Clean up on disconnect
73
+ request.raw.on('close', () => {
74
+ unsubscribe();
75
+ });
76
+ // Keep connection open until task completes or client disconnects
77
+ // The 'exit' event from the task will trigger the subscriber, and the client
78
+ // can close the EventSource after receiving it.
79
+ });
80
+ // Register a permission request from the hook script
81
+ // Called by permission-hook.mjs when Claude wants to use a tool
82
+ app.post('/api/v1/ai-tasks/:taskId/permission-request', async (request, reply) => {
83
+ const { taskId } = request.params;
84
+ const body = PermissionRequestBodySchema.parse(request.body);
85
+ const success = aiTaskManager.registerPermissionRequest(taskId, {
86
+ requestId: body.requestId,
87
+ toolName: body.toolName,
88
+ toolInput: body.toolInput,
89
+ description: body.description,
90
+ });
91
+ if (!success) {
92
+ reply.code(404);
93
+ return { error: 'Task not found' };
94
+ }
95
+ return { success: true, requestId: body.requestId };
96
+ });
97
+ // Poll for permission response (called by hook script)
98
+ app.get('/api/v1/ai-tasks/:taskId/permission-response', async (request, reply) => {
99
+ const { taskId } = request.params;
100
+ const { requestId } = request.query;
101
+ if (!requestId) {
102
+ reply.code(400);
103
+ return { error: 'requestId query parameter required' };
104
+ }
105
+ const response = aiTaskManager.getPermissionResponse(taskId, requestId);
106
+ if (!response) {
107
+ return { resolved: false };
108
+ }
109
+ return {
110
+ resolved: true,
111
+ approved: response.approved,
112
+ message: response.message || '',
113
+ };
114
+ });
115
+ // Approve/deny a permission request (called by dashboard)
116
+ app.post('/api/v1/ai-tasks/:taskId/approve', async (request, reply) => {
117
+ const { taskId } = request.params;
118
+ const response = AiTaskApprovalResponseSchema.parse(request.body);
119
+ const success = aiTaskManager.approve(taskId, response);
120
+ if (!success) {
121
+ reply.code(400);
122
+ return { error: 'No pending permission request found for this task' };
123
+ }
124
+ return { success: true, taskId };
125
+ });
126
+ // Get event buffer for a task (for debugging and catch-up)
127
+ app.get('/api/v1/ai-tasks/:taskId/events', async (request, reply) => {
128
+ const events = aiTaskManager.getEventBuffer(request.params.taskId);
129
+ return { events, count: events.length };
130
+ });
131
+ // Cancel a running task
132
+ app.delete('/api/v1/ai-tasks/:taskId', async (request, reply) => {
133
+ const success = aiTaskManager.cancel(request.params.taskId);
134
+ if (!success) {
135
+ // Maybe it's a completed task — try deleting from recent
136
+ const deleted = aiTaskManager.deleteTask(request.params.taskId);
137
+ if (!deleted) {
138
+ reply.code(404);
139
+ return { error: 'Task not found' };
140
+ }
141
+ return { success: true, taskId: request.params.taskId, deleted: true };
142
+ }
143
+ return { success: true, taskId: request.params.taskId };
144
+ });
145
+ }
146
+ //# sourceMappingURL=ai-tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-tasks.js","sourceRoot":"","sources":["../../src/routes/ai-tasks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type { ContextStore } from '../services/context-store.js';
3
+ export declare function registerContextRoutes(app: FastifyInstance, contextStore: ContextStore): void;
4
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/routes/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,eAAe,EAAE,YAAY,EAAE,YAAY,QAgDrF"}