@the-open-engine/zeroshot 6.38.1 → 6.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/README.md +6 -0
  2. package/cli/event-copy.js +8 -7
  3. package/cli/event-copy.ts +12 -0
  4. package/cli/index.js +67 -48
  5. package/cli/json-export.js +61 -64
  6. package/cli/json-export.ts +112 -0
  7. package/cli/message-formatter-utils.js +68 -56
  8. package/cli/message-formatter-utils.ts +121 -0
  9. package/cli/message-formatters-normal.js +124 -259
  10. package/cli/message-formatters-normal.ts +250 -0
  11. package/cli/message-formatters-watch.js +81 -84
  12. package/cli/message-formatters-watch.ts +189 -0
  13. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  14. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  15. package/lib/cluster/generated/protocol.d.cts +8 -0
  16. package/lib/cluster/generated/protocol.d.mts +8 -0
  17. package/lib/cluster/generated/protocol.d.ts +8 -0
  18. package/lib/clusters-registry.d.ts +23 -0
  19. package/lib/clusters-registry.js +17 -29
  20. package/lib/completion.d.ts +12 -0
  21. package/lib/completion.js +84 -94
  22. package/lib/compose-utils.d.ts +32 -0
  23. package/lib/compose-utils.js +57 -72
  24. package/lib/detached-startup.d.ts +84 -0
  25. package/lib/detached-startup.js +232 -302
  26. package/lib/docker-config.d.ts +43 -0
  27. package/lib/docker-config.js +150 -325
  28. package/lib/docker-env-auth.d.ts +17 -0
  29. package/lib/docker-env-auth.js +75 -0
  30. package/lib/git-remote-utils.d.ts +48 -0
  31. package/lib/git-remote-utils.js +147 -213
  32. package/lib/id-detector.d.ts +15 -0
  33. package/lib/id-detector.js +37 -41
  34. package/lib/path-check.d.ts +30 -0
  35. package/lib/path-check.js +42 -45
  36. package/lib/process-liveness.d.ts +16 -0
  37. package/lib/process-liveness.js +19 -12
  38. package/lib/provider-credential-path.d.ts +16 -0
  39. package/lib/provider-credential-path.js +31 -29
  40. package/lib/provider-defaults.d.ts +30 -0
  41. package/lib/provider-defaults.js +47 -42
  42. package/lib/provider-detection.d.ts +11 -0
  43. package/lib/provider-detection.js +91 -54
  44. package/lib/provider-names.d.ts +38 -0
  45. package/lib/provider-names.js +56 -64
  46. package/lib/repo-settings.d.ts +28 -0
  47. package/lib/repo-settings.js +83 -59
  48. package/lib/run-mode.d.ts +21 -0
  49. package/lib/run-mode.js +21 -20
  50. package/lib/run-plan.d.ts +28 -0
  51. package/lib/run-plan.js +17 -16
  52. package/lib/settings/claude-auth.d.ts +35 -0
  53. package/lib/settings/claude-auth.js +30 -47
  54. package/lib/settings-defaults.d.ts +20 -0
  55. package/lib/settings-defaults.js +149 -0
  56. package/lib/settings-error.d.ts +7 -0
  57. package/lib/settings-error.js +8 -0
  58. package/lib/settings-issue-providers.d.ts +10 -0
  59. package/lib/settings-issue-providers.js +12 -0
  60. package/lib/settings-models.d.ts +22 -0
  61. package/lib/settings-models.js +93 -0
  62. package/lib/settings-storage.d.ts +23 -0
  63. package/lib/settings-storage.js +205 -0
  64. package/lib/settings-validation.d.ts +7 -0
  65. package/lib/settings-validation.js +182 -0
  66. package/lib/settings.d.ts +29 -0
  67. package/lib/settings.js +41 -736
  68. package/lib/setup-apply-types.d.ts +66 -0
  69. package/lib/setup-apply-types.js +2 -0
  70. package/lib/setup-apply.d.ts +39 -0
  71. package/lib/setup-apply.js +267 -264
  72. package/lib/setup-journal.d.ts +41 -0
  73. package/lib/setup-journal.js +119 -76
  74. package/lib/setup-plan-types.d.ts +102 -0
  75. package/lib/setup-plan-types.js +2 -0
  76. package/lib/setup-plan.d.ts +30 -0
  77. package/lib/setup-plan.js +300 -324
  78. package/lib/setup-undo.d.ts +44 -0
  79. package/lib/setup-undo.js +61 -74
  80. package/lib/start-cluster-config.d.ts +26 -0
  81. package/lib/start-cluster-config.js +56 -0
  82. package/lib/start-cluster-environment.d.ts +41 -0
  83. package/lib/start-cluster-environment.js +134 -0
  84. package/lib/start-cluster-run-options.d.ts +54 -0
  85. package/lib/start-cluster-run-options.js +148 -0
  86. package/lib/start-cluster.d.ts +64 -0
  87. package/lib/start-cluster.js +98 -454
  88. package/lib/stream-json-parser.d.ts +17 -0
  89. package/lib/stream-json-parser.js +51 -52
  90. package/npm-shrinkwrap.json +6 -8
  91. package/package.json +14 -8
  92. package/scripts/postinstall.js +27 -0
  93. package/scripts/rust-distribution.js +36 -45
  94. package/src/agent/agent-command-proofs-context.js +35 -45
  95. package/src/agent/agent-command-proofs-context.ts +87 -0
  96. package/src/agent/agent-config-settings.js +19 -0
  97. package/src/agent/agent-config-settings.ts +41 -0
  98. package/src/agent/agent-config.js +122 -231
  99. package/src/agent/agent-config.ts +285 -0
  100. package/src/agent/agent-context-builder.js +38 -273
  101. package/src/agent/agent-context-builder.ts +51 -0
  102. package/src/agent/agent-context-environment-sections.js +105 -0
  103. package/src/agent/agent-context-environment-sections.ts +134 -0
  104. package/src/agent/agent-context-packs.js +165 -0
  105. package/src/agent/agent-context-packs.ts +296 -0
  106. package/src/agent/agent-context-prompt-sections.js +100 -0
  107. package/src/agent/agent-context-prompt-sections.ts +148 -0
  108. package/src/agent/agent-context-sections.js +25 -334
  109. package/src/agent/agent-context-sections.ts +36 -0
  110. package/src/agent/agent-context-sources.js +96 -149
  111. package/src/agent/agent-context-sources.ts +253 -0
  112. package/src/agent/agent-context-types.js +2 -0
  113. package/src/agent/agent-context-types.ts +132 -0
  114. package/src/agent/agent-context-validation-sections.js +73 -0
  115. package/src/agent/agent-context-validation-sections.ts +129 -0
  116. package/src/agent/agent-input-injector.js +99 -118
  117. package/src/agent/agent-input-injector.ts +195 -0
  118. package/src/agent/agent-liveness-poll.js +74 -78
  119. package/src/agent/agent-liveness-poll.ts +163 -0
  120. package/src/agent/agent-quality-gate-schema.js +77 -86
  121. package/src/agent/agent-quality-gate-schema.ts +135 -0
  122. package/src/agent/agent-quality-gates-context.js +44 -50
  123. package/src/agent/agent-quality-gates-context.ts +91 -0
  124. package/src/agent/agent-stuck-detector.js +171 -239
  125. package/src/agent/agent-stuck-detector.ts +288 -0
  126. package/src/agent/agent-trigger-evaluator.js +29 -46
  127. package/src/agent/agent-trigger-evaluator.ts +98 -0
  128. package/src/agent/context-metrics.js +110 -141
  129. package/src/agent/context-metrics.ts +261 -0
  130. package/src/agent/context-pack-builder.js +72 -358
  131. package/src/agent/context-pack-builder.ts +105 -0
  132. package/src/agent/context-pack-core.js +70 -0
  133. package/src/agent/context-pack-core.ts +96 -0
  134. package/src/agent/context-pack-selection.js +119 -0
  135. package/src/agent/context-pack-selection.ts +187 -0
  136. package/src/agent/context-pack-truncation.js +139 -0
  137. package/src/agent/context-pack-truncation.ts +208 -0
  138. package/src/agent/context-pack-types.js +2 -0
  139. package/src/agent/context-pack-types.ts +98 -0
  140. package/src/agent/context-replay-policy.js +30 -39
  141. package/src/agent/context-replay-policy.ts +71 -0
  142. package/src/agent/critical-agent-policy.js +6 -10
  143. package/src/agent/critical-agent-policy.ts +20 -0
  144. package/src/agent/guidance-queue.js +74 -87
  145. package/src/agent/guidance-queue.ts +166 -0
  146. package/src/agent/output-extraction-error-detail.js +45 -0
  147. package/src/agent/output-extraction-error-detail.ts +49 -0
  148. package/src/agent/output-extraction-failures.js +125 -0
  149. package/src/agent/output-extraction-failures.ts +149 -0
  150. package/src/agent/output-extraction-json.js +234 -0
  151. package/src/agent/output-extraction-json.ts +235 -0
  152. package/src/agent/output-extraction-pi.js +124 -0
  153. package/src/agent/output-extraction-pi.ts +137 -0
  154. package/src/agent/output-extraction-types.js +2 -0
  155. package/src/agent/output-extraction-types.ts +49 -0
  156. package/src/agent/output-extraction.js +17 -617
  157. package/src/agent/output-extraction.ts +30 -0
  158. package/src/agent/output-reformatter-errors.js +83 -0
  159. package/src/agent/output-reformatter-errors.ts +106 -0
  160. package/src/agent/output-reformatter-types.js +2 -0
  161. package/src/agent/output-reformatter-types.ts +86 -0
  162. package/src/agent/output-reformatter.js +140 -185
  163. package/src/agent/output-reformatter.ts +238 -0
  164. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  165. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  166. package/src/agent/pi-terminal-lifecycle.js +186 -206
  167. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  168. package/src/agent/provider-control-plane.js +22 -21
  169. package/src/agent/provider-control-plane.ts +52 -0
  170. package/src/agent/provider-terminal-failure-types.js +2 -0
  171. package/src/agent/provider-terminal-failure-types.ts +60 -0
  172. package/src/agent/provider-terminal-failure.js +194 -191
  173. package/src/agent/provider-terminal-failure.ts +262 -0
  174. package/src/agent/rate-limit-backoff.js +31 -74
  175. package/src/agent/rate-limit-backoff.ts +71 -0
  176. package/src/agent/schema-utils.js +85 -125
  177. package/src/agent/schema-utils.ts +148 -0
  178. package/src/agent/structured-output-error.js +34 -33
  179. package/src/agent/structured-output-error.ts +105 -0
  180. package/src/agent/validation-platform.js +27 -27
  181. package/src/agent/validation-platform.ts +49 -0
  182. package/src/agents/git-pusher-template.js +17 -34
  183. package/src/attach/attach-client.js +232 -405
  184. package/src/attach/attach-client.ts +300 -0
  185. package/src/attach/attach-server-cleanup.js +43 -0
  186. package/src/attach/attach-server-cleanup.ts +39 -0
  187. package/src/attach/attach-server-clients.js +117 -0
  188. package/src/attach/attach-server-clients.ts +122 -0
  189. package/src/attach/attach-server-events.js +38 -0
  190. package/src/attach/attach-server-events.ts +36 -0
  191. package/src/attach/attach-server-pty.js +45 -0
  192. package/src/attach/attach-server-pty.ts +64 -0
  193. package/src/attach/attach-server-runtime.js +73 -0
  194. package/src/attach/attach-server-runtime.ts +62 -0
  195. package/src/attach/attach-server-socket.js +28 -0
  196. package/src/attach/attach-server-socket.ts +23 -0
  197. package/src/attach/attach-server-types.js +2 -0
  198. package/src/attach/attach-server-types.ts +82 -0
  199. package/src/attach/attach-server.js +106 -523
  200. package/src/attach/attach-server.ts +158 -0
  201. package/src/attach/index.js +18 -35
  202. package/src/attach/index.ts +18 -0
  203. package/src/attach/protocol.js +95 -184
  204. package/src/attach/protocol.ts +181 -0
  205. package/src/attach/ring-buffer.js +76 -102
  206. package/src/attach/ring-buffer.ts +109 -0
  207. package/src/attach/send-input.js +64 -75
  208. package/src/attach/send-input.ts +94 -0
  209. package/src/attach/socket-discovery.js +164 -218
  210. package/src/attach/socket-discovery.ts +230 -0
  211. package/src/attach/socket-paths.js +42 -61
  212. package/src/attach/socket-paths.ts +81 -0
  213. package/src/claude-credentials.js +51 -54
  214. package/src/claude-credentials.ts +89 -0
  215. package/src/cluster/generated/protocol-schema.ts +1 -1
  216. package/src/cluster/generated/protocol.ts +2 -1
  217. package/src/command-proofs.js +110 -141
  218. package/src/command-proofs.ts +216 -0
  219. package/src/config-router.js +81 -73
  220. package/src/config-router.ts +131 -0
  221. package/src/copy-containment.js +191 -0
  222. package/src/copy-containment.ts +259 -0
  223. package/src/copy-worker.js +53 -30
  224. package/src/copy-worker.ts +88 -0
  225. package/src/darwin-keychain-boundary.js +80 -111
  226. package/src/darwin-keychain-boundary.ts +148 -0
  227. package/src/guidance-topics.js +4 -5
  228. package/src/guidance-topics.ts +10 -0
  229. package/src/input-helpers.js +33 -54
  230. package/src/input-helpers.ts +58 -0
  231. package/src/isolation-manager.js +59 -20
  232. package/src/ledger-sequence.js +45 -48
  233. package/src/ledger-sequence.ts +63 -0
  234. package/src/legacy-lib/clusters-registry.ts +40 -0
  235. package/src/legacy-lib/completion.ts +148 -0
  236. package/src/legacy-lib/compose-utils.ts +102 -0
  237. package/src/legacy-lib/detached-startup.ts +451 -0
  238. package/src/legacy-lib/docker-config.ts +282 -0
  239. package/src/legacy-lib/docker-env-auth.ts +116 -0
  240. package/src/legacy-lib/git-remote-utils.ts +244 -0
  241. package/src/legacy-lib/id-detector.ts +57 -0
  242. package/src/legacy-lib/js-yaml.d.ts +3 -0
  243. package/src/legacy-lib/omelette.d.ts +15 -0
  244. package/src/legacy-lib/path-check.ts +89 -0
  245. package/src/legacy-lib/process-liveness.ts +36 -0
  246. package/src/legacy-lib/provider-credential-path.ts +57 -0
  247. package/src/legacy-lib/provider-defaults.ts +114 -0
  248. package/src/legacy-lib/provider-detection.ts +67 -0
  249. package/src/legacy-lib/provider-names.ts +126 -0
  250. package/src/legacy-lib/repo-settings.ts +88 -0
  251. package/src/legacy-lib/run-mode.ts +58 -0
  252. package/src/legacy-lib/run-plan.ts +49 -0
  253. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  254. package/src/legacy-lib/settings-defaults.ts +212 -0
  255. package/src/legacy-lib/settings-error.ts +8 -0
  256. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  257. package/src/legacy-lib/settings-models.ts +124 -0
  258. package/src/legacy-lib/settings-storage.ts +277 -0
  259. package/src/legacy-lib/settings-validation.ts +220 -0
  260. package/src/legacy-lib/settings.ts +87 -0
  261. package/src/legacy-lib/setup-apply-types.ts +70 -0
  262. package/src/legacy-lib/setup-apply.ts +456 -0
  263. package/src/legacy-lib/setup-journal.ts +185 -0
  264. package/src/legacy-lib/setup-plan-types.ts +96 -0
  265. package/src/legacy-lib/setup-plan.ts +500 -0
  266. package/src/legacy-lib/setup-undo.ts +142 -0
  267. package/src/legacy-lib/start-cluster-config.ts +124 -0
  268. package/src/legacy-lib/start-cluster-environment.ts +166 -0
  269. package/src/legacy-lib/start-cluster-run-options.ts +281 -0
  270. package/src/legacy-lib/start-cluster.ts +237 -0
  271. package/src/legacy-lib/stream-json-parser.ts +88 -0
  272. package/src/message-buffer.js +55 -71
  273. package/src/message-buffer.ts +107 -0
  274. package/src/message-bus-bridge.js +92 -133
  275. package/src/message-bus-bridge.ts +149 -0
  276. package/src/name-generator-shared.js +220 -0
  277. package/src/name-generator-shared.ts +231 -0
  278. package/src/name-generator.js +8 -217
  279. package/src/name-generator.ts +27 -0
  280. package/src/omp-blob-root.js +83 -64
  281. package/src/omp-blob-root.ts +116 -0
  282. package/src/omp-config-overlay.js +65 -38
  283. package/src/omp-config-overlay.ts +110 -0
  284. package/src/omp-execution-fingerprint.js +38 -43
  285. package/src/omp-execution-fingerprint.ts +92 -0
  286. package/src/omp-session-limits.js +10 -15
  287. package/src/omp-session-limits.ts +53 -0
  288. package/src/omp-session-partition.js +2 -2
  289. package/src/omp-session-verifier.js +1 -1
  290. package/src/orchestrator.js +32 -7
  291. package/src/pr-body-template.js +71 -0
  292. package/src/providers/anthropic/index.js +3 -1
  293. package/src/providers/anthropic/index.ts +13 -0
  294. package/src/providers/capabilities.js +19 -27
  295. package/src/providers/capabilities.ts +44 -0
  296. package/src/providers/google/index.js +3 -1
  297. package/src/providers/google/index.ts +13 -0
  298. package/src/providers/openai/index.js +3 -1
  299. package/src/providers/openai/index.ts +13 -0
  300. package/src/providers/opencode/index.js +3 -1
  301. package/src/providers/opencode/index.ts +13 -0
  302. package/src/quality-gates.js +67 -127
  303. package/src/quality-gates.ts +149 -0
  304. package/src/repo-settings-access.js +40 -0
  305. package/src/repo-settings-access.ts +64 -0
  306. package/src/schemas/sub-cluster.js +127 -183
  307. package/src/schemas/sub-cluster.ts +238 -0
  308. package/src/state-snapshot-normalization.js +224 -0
  309. package/src/state-snapshot-normalization.ts +222 -0
  310. package/src/state-snapshot.js +192 -359
  311. package/src/state-snapshot.ts +291 -0
  312. package/src/state-snapshotter.js +118 -130
  313. package/src/state-snapshotter.ts +167 -0
  314. package/src/sub-cluster-wrapper.js +4 -13
  315. package/src/task-run-model-args.js +87 -124
  316. package/src/task-run-model-args.ts +204 -0
  317. package/src/task-runner.js +5 -25
  318. package/src/task-runner.ts +28 -0
  319. package/src/task-startup-error.js +73 -58
  320. package/src/task-startup-error.ts +126 -0
  321. package/src/template-validation/consensus-gate-contracts.js +2 -0
  322. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  323. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  324. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  325. package/src/template-validation/consensus-gate-stage.js +34 -0
  326. package/src/template-validation/consensus-gate-stage.ts +56 -0
  327. package/src/template-validation/random-topology-contracts.js +2 -0
  328. package/src/template-validation/random-topology-contracts.ts +54 -0
  329. package/src/template-validation/random-topology-dispatch.js +25 -0
  330. package/src/template-validation/random-topology-dispatch.ts +33 -0
  331. package/src/template-validation/random-topology-message-loop.js +53 -0
  332. package/src/template-validation/random-topology-message-loop.ts +73 -0
  333. package/src/template-validation/random-topology-operations.js +79 -0
  334. package/src/template-validation/random-topology-operations.ts +101 -0
  335. package/src/template-validation/random-topology-runtime.js +25 -0
  336. package/src/template-validation/random-topology-runtime.ts +43 -0
  337. package/src/template-validation/random-topology-scenario.js +52 -0
  338. package/src/template-validation/random-topology-scenario.ts +57 -0
  339. package/src/template-validation/random-topology-schema.js +159 -0
  340. package/src/template-validation/random-topology-schema.ts +190 -0
  341. package/src/template-validation/random-topology-state.js +28 -0
  342. package/src/template-validation/random-topology-state.ts +30 -0
  343. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  344. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  345. package/src/template-validation/random-topology-trigger.js +75 -0
  346. package/src/template-validation/random-topology-trigger.ts +88 -0
  347. package/src/template-validation/report-formatter.js +40 -46
  348. package/src/template-validation/report-formatter.ts +101 -0
  349. package/src/template-validation/simulate-consensus-gates.js +111 -302
  350. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  351. package/src/template-validation/simulate-random-topology.js +26 -519
  352. package/src/template-validation/simulate-random-topology.ts +57 -0
  353. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  354. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  355. package/src/template-validation/simulation-agent-runtime.js +25 -0
  356. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  357. package/src/template-validation/simulation-agent.js +29 -0
  358. package/src/template-validation/simulation-agent.ts +73 -0
  359. package/src/template-validation/simulation-runtime.js +34 -0
  360. package/src/template-validation/simulation-runtime.ts +72 -0
  361. package/src/template-validation/two-stage-contracts.js +2 -0
  362. package/src/template-validation/two-stage-contracts.ts +41 -0
  363. package/src/template-validation/two-stage-inputs.js +21 -0
  364. package/src/template-validation/two-stage-inputs.ts +29 -0
  365. package/src/template-validation/two-stage-results.js +30 -0
  366. package/src/template-validation/two-stage-results.ts +40 -0
  367. package/src/template-validation/two-stage-scenario.js +86 -0
  368. package/src/template-validation/two-stage-scenario.ts +120 -0
  369. package/src/worktree-claude-config.js +182 -220
  370. package/src/worktree-claude-config.ts +272 -0
  371. package/src/worktree-tooling-env.js +103 -125
  372. package/src/worktree-tooling-env.ts +142 -0
  373. package/task-lib/completion.js +2 -3
  374. package/task-lib/completion.ts +9 -0
  375. package/task-lib/config.js +1 -4
  376. package/task-lib/config.ts +11 -0
  377. package/task-lib/name-generator.js +4 -226
  378. package/task-lib/name-generator.ts +11 -0
  379. package/task-lib/omp-session-cleanup.js +1 -1
  380. package/task-lib/omp-storage-root.js +8 -12
  381. package/task-lib/omp-storage-root.ts +62 -0
  382. package/task-lib/process-termination.js +143 -166
  383. package/task-lib/process-termination.ts +268 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Copy Worker - Worker thread for parallel file copying
3
+ *
4
+ * Handles copying a batch of files from source to destination.
5
+ * Used by IsolationManager._copyDirExcluding() for parallel copying.
6
+ */
7
+ import fs = require('fs');
8
+ import { parentPort, workerData } from 'worker_threads';
9
+ import {
10
+ copyErrorCode,
11
+ createCopyBoundary,
12
+ isCopyContainmentError,
13
+ isCopyRecord,
14
+ resolveCopyPath,
15
+ } from './copy-containment';
16
+ import type { CopyBoundary } from './copy-containment';
17
+ interface CopyWorkerData {
18
+ files: string[];
19
+ sourceBase: string;
20
+ destBase: string;
21
+ expectedBoundary: CopyBoundary;
22
+ }
23
+ interface CopyError {
24
+ file: string;
25
+ name: string;
26
+ code: string | null;
27
+ message: string;
28
+ relativePath: unknown;
29
+ }
30
+ function isCopyWorkerData(value: unknown): value is CopyWorkerData {
31
+ if (!isCopyRecord(value)) {
32
+ return false;
33
+ }
34
+ return (
35
+ Array.isArray(value.files) &&
36
+ value.files.every((entry: unknown) => typeof entry === 'string') &&
37
+ typeof value.sourceBase === 'string' &&
38
+ typeof value.destBase === 'string' &&
39
+ isCopyRecord(value.expectedBoundary)
40
+ );
41
+ }
42
+ function errorMessage(error: unknown): string {
43
+ return error instanceof Error ? error.message : String(error);
44
+ }
45
+ const rawWorkerData: unknown = workerData;
46
+ if (!isCopyWorkerData(rawWorkerData)) {
47
+ throw new TypeError('copy worker requires files, sourceBase, and destBase');
48
+ }
49
+ const { files, sourceBase, destBase, expectedBoundary } = rawWorkerData;
50
+ const copyBoundary = createCopyBoundary(sourceBase, destBase, expectedBoundary);
51
+ let copied = 0;
52
+ let skipped = 0;
53
+ let error: CopyError | null = null;
54
+ for (const relativePath of files) {
55
+ try {
56
+ // Phase two creates every parent directory. Re-resolve the source and
57
+ // destination immediately before the only worker filesystem effect.
58
+ const { sourcePath, destinationPath } = resolveCopyPath(copyBoundary, relativePath);
59
+ fs.copyFileSync(sourcePath, destinationPath);
60
+ copied++;
61
+ } catch (caughtError: unknown) {
62
+ // Skip files we can't copy (permission denied, broken symlinks, etc.)
63
+ const code = copyErrorCode(caughtError);
64
+ if (
65
+ !isCopyContainmentError(caughtError) &&
66
+ (code === 'EACCES' || code === 'EPERM' || code === 'ENOENT')
67
+ ) {
68
+ skipped++;
69
+ continue;
70
+ }
71
+ error = {
72
+ file: relativePath,
73
+ name: caughtError instanceof Error ? caughtError.name : 'Error',
74
+ code,
75
+ message: errorMessage(caughtError),
76
+ relativePath:
77
+ isCopyRecord(caughtError) && 'relativePath' in caughtError
78
+ ? caughtError.relativePath
79
+ : relativePath,
80
+ };
81
+ break;
82
+ }
83
+ }
84
+ // Report results back to main thread
85
+ if (!parentPort) {
86
+ throw new Error('copy worker requires a parent port');
87
+ }
88
+ parentPort.postMessage({ copied, skipped, error });
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  /**
2
3
  * Darwin worker Keychain boundary (issue #704).
3
4
  *
@@ -15,46 +16,41 @@
15
16
  * Docker isolation never reaches this code path, and non-darwin platforms are
16
17
  * left untouched. Set ZEROSHOT_ALLOW_INTERACTIVE_KEYCHAIN=1 to opt out.
17
18
  */
18
-
19
- const fs = require('fs');
20
- const os = require('os');
21
- const path = require('path');
22
- const { randomUUID } = require('node:crypto');
23
-
19
+ const node_crypto_1 = require("node:crypto");
20
+ const fs = require("fs");
21
+ const os = require("os");
22
+ const path = require("path");
24
23
  const SHIM_DIR_RELATIVE_PATH = path.join('.zeroshot', 'keychain-shim');
25
24
  const REAL_SECURITY_PATH = '/usr/bin/security';
26
25
  const OPT_OUT_ENV_VAR = 'ZEROSHOT_ALLOW_INTERACTIVE_KEYCHAIN';
27
-
28
26
  function shellQuote(value) {
29
- return `'${String(value).replace(/'/g, `'\\''`)}'`;
27
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
28
+ }
29
+ function errorMessage(error) {
30
+ return error instanceof Error ? error.message : String(error);
30
31
  }
31
-
32
32
  function buildSecurityShimScript(realSecurityPath) {
33
- return `#!/bin/sh
33
+ return `#!/bin/sh
34
34
  # Managed by Zeroshot (src/darwin-keychain-boundary.js). Do not edit.
35
35
  #
36
36
  # Non-interactive Zeroshot workers must not open the logged-in user's GUI
37
37
  # Keychain session (SecurityAgent). Interactive \`security\` invocations fail
38
38
  # closed here; every other subcommand is passed through to the real binary so
39
39
  # provider authentication keeps working.
40
-
41
40
  REAL_SECURITY=${shellQuote(realSecurityPath)}
42
-
43
41
  if [ "\${${OPT_OUT_ENV_VAR}:-0}" = "1" ]; then
44
42
  exec "$REAL_SECURITY" "$@"
45
43
  fi
46
-
47
44
  fail_closed() {
48
45
  echo "zeroshot: blocked interactive 'security' invocation from a non-interactive worker (argv: $*)." >&2
49
46
  echo "zeroshot: this cluster has no interactive Keychain session, so SecurityAgent prompts are disabled." >&2
50
- echo "zeroshot: run the cluster with Docker isolation or configure explicit credentials for the tool that attempted Keychain access." >&2
47
+ echo "zeroshot: run the cluster with Docker isolation or configure explicit credentials for the tool that "\
48
+ "attempted Keychain access." >&2
51
49
  echo "zeroshot: set ${OPT_OUT_ENV_VAR}=1 to restore interactive Keychain access." >&2
52
50
  exit 1
53
51
  }
54
-
55
52
  # \`security\` without arguments enters interactive mode.
56
53
  [ "$#" -eq 0 ] && fail_closed
57
-
58
54
  # Global options precede the subcommand. -i (interactive) and -p (prompt,
59
55
  # implies -i) must not reach the real binary; option letters may be bundled
60
56
  # (e.g. -qi). Scanning stops at the first non-option token (the subcommand).
@@ -65,110 +61,83 @@ for arg in "$@"; do
65
61
  *) break ;;
66
62
  esac
67
63
  done
68
-
69
64
  exec "$REAL_SECURITY" "$@"
70
65
  `;
71
66
  }
72
-
73
- /**
74
- * Create (or refresh) the managed shim directory containing the `security`
75
- * wrapper. Idempotent: the script is only rewritten when its content changes.
76
- *
77
- * @param {object} [options]
78
- * @param {string} [options.shimBaseDir] - Shim directory (tests only); defaults to ~/.zeroshot/keychain-shim.
79
- * @param {string} [options.realSecurityPath] - Real binary to exec (tests only); defaults to /usr/bin/security.
80
- * @returns {string} Absolute path of the shim directory.
81
- */
67
+ /** Create or refresh the managed directory containing the `security` shim. */
82
68
  function ensureDarwinKeychainShimDir(options = {}) {
83
- const shimDir = options.shimBaseDir || path.join(os.homedir(), SHIM_DIR_RELATIVE_PATH);
84
- const script = buildSecurityShimScript(options.realSecurityPath || REAL_SECURITY_PATH);
85
- const shimPath = path.join(shimDir, 'security');
86
-
87
- fs.mkdirSync(shimDir, { recursive: true });
88
-
89
- let existing = null;
90
- try {
91
- existing = fs.readFileSync(shimPath, 'utf8');
92
- } catch {
93
- // Missing or unreadable: (re)write below.
94
- }
95
- if (existing !== script) {
96
- const tempPath = path.join(shimDir, `.security.${process.pid}.${randomUUID()}.tmp`);
69
+ const shimDir = options.shimBaseDir || path.join(os.homedir(), SHIM_DIR_RELATIVE_PATH);
70
+ const script = buildSecurityShimScript(options.realSecurityPath || REAL_SECURITY_PATH);
71
+ const shimPath = path.join(shimDir, 'security');
72
+ fs.mkdirSync(shimDir, { recursive: true });
73
+ let existing = null;
97
74
  try {
98
- fs.writeFileSync(tempPath, script, { mode: 0o755, flag: 'wx' });
99
- // The creation mode is subject to umask. Set the final mode before the
100
- // rename so the live path is never observable as non-executable.
101
- fs.chmodSync(tempPath, 0o755);
102
- fs.renameSync(tempPath, shimPath);
103
- } catch (error) {
104
- try {
105
- // Remove any unpublished partial file without masking the publication
106
- // failure that caused this cleanup path.
107
- fs.rmSync(tempPath, { force: true });
108
- } catch (cleanupError) {
109
- error.message += ` Cleanup also failed: ${cleanupError.message}.`;
110
- }
111
- throw error;
75
+ existing = fs.readFileSync(shimPath, 'utf8');
76
+ }
77
+ catch {
78
+ // Missing or unreadable: (re)write below.
112
79
  }
113
- } else {
114
- // An existing matching shim may have drifted permissions.
115
- fs.chmodSync(shimPath, 0o755);
116
- }
117
-
118
- return shimDir;
80
+ if (existing !== script) {
81
+ const tempPath = path.join(shimDir, `.security.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`);
82
+ try {
83
+ fs.writeFileSync(tempPath, script, { mode: 0o755, flag: 'wx' });
84
+ // The creation mode is subject to umask. Set the final mode before the
85
+ // rename so the live path is never observable as non-executable.
86
+ fs.chmodSync(tempPath, 0o755);
87
+ fs.renameSync(tempPath, shimPath);
88
+ }
89
+ catch (error) {
90
+ try {
91
+ // Remove any unpublished partial file without masking the publication
92
+ // failure that caused this cleanup path.
93
+ fs.rmSync(tempPath, { force: true });
94
+ }
95
+ catch (cleanupError) {
96
+ if (error instanceof Error) {
97
+ error.message += ` Cleanup also failed: ${errorMessage(cleanupError)}.`;
98
+ }
99
+ }
100
+ throw error;
101
+ }
102
+ }
103
+ else {
104
+ // An existing matching shim may have drifted permissions.
105
+ fs.chmodSync(shimPath, 0o755);
106
+ }
107
+ return shimDir;
119
108
  }
120
-
121
- /**
122
- * Prepend the Keychain boundary shim to a worker spawn env's PATH.
123
- *
124
- * No-op off darwin and when the operator opted out via
125
- * ZEROSHOT_ALLOW_INTERACTIVE_KEYCHAIN=1. Fails closed (throws) when the shim
126
- * cannot be installed: spawning the worker anyway would silently re-expose the
127
- * interactive Keychain session.
128
- *
129
- * @param {object} env - Spawn env to mutate (also returned).
130
- * @param {object} [options]
131
- * @param {string} [options.platform] - Platform override (tests only).
132
- * @param {string} [options.shimBaseDir] - See ensureDarwinKeychainShimDir.
133
- * @param {string} [options.realSecurityPath] - See ensureDarwinKeychainShimDir.
134
- * @returns {object} The same env object.
135
- */
109
+ /** Prepend the Keychain boundary shim to a worker spawn environment's PATH. */
136
110
  function applyDarwinKeychainBoundaryToEnv(env, options = {}) {
137
- const platform = options.platform || process.platform;
138
- if (platform !== 'darwin') {
139
- return env;
140
- }
141
- if (env[OPT_OUT_ENV_VAR] === '1' || process.env[OPT_OUT_ENV_VAR] === '1') {
111
+ const platform = options.platform || process.platform;
112
+ if (platform !== 'darwin') {
113
+ return env;
114
+ }
115
+ if (env[OPT_OUT_ENV_VAR] === '1' || process.env[OPT_OUT_ENV_VAR] === '1') {
116
+ return env;
117
+ }
118
+ let shimDir;
119
+ try {
120
+ shimDir = ensureDarwinKeychainShimDir(options);
121
+ }
122
+ catch (error) {
123
+ throw new Error(`Failed to install the darwin Keychain boundary shim: ${errorMessage(error)}. ` +
124
+ `Non-interactive workers must not reach the interactive Keychain session; ` +
125
+ `use Docker isolation or set ${OPT_OUT_ENV_VAR}=1 to opt out.`);
126
+ }
127
+ // Darwin environment keys are case-sensitive: descendants consult PATH,
128
+ // never a differently-cased key such as Path. Preserve empty components
129
+ // because POSIX interprets them as the current directory. An absent PATH
130
+ // retains Node/libuv's default Unix search path after the shim, while an
131
+ // explicitly empty PATH retains its empty component (`<shim>:`).
132
+ const existingEntries = env.PATH === undefined
133
+ ? ['/usr/bin', '/bin']
134
+ : String(env.PATH)
135
+ .split(path.delimiter)
136
+ .filter((entry) => entry !== shimDir);
137
+ env.PATH = [shimDir, ...existingEntries].join(path.delimiter);
142
138
  return env;
143
- }
144
-
145
- let shimDir;
146
- try {
147
- shimDir = ensureDarwinKeychainShimDir(options);
148
- } catch (error) {
149
- throw new Error(
150
- `Failed to install the darwin Keychain boundary shim: ${error.message}. ` +
151
- `Non-interactive workers must not reach the interactive Keychain session; ` +
152
- `use Docker isolation or set ${OPT_OUT_ENV_VAR}=1 to opt out.`
153
- );
154
- }
155
-
156
- // Darwin environment keys are case-sensitive: descendants consult PATH,
157
- // never a differently-cased key such as Path. Preserve empty components
158
- // because POSIX interprets them as the current directory. An absent PATH
159
- // retains Node/libuv's default Unix search path after the shim, while an
160
- // explicitly empty PATH retains its empty component (`<shim>:`).
161
- const existingEntries =
162
- env.PATH === undefined
163
- ? ['/usr/bin', '/bin']
164
- : String(env.PATH)
165
- .split(path.delimiter)
166
- .filter((entry) => entry !== shimDir);
167
- env.PATH = [shimDir, ...existingEntries].join(path.delimiter);
168
- return env;
169
139
  }
170
-
171
140
  module.exports = {
172
- applyDarwinKeychainBoundaryToEnv,
173
- ensureDarwinKeychainShimDir,
141
+ applyDarwinKeychainBoundaryToEnv,
142
+ ensureDarwinKeychainShimDir,
174
143
  };
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Darwin worker Keychain boundary (issue #704).
3
+ *
4
+ * Non-interactive local/worktree workers are spawned with the host environment,
5
+ * so worker descendants (e.g. `claude doctor` probing Keychain writes through
6
+ * `security -i`) reach the logged-in user's GUI Keychain session and launch
7
+ * SecurityAgent dialogs from a supposedly non-interactive cluster.
8
+ *
9
+ * On darwin, worker spawn envs get a managed shim directory prepended to PATH
10
+ * containing a `security` wrapper that fails closed on interactive invocations
11
+ * (`-i`, `-p`, or no arguments) with a deterministic diagnostic, and execs the
12
+ * real /usr/bin/security for every other subcommand so provider authentication
13
+ * (e.g. `security find-generic-password`) keeps working.
14
+ *
15
+ * Docker isolation never reaches this code path, and non-darwin platforms are
16
+ * left untouched. Set ZEROSHOT_ALLOW_INTERACTIVE_KEYCHAIN=1 to opt out.
17
+ */
18
+ import { randomUUID } from 'node:crypto';
19
+ import fs = require('fs');
20
+ import os = require('os');
21
+ import path = require('path');
22
+ interface DarwinKeychainBoundaryOptions {
23
+ platform?: string;
24
+ shimBaseDir?: string;
25
+ realSecurityPath?: string;
26
+ }
27
+ const SHIM_DIR_RELATIVE_PATH = path.join('.zeroshot', 'keychain-shim');
28
+ const REAL_SECURITY_PATH = '/usr/bin/security';
29
+ const OPT_OUT_ENV_VAR = 'ZEROSHOT_ALLOW_INTERACTIVE_KEYCHAIN';
30
+ function shellQuote(value: unknown): string {
31
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
32
+ }
33
+ function errorMessage(error: unknown): string {
34
+ return error instanceof Error ? error.message : String(error);
35
+ }
36
+ function buildSecurityShimScript(realSecurityPath: string): string {
37
+ return `#!/bin/sh
38
+ # Managed by Zeroshot (src/darwin-keychain-boundary.js). Do not edit.
39
+ #
40
+ # Non-interactive Zeroshot workers must not open the logged-in user's GUI
41
+ # Keychain session (SecurityAgent). Interactive \`security\` invocations fail
42
+ # closed here; every other subcommand is passed through to the real binary so
43
+ # provider authentication keeps working.
44
+ REAL_SECURITY=${shellQuote(realSecurityPath)}
45
+ if [ "\${${OPT_OUT_ENV_VAR}:-0}" = "1" ]; then
46
+ exec "$REAL_SECURITY" "$@"
47
+ fi
48
+ fail_closed() {
49
+ echo "zeroshot: blocked interactive 'security' invocation from a non-interactive worker (argv: $*)." >&2
50
+ echo "zeroshot: this cluster has no interactive Keychain session, so SecurityAgent prompts are disabled." >&2
51
+ echo "zeroshot: run the cluster with Docker isolation or configure explicit credentials for the tool that "\
52
+ "attempted Keychain access." >&2
53
+ echo "zeroshot: set ${OPT_OUT_ENV_VAR}=1 to restore interactive Keychain access." >&2
54
+ exit 1
55
+ }
56
+ # \`security\` without arguments enters interactive mode.
57
+ [ "$#" -eq 0 ] && fail_closed
58
+ # Global options precede the subcommand. -i (interactive) and -p (prompt,
59
+ # implies -i) must not reach the real binary; option letters may be bundled
60
+ # (e.g. -qi). Scanning stops at the first non-option token (the subcommand).
61
+ for arg in "$@"; do
62
+ case "$arg" in
63
+ -*i*|-*p*) fail_closed "$@" ;;
64
+ -*) ;;
65
+ *) break ;;
66
+ esac
67
+ done
68
+ exec "$REAL_SECURITY" "$@"
69
+ `;
70
+ }
71
+ /** Create or refresh the managed directory containing the `security` shim. */
72
+ function ensureDarwinKeychainShimDir(options: DarwinKeychainBoundaryOptions = {}): string {
73
+ const shimDir = options.shimBaseDir || path.join(os.homedir(), SHIM_DIR_RELATIVE_PATH);
74
+ const script = buildSecurityShimScript(options.realSecurityPath || REAL_SECURITY_PATH);
75
+ const shimPath = path.join(shimDir, 'security');
76
+ fs.mkdirSync(shimDir, { recursive: true });
77
+ let existing: string | null = null;
78
+ try {
79
+ existing = fs.readFileSync(shimPath, 'utf8');
80
+ } catch {
81
+ // Missing or unreadable: (re)write below.
82
+ }
83
+ if (existing !== script) {
84
+ const tempPath = path.join(shimDir, `.security.${process.pid}.${randomUUID()}.tmp`);
85
+ try {
86
+ fs.writeFileSync(tempPath, script, { mode: 0o755, flag: 'wx' });
87
+ // The creation mode is subject to umask. Set the final mode before the
88
+ // rename so the live path is never observable as non-executable.
89
+ fs.chmodSync(tempPath, 0o755);
90
+ fs.renameSync(tempPath, shimPath);
91
+ } catch (error: unknown) {
92
+ try {
93
+ // Remove any unpublished partial file without masking the publication
94
+ // failure that caused this cleanup path.
95
+ fs.rmSync(tempPath, { force: true });
96
+ } catch (cleanupError: unknown) {
97
+ if (error instanceof Error) {
98
+ error.message += ` Cleanup also failed: ${errorMessage(cleanupError)}.`;
99
+ }
100
+ }
101
+ throw error;
102
+ }
103
+ } else {
104
+ // An existing matching shim may have drifted permissions.
105
+ fs.chmodSync(shimPath, 0o755);
106
+ }
107
+ return shimDir;
108
+ }
109
+ /** Prepend the Keychain boundary shim to a worker spawn environment's PATH. */
110
+ function applyDarwinKeychainBoundaryToEnv(
111
+ env: NodeJS.ProcessEnv,
112
+ options: DarwinKeychainBoundaryOptions = {}
113
+ ): NodeJS.ProcessEnv {
114
+ const platform = options.platform || process.platform;
115
+ if (platform !== 'darwin') {
116
+ return env;
117
+ }
118
+ if (env[OPT_OUT_ENV_VAR] === '1' || process.env[OPT_OUT_ENV_VAR] === '1') {
119
+ return env;
120
+ }
121
+ let shimDir: string;
122
+ try {
123
+ shimDir = ensureDarwinKeychainShimDir(options);
124
+ } catch (error: unknown) {
125
+ throw new Error(
126
+ `Failed to install the darwin Keychain boundary shim: ${errorMessage(error)}. ` +
127
+ `Non-interactive workers must not reach the interactive Keychain session; ` +
128
+ `use Docker isolation or set ${OPT_OUT_ENV_VAR}=1 to opt out.`
129
+ );
130
+ }
131
+ // Darwin environment keys are case-sensitive: descendants consult PATH,
132
+ // never a differently-cased key such as Path. Preserve empty components
133
+ // because POSIX interprets them as the current directory. An absent PATH
134
+ // retains Node/libuv's default Unix search path after the shim, while an
135
+ // explicitly empty PATH retains its empty component (`<shim>:`).
136
+ const existingEntries =
137
+ env.PATH === undefined
138
+ ? ['/usr/bin', '/bin']
139
+ : String(env.PATH)
140
+ .split(path.delimiter)
141
+ .filter((entry) => entry !== shimDir);
142
+ env.PATH = [shimDir, ...existingEntries].join(path.delimiter);
143
+ return env;
144
+ }
145
+ export = {
146
+ applyDarwinKeychainBoundaryToEnv,
147
+ ensureDarwinKeychainShimDir,
148
+ };
@@ -1,10 +1,9 @@
1
+ "use strict";
1
2
  const USER_GUIDANCE_CLUSTER = 'USER_GUIDANCE_CLUSTER';
2
3
  const USER_GUIDANCE_AGENT = 'USER_GUIDANCE_AGENT';
3
-
4
4
  const GUIDANCE_TOPICS = [USER_GUIDANCE_CLUSTER, USER_GUIDANCE_AGENT];
5
-
6
5
  module.exports = {
7
- USER_GUIDANCE_CLUSTER,
8
- USER_GUIDANCE_AGENT,
9
- GUIDANCE_TOPICS,
6
+ USER_GUIDANCE_CLUSTER,
7
+ USER_GUIDANCE_AGENT,
8
+ GUIDANCE_TOPICS,
10
9
  };
@@ -0,0 +1,10 @@
1
+ const USER_GUIDANCE_CLUSTER = 'USER_GUIDANCE_CLUSTER';
2
+ const USER_GUIDANCE_AGENT = 'USER_GUIDANCE_AGENT';
3
+
4
+ const GUIDANCE_TOPICS = [USER_GUIDANCE_CLUSTER, USER_GUIDANCE_AGENT] as const;
5
+
6
+ export = {
7
+ USER_GUIDANCE_CLUSTER,
8
+ USER_GUIDANCE_AGENT,
9
+ GUIDANCE_TOPICS,
10
+ };
@@ -1,3 +1,6 @@
1
+ "use strict";
2
+ const fs = require("fs");
3
+ const path = require("path");
1
4
  /**
2
5
  * Input Helpers - Create input data from text or files
3
6
  *
@@ -5,61 +8,37 @@
5
8
  * - Plain text input
6
9
  * - File input (markdown)
7
10
  */
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
11
  class InputHelpers {
13
- /**
14
- * Create a plain text input wrapper
15
- * @param {String} text - Plain text input
16
- * @returns {Object} Structured context
17
- */
18
- static createTextInput(text) {
19
- return {
20
- number: null,
21
- title: 'Manual Input',
22
- body: text,
23
- labels: [],
24
- comments: [],
25
- url: null,
26
- context: `# Manual Input\n\n${text}\n`,
27
- };
28
- }
29
-
30
- /**
31
- * Create input from markdown file
32
- * @param {String} filePath - Path to markdown file (.md or .markdown)
33
- * @returns {Object} Structured context matching issue format
34
- */
35
- static createFileInput(filePath) {
36
- // Resolve relative paths
37
- const resolvedPath = path.resolve(filePath);
38
-
39
- // Validate file exists
40
- if (!fs.existsSync(resolvedPath)) {
41
- throw new Error(`File not found: ${filePath}`);
12
+ static createTextInput(text) {
13
+ return {
14
+ number: null,
15
+ title: 'Manual Input',
16
+ body: text,
17
+ labels: [],
18
+ comments: [],
19
+ url: null,
20
+ context: `# Manual Input\n\n${text}\n`,
21
+ };
22
+ }
23
+ static createFileInput(filePath) {
24
+ const resolvedPath = path.resolve(filePath);
25
+ if (!fs.existsSync(resolvedPath)) {
26
+ throw new Error(`File not found: ${filePath}`);
27
+ }
28
+ const fileContent = fs.readFileSync(resolvedPath, 'utf8');
29
+ const headerMatch = /^#\s+(.+)$/m.exec(fileContent);
30
+ const extractedTitle = headerMatch?.[1]?.trim() ?? null;
31
+ const fallbackTitle = path.basename(filePath, path.extname(filePath));
32
+ const title = extractedTitle || fallbackTitle;
33
+ return {
34
+ number: null,
35
+ title,
36
+ body: fileContent,
37
+ labels: [],
38
+ comments: [],
39
+ url: null,
40
+ context: `# ${title}\n\n${fileContent}\n`,
41
+ };
42
42
  }
43
-
44
- // Read file content
45
- const fileContent = fs.readFileSync(resolvedPath, 'utf8');
46
-
47
- // Extract title from first header or use filename
48
- const headerMatch = fileContent.match(/^#\s+(.+)$/m);
49
- const extractedTitle = headerMatch ? headerMatch[1].trim() : null;
50
- const fallbackTitle = path.basename(filePath, path.extname(filePath));
51
- const title = extractedTitle || fallbackTitle;
52
-
53
- return {
54
- number: null,
55
- title,
56
- body: fileContent,
57
- labels: [],
58
- comments: [],
59
- url: null,
60
- context: `# ${title}\n\n${fileContent}\n`,
61
- };
62
- }
63
43
  }
64
-
65
44
  module.exports = InputHelpers;
@@ -0,0 +1,58 @@
1
+ import fs = require('fs');
2
+ import path = require('path');
3
+
4
+ interface ManualInput {
5
+ number: null;
6
+ title: string;
7
+ body: string;
8
+ labels: unknown[];
9
+ comments: unknown[];
10
+ url: null;
11
+ context: string;
12
+ }
13
+
14
+ /**
15
+ * Input Helpers - Create input data from text or files
16
+ *
17
+ * Provides fallback input methods for non-issue-based input:
18
+ * - Plain text input
19
+ * - File input (markdown)
20
+ */
21
+ class InputHelpers {
22
+ static createTextInput(text: string): ManualInput {
23
+ return {
24
+ number: null,
25
+ title: 'Manual Input',
26
+ body: text,
27
+ labels: [],
28
+ comments: [],
29
+ url: null,
30
+ context: `# Manual Input\n\n${text}\n`,
31
+ };
32
+ }
33
+
34
+ static createFileInput(filePath: string): ManualInput {
35
+ const resolvedPath = path.resolve(filePath);
36
+ if (!fs.existsSync(resolvedPath)) {
37
+ throw new Error(`File not found: ${filePath}`);
38
+ }
39
+
40
+ const fileContent = fs.readFileSync(resolvedPath, 'utf8');
41
+ const headerMatch = /^#\s+(.+)$/m.exec(fileContent);
42
+ const extractedTitle = headerMatch?.[1]?.trim() ?? null;
43
+ const fallbackTitle = path.basename(filePath, path.extname(filePath));
44
+ const title = extractedTitle || fallbackTitle;
45
+
46
+ return {
47
+ number: null,
48
+ title,
49
+ body: fileContent,
50
+ labels: [],
51
+ comments: [],
52
+ url: null,
53
+ context: `# ${title}\n\n${fileContent}\n`,
54
+ };
55
+ }
56
+ }
57
+
58
+ export = InputHelpers;