mewkit 1.7.0 → 1.8.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 (264) hide show
  1. package/README.md +76 -0
  2. package/dist/commands/memory.js +3 -3
  3. package/dist/commands/memory.js.map +1 -1
  4. package/dist/commands/orchviz.d.ts +12 -0
  5. package/dist/commands/orchviz.d.ts.map +1 -0
  6. package/dist/commands/orchviz.js +160 -0
  7. package/dist/commands/orchviz.js.map +1 -0
  8. package/dist/commands/setup.d.ts.map +1 -1
  9. package/dist/commands/setup.js +7 -5
  10. package/dist/commands/setup.js.map +1 -1
  11. package/dist/core/skills-dependencies.js +2 -2
  12. package/dist/core/skills-dependencies.js.map +1 -1
  13. package/dist/index.js +50 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/migrate/__tests__/skill-id-utils.test.d.ts +2 -0
  16. package/dist/migrate/__tests__/skill-id-utils.test.d.ts.map +1 -0
  17. package/dist/migrate/__tests__/skill-id-utils.test.js +78 -0
  18. package/dist/migrate/__tests__/skill-id-utils.test.js.map +1 -0
  19. package/dist/migrate/discovery/skill-id-utils.d.ts +18 -0
  20. package/dist/migrate/discovery/skill-id-utils.d.ts.map +1 -0
  21. package/dist/migrate/discovery/skill-id-utils.js +45 -0
  22. package/dist/migrate/discovery/skill-id-utils.js.map +1 -0
  23. package/dist/migrate/discovery/skills-discovery.d.ts.map +1 -1
  24. package/dist/migrate/discovery/skills-discovery.js +5 -1
  25. package/dist/migrate/discovery/skills-discovery.js.map +1 -1
  26. package/dist/migrate/reconcile/portable-registry.d.ts +12 -12
  27. package/dist/migrate/types.d.ts +8 -6
  28. package/dist/migrate/types.d.ts.map +1 -1
  29. package/dist/migrate/types.js.map +1 -1
  30. package/dist/orchviz/constants.d.ts +53 -0
  31. package/dist/orchviz/constants.d.ts.map +1 -0
  32. package/dist/orchviz/constants.js +68 -0
  33. package/dist/orchviz/constants.js.map +1 -0
  34. package/dist/orchviz/fs-utils.d.ts +24 -0
  35. package/dist/orchviz/fs-utils.d.ts.map +1 -0
  36. package/dist/orchviz/fs-utils.js +49 -0
  37. package/dist/orchviz/fs-utils.js.map +1 -0
  38. package/dist/orchviz/index.d.ts +29 -0
  39. package/dist/orchviz/index.d.ts.map +1 -0
  40. package/dist/orchviz/index.js +28 -0
  41. package/dist/orchviz/index.js.map +1 -0
  42. package/dist/orchviz/log-persister.d.ts +22 -0
  43. package/dist/orchviz/log-persister.d.ts.map +1 -0
  44. package/dist/orchviz/log-persister.js +96 -0
  45. package/dist/orchviz/log-persister.js.map +1 -0
  46. package/dist/orchviz/logger.d.ts +13 -0
  47. package/dist/orchviz/logger.d.ts.map +1 -0
  48. package/dist/orchviz/logger.js +47 -0
  49. package/dist/orchviz/logger.js.map +1 -0
  50. package/dist/orchviz/open-url.d.ts +11 -0
  51. package/dist/orchviz/open-url.d.ts.map +1 -0
  52. package/dist/orchviz/open-url.js +28 -0
  53. package/dist/orchviz/open-url.js.map +1 -0
  54. package/dist/orchviz/overlay/collector.d.ts +29 -0
  55. package/dist/orchviz/overlay/collector.d.ts.map +1 -0
  56. package/dist/orchviz/overlay/collector.js +38 -0
  57. package/dist/orchviz/overlay/collector.js.map +1 -0
  58. package/dist/orchviz/overlay/gate-readers.d.ts +18 -0
  59. package/dist/orchviz/overlay/gate-readers.d.ts.map +1 -0
  60. package/dist/orchviz/overlay/gate-readers.js +111 -0
  61. package/dist/orchviz/overlay/gate-readers.js.map +1 -0
  62. package/dist/orchviz/overlay/session-state-readers.d.ts +18 -0
  63. package/dist/orchviz/overlay/session-state-readers.d.ts.map +1 -0
  64. package/dist/orchviz/overlay/session-state-readers.js +78 -0
  65. package/dist/orchviz/overlay/session-state-readers.js.map +1 -0
  66. package/dist/orchviz/parser/handle-progress.d.ts +9 -0
  67. package/dist/orchviz/parser/handle-progress.d.ts.map +1 -0
  68. package/dist/orchviz/parser/handle-progress.js +38 -0
  69. package/dist/orchviz/parser/handle-progress.js.map +1 -0
  70. package/dist/orchviz/parser/handle-text.d.ts +10 -0
  71. package/dist/orchviz/parser/handle-text.d.ts.map +1 -0
  72. package/dist/orchviz/parser/handle-text.js +38 -0
  73. package/dist/orchviz/parser/handle-text.js.map +1 -0
  74. package/dist/orchviz/parser/handle-thinking.d.ts +10 -0
  75. package/dist/orchviz/parser/handle-thinking.d.ts.map +1 -0
  76. package/dist/orchviz/parser/handle-thinking.js +35 -0
  77. package/dist/orchviz/parser/handle-thinking.js.map +1 -0
  78. package/dist/orchviz/parser/handle-tool-result.d.ts +10 -0
  79. package/dist/orchviz/parser/handle-tool-result.d.ts.map +1 -0
  80. package/dist/orchviz/parser/handle-tool-result.js +62 -0
  81. package/dist/orchviz/parser/handle-tool-result.js.map +1 -0
  82. package/dist/orchviz/parser/handle-tool-use.d.ts +11 -0
  83. package/dist/orchviz/parser/handle-tool-use.d.ts.map +1 -0
  84. package/dist/orchviz/parser/handle-tool-use.js +38 -0
  85. package/dist/orchviz/parser/handle-tool-use.js.map +1 -0
  86. package/dist/orchviz/parser/index.d.ts +38 -0
  87. package/dist/orchviz/parser/index.d.ts.map +1 -0
  88. package/dist/orchviz/parser/index.js +139 -0
  89. package/dist/orchviz/parser/index.js.map +1 -0
  90. package/dist/orchviz/parser/label-helpers.d.ts +9 -0
  91. package/dist/orchviz/parser/label-helpers.d.ts.map +1 -0
  92. package/dist/orchviz/parser/label-helpers.js +44 -0
  93. package/dist/orchviz/parser/label-helpers.js.map +1 -0
  94. package/dist/orchviz/parser/strip-ansi.d.ts +6 -0
  95. package/dist/orchviz/parser/strip-ansi.d.ts.map +1 -0
  96. package/dist/orchviz/parser/strip-ansi.js +14 -0
  97. package/dist/orchviz/parser/strip-ansi.js.map +1 -0
  98. package/dist/orchviz/parser/utils.d.ts +20 -0
  99. package/dist/orchviz/parser/utils.d.ts.map +1 -0
  100. package/dist/orchviz/parser/utils.js +56 -0
  101. package/dist/orchviz/parser/utils.js.map +1 -0
  102. package/dist/orchviz/permission-detection.d.ts +18 -0
  103. package/dist/orchviz/permission-detection.d.ts.map +1 -0
  104. package/dist/orchviz/permission-detection.js +50 -0
  105. package/dist/orchviz/permission-detection.js.map +1 -0
  106. package/dist/orchviz/plan/__tests__/apply-todo-toggle.test.d.ts +15 -0
  107. package/dist/orchviz/plan/__tests__/apply-todo-toggle.test.d.ts.map +1 -0
  108. package/dist/orchviz/plan/__tests__/apply-todo-toggle.test.js +165 -0
  109. package/dist/orchviz/plan/__tests__/apply-todo-toggle.test.js.map +1 -0
  110. package/dist/orchviz/plan/__tests__/atomic-write.test.d.ts +11 -0
  111. package/dist/orchviz/plan/__tests__/atomic-write.test.d.ts.map +1 -0
  112. package/dist/orchviz/plan/__tests__/atomic-write.test.js +89 -0
  113. package/dist/orchviz/plan/__tests__/atomic-write.test.js.map +1 -0
  114. package/dist/orchviz/plan/__tests__/end-to-end.test.d.ts +10 -0
  115. package/dist/orchviz/plan/__tests__/end-to-end.test.d.ts.map +1 -0
  116. package/dist/orchviz/plan/__tests__/end-to-end.test.js +132 -0
  117. package/dist/orchviz/plan/__tests__/end-to-end.test.js.map +1 -0
  118. package/dist/orchviz/plan/__tests__/etag.test.d.ts +11 -0
  119. package/dist/orchviz/plan/__tests__/etag.test.d.ts.map +1 -0
  120. package/dist/orchviz/plan/__tests__/etag.test.js +92 -0
  121. package/dist/orchviz/plan/__tests__/etag.test.js.map +1 -0
  122. package/dist/orchviz/plan/__tests__/list-plans.test.d.ts +14 -0
  123. package/dist/orchviz/plan/__tests__/list-plans.test.d.ts.map +1 -0
  124. package/dist/orchviz/plan/__tests__/list-plans.test.js +154 -0
  125. package/dist/orchviz/plan/__tests__/list-plans.test.js.map +1 -0
  126. package/dist/orchviz/plan/apply-todo-toggle.d.ts +29 -0
  127. package/dist/orchviz/plan/apply-todo-toggle.d.ts.map +1 -0
  128. package/dist/orchviz/plan/apply-todo-toggle.js +129 -0
  129. package/dist/orchviz/plan/apply-todo-toggle.js.map +1 -0
  130. package/dist/orchviz/plan/atomic-write.d.ts +25 -0
  131. package/dist/orchviz/plan/atomic-write.d.ts.map +1 -0
  132. package/dist/orchviz/plan/atomic-write.js +85 -0
  133. package/dist/orchviz/plan/atomic-write.js.map +1 -0
  134. package/dist/orchviz/plan/collector.d.ts +49 -0
  135. package/dist/orchviz/plan/collector.d.ts.map +1 -0
  136. package/dist/orchviz/plan/collector.js +173 -0
  137. package/dist/orchviz/plan/collector.js.map +1 -0
  138. package/dist/orchviz/plan/etag.d.ts +24 -0
  139. package/dist/orchviz/plan/etag.d.ts.map +1 -0
  140. package/dist/orchviz/plan/etag.js +58 -0
  141. package/dist/orchviz/plan/etag.js.map +1 -0
  142. package/dist/orchviz/plan/find-active-plan.d.ts +9 -0
  143. package/dist/orchviz/plan/find-active-plan.d.ts.map +1 -0
  144. package/dist/orchviz/plan/find-active-plan.js +90 -0
  145. package/dist/orchviz/plan/find-active-plan.js.map +1 -0
  146. package/dist/orchviz/plan/index.d.ts +23 -0
  147. package/dist/orchviz/plan/index.d.ts.map +1 -0
  148. package/dist/orchviz/plan/index.js +91 -0
  149. package/dist/orchviz/plan/index.js.map +1 -0
  150. package/dist/orchviz/plan/list-plans.d.ts +19 -0
  151. package/dist/orchviz/plan/list-plans.d.ts.map +1 -0
  152. package/dist/orchviz/plan/list-plans.js +148 -0
  153. package/dist/orchviz/plan/list-plans.js.map +1 -0
  154. package/dist/orchviz/plan/parse-phase-file.d.ts +13 -0
  155. package/dist/orchviz/plan/parse-phase-file.d.ts.map +1 -0
  156. package/dist/orchviz/plan/parse-phase-file.js +136 -0
  157. package/dist/orchviz/plan/parse-phase-file.js.map +1 -0
  158. package/dist/orchviz/plan/parse-plan-file.d.ts +19 -0
  159. package/dist/orchviz/plan/parse-plan-file.d.ts.map +1 -0
  160. package/dist/orchviz/plan/parse-plan-file.js +62 -0
  161. package/dist/orchviz/plan/parse-plan-file.js.map +1 -0
  162. package/dist/orchviz/plan/plan-constants.d.ts +17 -0
  163. package/dist/orchviz/plan/plan-constants.d.ts.map +1 -0
  164. package/dist/orchviz/plan/plan-constants.js +19 -0
  165. package/dist/orchviz/plan/plan-constants.js.map +1 -0
  166. package/dist/orchviz/plan/types.d.ts +46 -0
  167. package/dist/orchviz/plan/types.d.ts.map +1 -0
  168. package/dist/orchviz/plan/types.js +6 -0
  169. package/dist/orchviz/plan/types.js.map +1 -0
  170. package/dist/orchviz/protocol.d.ts +116 -0
  171. package/dist/orchviz/protocol.d.ts.map +1 -0
  172. package/dist/orchviz/protocol.js +23 -0
  173. package/dist/orchviz/protocol.js.map +1 -0
  174. package/dist/orchviz/redact.d.ts +10 -0
  175. package/dist/orchviz/redact.d.ts.map +1 -0
  176. package/dist/orchviz/redact.js +38 -0
  177. package/dist/orchviz/redact.js.map +1 -0
  178. package/dist/orchviz/sanitize.d.ts +11 -0
  179. package/dist/orchviz/sanitize.d.ts.map +1 -0
  180. package/dist/orchviz/sanitize.js +38 -0
  181. package/dist/orchviz/sanitize.js.map +1 -0
  182. package/dist/orchviz/server/__tests__/security-smoke.test.d.ts +13 -0
  183. package/dist/orchviz/server/__tests__/security-smoke.test.d.ts.map +1 -0
  184. package/dist/orchviz/server/__tests__/security-smoke.test.js +207 -0
  185. package/dist/orchviz/server/__tests__/security-smoke.test.js.map +1 -0
  186. package/dist/orchviz/server/__tests__/write-handlers.test.d.ts +24 -0
  187. package/dist/orchviz/server/__tests__/write-handlers.test.d.ts.map +1 -0
  188. package/dist/orchviz/server/__tests__/write-handlers.test.js +347 -0
  189. package/dist/orchviz/server/__tests__/write-handlers.test.js.map +1 -0
  190. package/dist/orchviz/server/api-handlers.d.ts +55 -0
  191. package/dist/orchviz/server/api-handlers.d.ts.map +1 -0
  192. package/dist/orchviz/server/api-handlers.js +112 -0
  193. package/dist/orchviz/server/api-handlers.js.map +1 -0
  194. package/dist/orchviz/server/index.d.ts +36 -0
  195. package/dist/orchviz/server/index.d.ts.map +1 -0
  196. package/dist/orchviz/server/index.js +147 -0
  197. package/dist/orchviz/server/index.js.map +1 -0
  198. package/dist/orchviz/server/sse-handler.d.ts +25 -0
  199. package/dist/orchviz/server/sse-handler.d.ts.map +1 -0
  200. package/dist/orchviz/server/sse-handler.js +128 -0
  201. package/dist/orchviz/server/sse-handler.js.map +1 -0
  202. package/dist/orchviz/server/static-handler.d.ts +9 -0
  203. package/dist/orchviz/server/static-handler.d.ts.map +1 -0
  204. package/dist/orchviz/server/static-handler.js +76 -0
  205. package/dist/orchviz/server/static-handler.js.map +1 -0
  206. package/dist/orchviz/server/write-handlers.d.ts +20 -0
  207. package/dist/orchviz/server/write-handlers.d.ts.map +1 -0
  208. package/dist/orchviz/server/write-handlers.js +167 -0
  209. package/dist/orchviz/server/write-handlers.js.map +1 -0
  210. package/dist/orchviz/server/write-utils.d.ts +59 -0
  211. package/dist/orchviz/server/write-utils.d.ts.map +1 -0
  212. package/dist/orchviz/server/write-utils.js +161 -0
  213. package/dist/orchviz/server/write-utils.js.map +1 -0
  214. package/dist/orchviz/session-discovery.d.ts +19 -0
  215. package/dist/orchviz/session-discovery.d.ts.map +1 -0
  216. package/dist/orchviz/session-discovery.js +104 -0
  217. package/dist/orchviz/session-discovery.js.map +1 -0
  218. package/dist/orchviz/session-manager.d.ts +17 -0
  219. package/dist/orchviz/session-manager.d.ts.map +1 -0
  220. package/dist/orchviz/session-manager.js +62 -0
  221. package/dist/orchviz/session-manager.js.map +1 -0
  222. package/dist/orchviz/session-runtime.d.ts +22 -0
  223. package/dist/orchviz/session-runtime.d.ts.map +1 -0
  224. package/dist/orchviz/session-runtime.js +135 -0
  225. package/dist/orchviz/session-runtime.js.map +1 -0
  226. package/dist/orchviz/session-watcher.d.ts +33 -0
  227. package/dist/orchviz/session-watcher.d.ts.map +1 -0
  228. package/dist/orchviz/session-watcher.js +135 -0
  229. package/dist/orchviz/session-watcher.js.map +1 -0
  230. package/dist/orchviz/subagent-meta.d.ts +8 -0
  231. package/dist/orchviz/subagent-meta.d.ts.map +1 -0
  232. package/dist/orchviz/subagent-meta.js +28 -0
  233. package/dist/orchviz/subagent-meta.js.map +1 -0
  234. package/dist/orchviz/subagent-scanner.d.ts +15 -0
  235. package/dist/orchviz/subagent-scanner.d.ts.map +1 -0
  236. package/dist/orchviz/subagent-scanner.js +27 -0
  237. package/dist/orchviz/subagent-scanner.js.map +1 -0
  238. package/dist/orchviz/subagent-watcher.d.ts +19 -0
  239. package/dist/orchviz/subagent-watcher.d.ts.map +1 -0
  240. package/dist/orchviz/subagent-watcher.js +147 -0
  241. package/dist/orchviz/subagent-watcher.js.map +1 -0
  242. package/dist/orchviz/test-server-boot.d.ts +28 -0
  243. package/dist/orchviz/test-server-boot.d.ts.map +1 -0
  244. package/dist/orchviz/test-server-boot.js +64 -0
  245. package/dist/orchviz/test-server-boot.js.map +1 -0
  246. package/dist/orchviz/token-estimator.d.ts +11 -0
  247. package/dist/orchviz/token-estimator.d.ts.map +1 -0
  248. package/dist/orchviz/token-estimator.js +38 -0
  249. package/dist/orchviz/token-estimator.js.map +1 -0
  250. package/dist/orchviz/tool-input-data.d.ts +11 -0
  251. package/dist/orchviz/tool-input-data.d.ts.map +1 -0
  252. package/dist/orchviz/tool-input-data.js +76 -0
  253. package/dist/orchviz/tool-input-data.js.map +1 -0
  254. package/dist/orchviz/tool-summarizer.d.ts +16 -0
  255. package/dist/orchviz/tool-summarizer.d.ts.map +1 -0
  256. package/dist/orchviz/tool-summarizer.js +131 -0
  257. package/dist/orchviz/tool-summarizer.js.map +1 -0
  258. package/dist/orchviz-web/index.css +1 -0
  259. package/dist/orchviz-web/index.html +18 -0
  260. package/dist/orchviz-web/index.js +51 -0
  261. package/package.json +18 -3
  262. package/dist/logger.d.ts +0 -26
  263. package/dist/logger.js +0 -70
  264. package/dist/logger.js.map +0 -1
@@ -0,0 +1,59 @@
1
+ /**
2
+ * write-utils — shared helpers for the POST /api/plan/todo pipeline.
3
+ *
4
+ * Extracted from write-handlers.ts to keep each file ≤200 LOC.
5
+ * Exports: isOriginAllowed, bufferBody, BodyError, handleTodoPreflight.
6
+ */
7
+ import type { IncomingMessage, ServerResponse } from "node:http";
8
+ import { writeJson } from "./api-handlers.js";
9
+ /**
10
+ * Case-insensitive exact equality against the two allowed origins.
11
+ * NO prefix-match, NO contains, NO regex.
12
+ *
13
+ * NOTE: distinct from `isHostAllowed` in server/index.ts — that guards the
14
+ * `Host` header (which proxies may send mixed-case) using a Set; this guards
15
+ * the `Origin` header (always lowercase per browser spec). Do NOT unify.
16
+ */
17
+ export declare function isOriginAllowed(origin: string, port: number): boolean;
18
+ export declare class BodyError extends Error {
19
+ readonly status: number;
20
+ readonly tag: string;
21
+ constructor(status: number, tag: string);
22
+ }
23
+ /**
24
+ * Collect the full request body up to capBytes.
25
+ * Destroys the socket if body exceeds cap OR if timeoutMs elapses first.
26
+ * Throws BodyError(413) on overflow, BodyError(408) on timeout.
27
+ */
28
+ export declare function bufferBody(req: IncomingMessage, capBytes: number, timeoutMs: number): Promise<Buffer>;
29
+ /**
30
+ * Handle OPTIONS /api/plan/todo preflight.
31
+ * H4: allowlist check FIRST — only emit ACAO after passing.
32
+ * Disallowed origin → 403 with NO ACAO header.
33
+ */
34
+ export declare function handleTodoPreflight(req: IncomingMessage, res: ServerResponse, port: number): void;
35
+ /**
36
+ * Wraps realpathSync in try/catch. ANY exception → returns null.
37
+ * Caller must treat null as 403 (fail-closed per R2-6).
38
+ */
39
+ export declare function safeRealpath(p: string): string | null;
40
+ export { writeJson };
41
+ export declare function resetPlansDirCache(): void;
42
+ /**
43
+ * Resolve planDir realpath and verify it sits inside plansDir.
44
+ * Returns { resolvedPlanDir, resolvedPlansDir } on success,
45
+ * or null when any realpath fails or boundary is violated (R2-6, R2-15).
46
+ *
47
+ * `plansDir` realpath is cached per process — that path is constant per
48
+ * project root and resolving it on every POST is wasted syscalls.
49
+ */
50
+ export declare function resolvePlanDirBoundary(plansDir: string, planDir: string): {
51
+ resolvedPlanDir: string;
52
+ resolvedPlansDir: string;
53
+ } | null;
54
+ /**
55
+ * Verify a globbed phase file sits inside resolvedPlanDir (M15, R2-15).
56
+ * Returns the resolved absolute path, or null on failure.
57
+ */
58
+ export declare function resolvePhaseFileBoundary(phaseFilePath: string, resolvedPlanDir: string): string | null;
59
+ //# sourceMappingURL=write-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-utils.d.ts","sourceRoot":"","sources":["../../../src/orchviz/server/write-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9C;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAKrE;AAGD,qBAAa,SAAU,SAAQ,KAAK;aAElB,MAAM,EAAE,MAAM;aACd,GAAG,EAAE,MAAM;gBADX,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM;CAI5B;AAGD;;;;GAIG;AACH,wBAAgB,UAAU,CACzB,GAAG,EAAE,eAAe,EACpB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAwCjB;AAGD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAClC,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE,MAAM,GACV,IAAI,CAaN;AAGD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMrD;AAED,OAAO,EAAE,SAAS,EAAE,CAAC;AAWrB,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACb;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAW9D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACvC,aAAa,EAAE,MAAM,EACrB,eAAe,EAAE,MAAM,GACrB,MAAM,GAAG,IAAI,CAKf"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * write-utils — shared helpers for the POST /api/plan/todo pipeline.
3
+ *
4
+ * Extracted from write-handlers.ts to keep each file ≤200 LOC.
5
+ * Exports: isOriginAllowed, bufferBody, BodyError, handleTodoPreflight.
6
+ */
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import { writeJson } from "./api-handlers.js";
10
+ // ── Origin allowlist (H5) ──────────────────────────────────────────────────
11
+ /**
12
+ * Case-insensitive exact equality against the two allowed origins.
13
+ * NO prefix-match, NO contains, NO regex.
14
+ *
15
+ * NOTE: distinct from `isHostAllowed` in server/index.ts — that guards the
16
+ * `Host` header (which proxies may send mixed-case) using a Set; this guards
17
+ * the `Origin` header (always lowercase per browser spec). Do NOT unify.
18
+ */
19
+ export function isOriginAllowed(origin, port) {
20
+ const lower = origin.toLowerCase();
21
+ const a = `http://127.0.0.1:${port}`;
22
+ const b = `http://localhost:${port}`;
23
+ return lower === a || lower === b;
24
+ }
25
+ // ── Body error ─────────────────────────────────────────────────────────────
26
+ export class BodyError extends Error {
27
+ status;
28
+ tag;
29
+ constructor(status, tag) {
30
+ super(tag);
31
+ this.status = status;
32
+ this.tag = tag;
33
+ }
34
+ }
35
+ // ── Body buffer with socket timeout (M11) ─────────────────────────────────
36
+ /**
37
+ * Collect the full request body up to capBytes.
38
+ * Destroys the socket if body exceeds cap OR if timeoutMs elapses first.
39
+ * Throws BodyError(413) on overflow, BodyError(408) on timeout.
40
+ */
41
+ export function bufferBody(req, capBytes, timeoutMs) {
42
+ return new Promise((resolve, reject) => {
43
+ const chunks = [];
44
+ let total = 0;
45
+ let settled = false;
46
+ const timer = setTimeout(() => {
47
+ if (settled)
48
+ return;
49
+ settled = true;
50
+ req.socket?.destroy();
51
+ reject(new BodyError(408, "request-timeout"));
52
+ }, timeoutMs);
53
+ req.on("data", (chunk) => {
54
+ total += chunk.length;
55
+ if (total > capBytes) {
56
+ if (settled)
57
+ return;
58
+ settled = true;
59
+ clearTimeout(timer);
60
+ req.socket?.destroy();
61
+ reject(new BodyError(413, "body-too-large"));
62
+ return;
63
+ }
64
+ chunks.push(chunk);
65
+ });
66
+ req.on("end", () => {
67
+ if (settled)
68
+ return;
69
+ settled = true;
70
+ clearTimeout(timer);
71
+ resolve(Buffer.concat(chunks));
72
+ });
73
+ req.on("error", (err) => {
74
+ if (settled)
75
+ return;
76
+ settled = true;
77
+ clearTimeout(timer);
78
+ reject(err);
79
+ });
80
+ });
81
+ }
82
+ // ── OPTIONS preflight (H4) ─────────────────────────────────────────────────
83
+ /**
84
+ * Handle OPTIONS /api/plan/todo preflight.
85
+ * H4: allowlist check FIRST — only emit ACAO after passing.
86
+ * Disallowed origin → 403 with NO ACAO header.
87
+ */
88
+ export function handleTodoPreflight(req, res, port) {
89
+ const origin = req.headers["origin"] ?? "";
90
+ if (!isOriginAllowed(origin, port)) {
91
+ res.writeHead(403, { "Content-Type": "text/plain" });
92
+ res.end("Forbidden");
93
+ return;
94
+ }
95
+ res.writeHead(204, {
96
+ "Access-Control-Allow-Origin": origin,
97
+ "Access-Control-Allow-Methods": "POST",
98
+ "Access-Control-Allow-Headers": "content-type",
99
+ });
100
+ res.end();
101
+ }
102
+ // ── realpath helper — fail-closed (R2-6) ──────────────────────────────────
103
+ /**
104
+ * Wraps realpathSync in try/catch. ANY exception → returns null.
105
+ * Caller must treat null as 403 (fail-closed per R2-6).
106
+ */
107
+ export function safeRealpath(p) {
108
+ try {
109
+ return fs.realpathSync(p);
110
+ }
111
+ catch {
112
+ return null;
113
+ }
114
+ }
115
+ export { writeJson };
116
+ // ── Boundary check helpers ─────────────────────────────────────────────────
117
+ /**
118
+ * Module-level cache: plansDir paths are constant per project, so realpath
119
+ * resolves only once per process per project root. Cleared by tests via
120
+ * resetPlansDirCache() if needed.
121
+ */
122
+ const plansDirRealpathCache = new Map();
123
+ export function resetPlansDirCache() {
124
+ plansDirRealpathCache.clear();
125
+ }
126
+ /**
127
+ * Resolve planDir realpath and verify it sits inside plansDir.
128
+ * Returns { resolvedPlanDir, resolvedPlansDir } on success,
129
+ * or null when any realpath fails or boundary is violated (R2-6, R2-15).
130
+ *
131
+ * `plansDir` realpath is cached per process — that path is constant per
132
+ * project root and resolving it on every POST is wasted syscalls.
133
+ */
134
+ export function resolvePlanDirBoundary(plansDir, planDir) {
135
+ let resolvedPlansDir = plansDirRealpathCache.get(plansDir) ?? null;
136
+ if (!resolvedPlansDir) {
137
+ resolvedPlansDir = safeRealpath(plansDir);
138
+ if (!resolvedPlansDir)
139
+ return null;
140
+ plansDirRealpathCache.set(plansDir, resolvedPlansDir);
141
+ }
142
+ const resolvedPlanDir = safeRealpath(planDir);
143
+ if (!resolvedPlanDir)
144
+ return null;
145
+ if (!(resolvedPlanDir + path.sep).startsWith(resolvedPlansDir + path.sep))
146
+ return null;
147
+ return { resolvedPlanDir, resolvedPlansDir };
148
+ }
149
+ /**
150
+ * Verify a globbed phase file sits inside resolvedPlanDir (M15, R2-15).
151
+ * Returns the resolved absolute path, or null on failure.
152
+ */
153
+ export function resolvePhaseFileBoundary(phaseFilePath, resolvedPlanDir) {
154
+ const resolved = safeRealpath(phaseFilePath);
155
+ if (!resolved)
156
+ return null;
157
+ if (!resolved.startsWith(resolvedPlanDir + path.sep))
158
+ return null;
159
+ return resolved;
160
+ }
161
+ //# sourceMappingURL=write-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write-utils.js","sourceRoot":"","sources":["../../../src/orchviz/server/write-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Discover active Claude Code session JSONL files for a workspace.
3
+ *
4
+ * Strategy ported from patoles/agent-flow @ 59ccf4e (scripts/relay.ts
5
+ * scanForActiveSessions). License Apache-2.0 (see ../../NOTICE).
6
+ */
7
+ export declare const CLAUDE_PROJECTS_DIR: string;
8
+ export interface SessionFile {
9
+ sessionId: string;
10
+ filePath: string;
11
+ mtimeMs: number;
12
+ }
13
+ /** Encode a workspace path the way Claude Code names its projects directory. */
14
+ export declare function encodeCwd(workspace: string): string;
15
+ /** Return candidate project dirs for a workspace: encoded dir + any sibling-prefixed dirs. */
16
+ export declare function scanCandidateDirs(workspace: string): string[];
17
+ /** Find active sessions for a workspace (mtime within ageSeconds). */
18
+ export declare function findActiveSessions(workspace: string, ageSeconds?: number): SessionFile[];
19
+ //# sourceMappingURL=session-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-discovery.d.ts","sourceRoot":"","sources":["../../src/orchviz/session-discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,eAAO,MAAM,mBAAmB,QAAiD,CAAC;AAElF,MAAM,WAAW,WAAW;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB7D;AAED,sEAAsE;AACtE,wBAAgB,kBAAkB,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,GAAE,MAA6B,GACvC,WAAW,EAAE,CAkDf"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Discover active Claude Code session JSONL files for a workspace.
3
+ *
4
+ * Strategy ported from patoles/agent-flow @ 59ccf4e (scripts/relay.ts
5
+ * scanForActiveSessions). License Apache-2.0 (see ../../NOTICE).
6
+ */
7
+ import * as fs from "node:fs";
8
+ import * as os from "node:os";
9
+ import * as path from "node:path";
10
+ import { ACTIVE_SESSION_AGE_S } from "./constants.js";
11
+ export const CLAUDE_PROJECTS_DIR = path.join(os.homedir(), ".claude", "projects");
12
+ /** Encode a workspace path the way Claude Code names its projects directory. */
13
+ export function encodeCwd(workspace) {
14
+ let resolved = path.resolve(workspace);
15
+ try {
16
+ resolved = fs.realpathSync(resolved);
17
+ }
18
+ catch {
19
+ // fall through with un-realpathed value
20
+ }
21
+ return resolved.replace(/[^a-zA-Z0-9]/g, "-");
22
+ }
23
+ /** Return candidate project dirs for a workspace: encoded dir + any sibling-prefixed dirs. */
24
+ export function scanCandidateDirs(workspace) {
25
+ if (!fs.existsSync(CLAUDE_PROJECTS_DIR))
26
+ return [];
27
+ const encoded = encodeCwd(workspace);
28
+ const dirs = [];
29
+ const projectDir = path.join(CLAUDE_PROJECTS_DIR, encoded);
30
+ if (fs.existsSync(projectDir))
31
+ dirs.push(projectDir);
32
+ try {
33
+ for (const entry of fs.readdirSync(CLAUDE_PROJECTS_DIR, { withFileTypes: true })) {
34
+ if (!entry.isDirectory())
35
+ continue;
36
+ const full = path.join(CLAUDE_PROJECTS_DIR, entry.name);
37
+ if (full === projectDir)
38
+ continue;
39
+ if (entry.name.startsWith(encoded + "-"))
40
+ dirs.push(full);
41
+ }
42
+ }
43
+ catch {
44
+ // projects dir disappeared mid-scan
45
+ }
46
+ return dirs;
47
+ }
48
+ /** Find active sessions for a workspace (mtime within ageSeconds). */
49
+ export function findActiveSessions(workspace, ageSeconds = ACTIVE_SESSION_AGE_S) {
50
+ const out = [];
51
+ const now = Date.now();
52
+ for (const dirPath of scanCandidateDirs(workspace)) {
53
+ let entries;
54
+ try {
55
+ entries = fs.readdirSync(dirPath);
56
+ }
57
+ catch {
58
+ continue;
59
+ }
60
+ for (const file of entries) {
61
+ if (!file.endsWith(".jsonl"))
62
+ continue;
63
+ const filePath = path.join(dirPath, file);
64
+ let stat;
65
+ try {
66
+ stat = fs.statSync(filePath);
67
+ }
68
+ catch {
69
+ continue;
70
+ }
71
+ if (!stat.isFile())
72
+ continue;
73
+ const sessionId = path.basename(file, ".jsonl");
74
+ let newestMtime = stat.mtimeMs;
75
+ const subagentsDir = path.join(dirPath, sessionId, "subagents");
76
+ try {
77
+ if (fs.existsSync(subagentsDir)) {
78
+ for (const subFile of fs.readdirSync(subagentsDir)) {
79
+ if (!subFile.endsWith(".jsonl"))
80
+ continue;
81
+ let subStat;
82
+ try {
83
+ subStat = fs.statSync(path.join(subagentsDir, subFile));
84
+ }
85
+ catch {
86
+ continue;
87
+ }
88
+ if (subStat.mtimeMs > newestMtime)
89
+ newestMtime = subStat.mtimeMs;
90
+ }
91
+ }
92
+ }
93
+ catch {
94
+ // subagents dir disappeared
95
+ }
96
+ const ageS = (now - newestMtime) / 1000;
97
+ if (ageS <= ageSeconds) {
98
+ out.push({ sessionId, filePath, mtimeMs: newestMtime });
99
+ }
100
+ }
101
+ }
102
+ return out;
103
+ }
104
+ //# sourceMappingURL=session-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-discovery.js","sourceRoot":"","sources":["../../src/orchviz/session-discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * In-memory registry of WatchedSession state, used by parser delegate.
3
+ *
4
+ * Pure data. No fs/io concerns; that's the SessionWatcher's job.
5
+ */
6
+ import type { WatchedSession } from "./protocol.js";
7
+ export declare class SessionManager {
8
+ private readonly sessions;
9
+ private readonly startWallClock;
10
+ create(sessionId: string, filePath: string): WatchedSession;
11
+ get(sessionId: string): WatchedSession | undefined;
12
+ delete(sessionId: string): void;
13
+ list(): WatchedSession[];
14
+ /** Elapsed ms since the manager was constructed. Used as event.time fallback. */
15
+ elapsed(): number;
16
+ }
17
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/orchviz/session-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqC;IAC9D,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAc;IAE7C,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc;IAuC3D,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAIlD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI/B,IAAI,IAAI,cAAc,EAAE;IAIxB,iFAAiF;IACjF,OAAO,IAAI,MAAM;CAGjB"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * In-memory registry of WatchedSession state, used by parser delegate.
3
+ *
4
+ * Pure data. No fs/io concerns; that's the SessionWatcher's job.
5
+ */
6
+ export class SessionManager {
7
+ sessions = new Map();
8
+ startWallClock = Date.now();
9
+ create(sessionId, filePath) {
10
+ const existing = this.sessions.get(sessionId);
11
+ if (existing)
12
+ return existing;
13
+ const session = {
14
+ sessionId,
15
+ filePath,
16
+ fileWatcher: null,
17
+ pollTimer: null,
18
+ fileSize: 0,
19
+ sessionStartTime: Date.now(),
20
+ pendingToolCalls: new Map(),
21
+ seenToolUseIds: new Set(),
22
+ seenMessageHashes: new Set(),
23
+ sessionDetected: true,
24
+ sessionCompleted: false,
25
+ lastActivityTime: Date.now(),
26
+ inactivityTimer: null,
27
+ subagentWatchers: new Map(),
28
+ spawnedSubagents: new Set(),
29
+ inlineProgressAgents: new Set(),
30
+ subagentsDirWatcher: null,
31
+ subagentsDir: null,
32
+ label: sessionId.slice(0, 8),
33
+ labelSet: false,
34
+ model: null,
35
+ permissionTimer: null,
36
+ permissionEmitted: false,
37
+ contextBreakdown: {
38
+ systemPrompt: 0,
39
+ userMessages: 0,
40
+ toolResults: 0,
41
+ reasoning: 0,
42
+ subagentResults: 0,
43
+ },
44
+ };
45
+ this.sessions.set(sessionId, session);
46
+ return session;
47
+ }
48
+ get(sessionId) {
49
+ return this.sessions.get(sessionId);
50
+ }
51
+ delete(sessionId) {
52
+ this.sessions.delete(sessionId);
53
+ }
54
+ list() {
55
+ return Array.from(this.sessions.values());
56
+ }
57
+ /** Elapsed ms since the manager was constructed. Used as event.time fallback. */
58
+ elapsed() {
59
+ return Date.now() - this.startWallClock;
60
+ }
61
+ }
62
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/orchviz/session-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,OAAO,cAAc;IACT,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC7C,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7C,MAAM,CAAC,SAAiB,EAAE,QAAgB;QACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,OAAO,GAAmB;YAC/B,SAAS;YACT,QAAQ;YACR,WAAW,EAAE,IAAI;YACjB,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,CAAC;YACX,gBAAgB,EAAE,IAAI,CAAC,GAAG,EAAE;YAC5B,gBAAgB,EAAE,IAAI,GAAG,EAAE;YAC3B,cAAc,EAAE,IAAI,GAAG,EAAE;YACzB,iBAAiB,EAAE,IAAI,GAAG,EAAE;YAC5B,eAAe,EAAE,IAAI;YACrB,gBAAgB,EAAE,KAAK;YACvB,gBAAgB,EAAE,IAAI,CAAC,GAAG,EAAE;YAC5B,eAAe,EAAE,IAAI;YACrB,gBAAgB,EAAE,IAAI,GAAG,EAAE;YAC3B,gBAAgB,EAAE,IAAI,GAAG,EAAE;YAC3B,oBAAoB,EAAE,IAAI,GAAG,EAAE;YAC/B,mBAAmB,EAAE,IAAI;YACzB,YAAY,EAAE,IAAI;YAClB,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5B,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,IAAI;YACX,eAAe,EAAE,IAAI;YACrB,iBAAiB,EAAE,KAAK;YACxB,gBAAgB,EAAE;gBACjB,YAAY,EAAE,CAAC;gBACf,YAAY,EAAE,CAAC;gBACf,WAAW,EAAE,CAAC;gBACd,SAAS,EAAE,CAAC;gBACZ,eAAe,EAAE,CAAC;aAClB;SACD,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACtC,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,GAAG,CAAC,SAAiB;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,SAAiB;QACvB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,IAAI;QACH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,iFAAiF;IACjF,OAAO;QACN,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC;IACzC,CAAC;CACD"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * SessionRuntime — wires SessionWatcher + TranscriptParser + SessionManager
3
+ * + SubagentScanner. Exposes a single AgentEvent stream for downstream consumers.
4
+ */
5
+ import { EventEmitter } from "node:events";
6
+ import { SessionWatcher, type SessionWatcherOptions } from "./session-watcher.js";
7
+ import { SessionManager } from "./session-manager.js";
8
+ import { TranscriptParser } from "./parser/index.js";
9
+ export interface SessionRuntimeOptions extends SessionWatcherOptions {
10
+ }
11
+ export declare class SessionRuntime extends EventEmitter {
12
+ readonly manager: SessionManager;
13
+ readonly watcher: SessionWatcher;
14
+ readonly parser: TranscriptParser;
15
+ private readonly scanner;
16
+ private disposed;
17
+ constructor(workspace: string, opts?: SessionRuntimeOptions);
18
+ private armInactivity;
19
+ start(): void;
20
+ dispose(): void;
21
+ }
22
+ //# sourceMappingURL=session-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-runtime.d.ts","sourceRoot":"","sources":["../../src/orchviz/session-runtime.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,cAAc,EAAE,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAiC,MAAM,mBAAmB,CAAC;AAKpF,MAAM,WAAW,qBAAsB,SAAQ,qBAAqB;CAAG;AAEvE,qBAAa,cAAe,SAAQ,YAAY;IAC/C,QAAQ,CAAC,OAAO,iBAAwB;IACxC,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAS;gBAEb,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA0B;IA0F/D,OAAO,CAAC,aAAa;IAWrB,KAAK,IAAI,IAAI;IAIb,OAAO,IAAI,IAAI;CAuBf"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * SessionRuntime — wires SessionWatcher + TranscriptParser + SessionManager
3
+ * + SubagentScanner. Exposes a single AgentEvent stream for downstream consumers.
4
+ */
5
+ import * as path from "node:path";
6
+ import { EventEmitter } from "node:events";
7
+ import { SessionWatcher } from "./session-watcher.js";
8
+ import { SessionManager } from "./session-manager.js";
9
+ import { TranscriptParser } from "./parser/index.js";
10
+ import { ORCHESTRATOR_NAME, INACTIVITY_TIMEOUT_MS } from "./constants.js";
11
+ import { SubagentScanner } from "./subagent-scanner.js";
12
+ export class SessionRuntime extends EventEmitter {
13
+ manager = new SessionManager();
14
+ watcher;
15
+ parser;
16
+ scanner;
17
+ disposed = false;
18
+ constructor(workspace, opts = {}) {
19
+ super();
20
+ this.watcher = new SessionWatcher(workspace, opts);
21
+ const emit = (ev, sid) => {
22
+ const event = sid ? { ...ev, sessionId: sid } : ev;
23
+ this.emit("event", event);
24
+ };
25
+ const elapsed = (sid) => {
26
+ if (sid) {
27
+ const s = this.manager.get(sid);
28
+ if (s)
29
+ return Date.now() - s.sessionStartTime;
30
+ }
31
+ return this.manager.elapsed();
32
+ };
33
+ const parserDelegate = {
34
+ emit,
35
+ elapsed,
36
+ getSession: (sid) => this.manager.get(sid),
37
+ fireSessionLifecycle: (lifecycle) => this.emit("lifecycle", lifecycle),
38
+ emitContextUpdate: (agentName, session, sid) => {
39
+ emit({
40
+ time: Date.now() - session.sessionStartTime,
41
+ type: "context_update",
42
+ payload: { agent: agentName, breakdown: { ...session.contextBreakdown } },
43
+ }, sid);
44
+ },
45
+ };
46
+ this.parser = new TranscriptParser(parserDelegate);
47
+ const subagentDelegate = {
48
+ emit,
49
+ elapsed,
50
+ getLastActivityTime: (sid) => this.manager.get(sid)?.lastActivityTime,
51
+ getSession: (sid) => this.manager.get(sid),
52
+ resetInactivityTimer: (sid) => this.armInactivity(sid),
53
+ };
54
+ this.scanner = new SubagentScanner(subagentDelegate, this.parser);
55
+ this.watcher.on("session:start", ({ sessionId, filePath }) => {
56
+ const session = this.manager.create(sessionId, filePath);
57
+ const projectDir = path.dirname(filePath);
58
+ session.subagentsDir = path.join(projectDir, sessionId, "subagents");
59
+ this.armInactivity(sessionId);
60
+ // Spawn the main orchestrator node so the canvas has a root agent for
61
+ // every subsequent tool/message event to attach to. Without this, no
62
+ // nodes ever render — subagents only spawn on Task/Agent tool calls.
63
+ emit({
64
+ time: 0,
65
+ type: "agent_spawn",
66
+ payload: {
67
+ name: ORCHESTRATOR_NAME,
68
+ parent: null,
69
+ task: session.label,
70
+ isMain: true,
71
+ },
72
+ }, sessionId);
73
+ this.scanner.start(sessionId);
74
+ this.emit("session:start", { sessionId, filePath, label: session.label });
75
+ });
76
+ this.watcher.on("session:reset", ({ sessionId }) => {
77
+ this.emit("session:reset", { sessionId });
78
+ });
79
+ this.watcher.on("line", ({ sessionId, line }) => {
80
+ const session = this.manager.get(sessionId);
81
+ if (!session)
82
+ return;
83
+ session.lastActivityTime = Date.now();
84
+ this.parser.processTranscriptLine(line, ORCHESTRATOR_NAME, session.pendingToolCalls, session.seenToolUseIds, sessionId, session.seenMessageHashes);
85
+ });
86
+ this.watcher.on("error", (err) => this.emit("error", err));
87
+ this.watcher.on("closed", () => this.emit("closed"));
88
+ }
89
+ armInactivity(sessionId) {
90
+ const session = this.manager.get(sessionId);
91
+ if (!session)
92
+ return;
93
+ if (session.inactivityTimer)
94
+ clearTimeout(session.inactivityTimer);
95
+ session.inactivityTimer = setTimeout(() => {
96
+ session.sessionCompleted = true;
97
+ this.emit("session:end", { sessionId });
98
+ }, INACTIVITY_TIMEOUT_MS);
99
+ if (typeof session.inactivityTimer.unref === "function")
100
+ session.inactivityTimer.unref();
101
+ }
102
+ start() {
103
+ this.watcher.start();
104
+ }
105
+ dispose() {
106
+ if (this.disposed)
107
+ return;
108
+ this.disposed = true;
109
+ this.scanner.stop();
110
+ for (const s of this.manager.list()) {
111
+ if (s.inactivityTimer)
112
+ clearTimeout(s.inactivityTimer);
113
+ if (s.permissionTimer)
114
+ clearTimeout(s.permissionTimer);
115
+ for (const sa of s.subagentWatchers.values()) {
116
+ if (sa.permissionTimer)
117
+ clearTimeout(sa.permissionTimer);
118
+ try {
119
+ sa.watcher?.close();
120
+ }
121
+ catch {
122
+ // ignore
123
+ }
124
+ }
125
+ try {
126
+ s.subagentsDirWatcher?.close();
127
+ }
128
+ catch {
129
+ // ignore
130
+ }
131
+ }
132
+ this.watcher.dispose();
133
+ }
134
+ }
135
+ //# sourceMappingURL=session-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-runtime.js","sourceRoot":"","sources":["../../src/orchviz/session-runtime.ts"],"names":[],"mappings":"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"}