@the-open-engine/zeroshot 6.38.1 → 6.39.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 (377) hide show
  1. package/cli/event-copy.js +8 -7
  2. package/cli/event-copy.ts +12 -0
  3. package/cli/index.js +7 -31
  4. package/cli/json-export.js +61 -64
  5. package/cli/json-export.ts +112 -0
  6. package/cli/message-formatter-utils.js +68 -56
  7. package/cli/message-formatter-utils.ts +121 -0
  8. package/cli/message-formatters-normal.js +124 -259
  9. package/cli/message-formatters-normal.ts +250 -0
  10. package/cli/message-formatters-watch.js +81 -84
  11. package/cli/message-formatters-watch.ts +189 -0
  12. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  13. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  14. package/lib/cluster/generated/protocol.d.cts +8 -0
  15. package/lib/cluster/generated/protocol.d.mts +8 -0
  16. package/lib/cluster/generated/protocol.d.ts +8 -0
  17. package/lib/clusters-registry.d.ts +23 -0
  18. package/lib/clusters-registry.js +17 -29
  19. package/lib/completion.d.ts +12 -0
  20. package/lib/completion.js +84 -94
  21. package/lib/compose-utils.d.ts +32 -0
  22. package/lib/compose-utils.js +57 -72
  23. package/lib/detached-startup.d.ts +83 -0
  24. package/lib/detached-startup.js +231 -302
  25. package/lib/docker-config.d.ts +43 -0
  26. package/lib/docker-config.js +150 -325
  27. package/lib/docker-env-auth.d.ts +17 -0
  28. package/lib/docker-env-auth.js +75 -0
  29. package/lib/git-remote-utils.d.ts +48 -0
  30. package/lib/git-remote-utils.js +147 -213
  31. package/lib/id-detector.d.ts +15 -0
  32. package/lib/id-detector.js +37 -41
  33. package/lib/path-check.d.ts +30 -0
  34. package/lib/path-check.js +42 -45
  35. package/lib/process-liveness.d.ts +16 -0
  36. package/lib/process-liveness.js +19 -12
  37. package/lib/provider-credential-path.d.ts +16 -0
  38. package/lib/provider-credential-path.js +31 -29
  39. package/lib/provider-defaults.d.ts +30 -0
  40. package/lib/provider-defaults.js +47 -42
  41. package/lib/provider-detection.d.ts +11 -0
  42. package/lib/provider-detection.js +91 -54
  43. package/lib/provider-names.d.ts +38 -0
  44. package/lib/provider-names.js +56 -64
  45. package/lib/repo-settings.d.ts +28 -0
  46. package/lib/repo-settings.js +83 -59
  47. package/lib/run-mode.d.ts +21 -0
  48. package/lib/run-mode.js +21 -20
  49. package/lib/run-plan.d.ts +28 -0
  50. package/lib/run-plan.js +17 -16
  51. package/lib/settings/claude-auth.d.ts +35 -0
  52. package/lib/settings/claude-auth.js +30 -47
  53. package/lib/settings-defaults.d.ts +20 -0
  54. package/lib/settings-defaults.js +149 -0
  55. package/lib/settings-error.d.ts +7 -0
  56. package/lib/settings-error.js +8 -0
  57. package/lib/settings-issue-providers.d.ts +10 -0
  58. package/lib/settings-issue-providers.js +12 -0
  59. package/lib/settings-models.d.ts +22 -0
  60. package/lib/settings-models.js +93 -0
  61. package/lib/settings-storage.d.ts +23 -0
  62. package/lib/settings-storage.js +205 -0
  63. package/lib/settings-validation.d.ts +7 -0
  64. package/lib/settings-validation.js +182 -0
  65. package/lib/settings.d.ts +29 -0
  66. package/lib/settings.js +41 -736
  67. package/lib/setup-apply-types.d.ts +66 -0
  68. package/lib/setup-apply-types.js +2 -0
  69. package/lib/setup-apply.d.ts +39 -0
  70. package/lib/setup-apply.js +267 -264
  71. package/lib/setup-journal.d.ts +41 -0
  72. package/lib/setup-journal.js +119 -76
  73. package/lib/setup-plan-types.d.ts +102 -0
  74. package/lib/setup-plan-types.js +2 -0
  75. package/lib/setup-plan.d.ts +30 -0
  76. package/lib/setup-plan.js +300 -324
  77. package/lib/setup-undo.d.ts +44 -0
  78. package/lib/setup-undo.js +61 -74
  79. package/lib/start-cluster-config.d.ts +26 -0
  80. package/lib/start-cluster-config.js +56 -0
  81. package/lib/start-cluster-environment.d.ts +40 -0
  82. package/lib/start-cluster-environment.js +134 -0
  83. package/lib/start-cluster-run-options.d.ts +53 -0
  84. package/lib/start-cluster-run-options.js +147 -0
  85. package/lib/start-cluster.d.ts +64 -0
  86. package/lib/start-cluster.js +98 -454
  87. package/lib/stream-json-parser.d.ts +17 -0
  88. package/lib/stream-json-parser.js +51 -52
  89. package/npm-shrinkwrap.json +2 -2
  90. package/package.json +12 -6
  91. package/scripts/postinstall.js +27 -0
  92. package/scripts/rust-distribution.js +23 -14
  93. package/src/agent/agent-command-proofs-context.js +35 -45
  94. package/src/agent/agent-command-proofs-context.ts +87 -0
  95. package/src/agent/agent-config-settings.js +19 -0
  96. package/src/agent/agent-config-settings.ts +41 -0
  97. package/src/agent/agent-config.js +122 -231
  98. package/src/agent/agent-config.ts +285 -0
  99. package/src/agent/agent-context-builder.js +38 -273
  100. package/src/agent/agent-context-builder.ts +51 -0
  101. package/src/agent/agent-context-environment-sections.js +105 -0
  102. package/src/agent/agent-context-environment-sections.ts +134 -0
  103. package/src/agent/agent-context-packs.js +165 -0
  104. package/src/agent/agent-context-packs.ts +296 -0
  105. package/src/agent/agent-context-prompt-sections.js +100 -0
  106. package/src/agent/agent-context-prompt-sections.ts +148 -0
  107. package/src/agent/agent-context-sections.js +25 -334
  108. package/src/agent/agent-context-sections.ts +36 -0
  109. package/src/agent/agent-context-sources.js +96 -149
  110. package/src/agent/agent-context-sources.ts +253 -0
  111. package/src/agent/agent-context-types.js +2 -0
  112. package/src/agent/agent-context-types.ts +132 -0
  113. package/src/agent/agent-context-validation-sections.js +73 -0
  114. package/src/agent/agent-context-validation-sections.ts +129 -0
  115. package/src/agent/agent-input-injector.js +99 -118
  116. package/src/agent/agent-input-injector.ts +195 -0
  117. package/src/agent/agent-liveness-poll.js +74 -78
  118. package/src/agent/agent-liveness-poll.ts +163 -0
  119. package/src/agent/agent-quality-gate-schema.js +77 -86
  120. package/src/agent/agent-quality-gate-schema.ts +135 -0
  121. package/src/agent/agent-quality-gates-context.js +44 -50
  122. package/src/agent/agent-quality-gates-context.ts +91 -0
  123. package/src/agent/agent-stuck-detector.js +171 -239
  124. package/src/agent/agent-stuck-detector.ts +288 -0
  125. package/src/agent/agent-trigger-evaluator.js +29 -46
  126. package/src/agent/agent-trigger-evaluator.ts +98 -0
  127. package/src/agent/context-metrics.js +110 -141
  128. package/src/agent/context-metrics.ts +261 -0
  129. package/src/agent/context-pack-builder.js +72 -358
  130. package/src/agent/context-pack-builder.ts +105 -0
  131. package/src/agent/context-pack-core.js +70 -0
  132. package/src/agent/context-pack-core.ts +96 -0
  133. package/src/agent/context-pack-selection.js +119 -0
  134. package/src/agent/context-pack-selection.ts +187 -0
  135. package/src/agent/context-pack-truncation.js +139 -0
  136. package/src/agent/context-pack-truncation.ts +208 -0
  137. package/src/agent/context-pack-types.js +2 -0
  138. package/src/agent/context-pack-types.ts +98 -0
  139. package/src/agent/context-replay-policy.js +30 -39
  140. package/src/agent/context-replay-policy.ts +71 -0
  141. package/src/agent/critical-agent-policy.js +6 -10
  142. package/src/agent/critical-agent-policy.ts +20 -0
  143. package/src/agent/guidance-queue.js +74 -87
  144. package/src/agent/guidance-queue.ts +166 -0
  145. package/src/agent/output-extraction-error-detail.js +45 -0
  146. package/src/agent/output-extraction-error-detail.ts +49 -0
  147. package/src/agent/output-extraction-failures.js +125 -0
  148. package/src/agent/output-extraction-failures.ts +149 -0
  149. package/src/agent/output-extraction-json.js +234 -0
  150. package/src/agent/output-extraction-json.ts +235 -0
  151. package/src/agent/output-extraction-pi.js +124 -0
  152. package/src/agent/output-extraction-pi.ts +137 -0
  153. package/src/agent/output-extraction-types.js +2 -0
  154. package/src/agent/output-extraction-types.ts +49 -0
  155. package/src/agent/output-extraction.js +17 -617
  156. package/src/agent/output-extraction.ts +30 -0
  157. package/src/agent/output-reformatter-errors.js +83 -0
  158. package/src/agent/output-reformatter-errors.ts +106 -0
  159. package/src/agent/output-reformatter-types.js +2 -0
  160. package/src/agent/output-reformatter-types.ts +86 -0
  161. package/src/agent/output-reformatter.js +140 -185
  162. package/src/agent/output-reformatter.ts +238 -0
  163. package/src/agent/pi-terminal-lifecycle-types.js +2 -0
  164. package/src/agent/pi-terminal-lifecycle-types.ts +41 -0
  165. package/src/agent/pi-terminal-lifecycle.js +186 -206
  166. package/src/agent/pi-terminal-lifecycle.ts +297 -0
  167. package/src/agent/provider-control-plane.js +22 -21
  168. package/src/agent/provider-control-plane.ts +52 -0
  169. package/src/agent/provider-terminal-failure-types.js +2 -0
  170. package/src/agent/provider-terminal-failure-types.ts +60 -0
  171. package/src/agent/provider-terminal-failure.js +194 -191
  172. package/src/agent/provider-terminal-failure.ts +262 -0
  173. package/src/agent/rate-limit-backoff.js +31 -74
  174. package/src/agent/rate-limit-backoff.ts +71 -0
  175. package/src/agent/schema-utils.js +85 -125
  176. package/src/agent/schema-utils.ts +148 -0
  177. package/src/agent/structured-output-error.js +34 -33
  178. package/src/agent/structured-output-error.ts +105 -0
  179. package/src/agent/validation-platform.js +27 -27
  180. package/src/agent/validation-platform.ts +49 -0
  181. package/src/attach/attach-client.js +232 -405
  182. package/src/attach/attach-client.ts +300 -0
  183. package/src/attach/attach-server-cleanup.js +43 -0
  184. package/src/attach/attach-server-cleanup.ts +39 -0
  185. package/src/attach/attach-server-clients.js +117 -0
  186. package/src/attach/attach-server-clients.ts +122 -0
  187. package/src/attach/attach-server-events.js +38 -0
  188. package/src/attach/attach-server-events.ts +36 -0
  189. package/src/attach/attach-server-pty.js +45 -0
  190. package/src/attach/attach-server-pty.ts +64 -0
  191. package/src/attach/attach-server-runtime.js +73 -0
  192. package/src/attach/attach-server-runtime.ts +62 -0
  193. package/src/attach/attach-server-socket.js +28 -0
  194. package/src/attach/attach-server-socket.ts +23 -0
  195. package/src/attach/attach-server-types.js +2 -0
  196. package/src/attach/attach-server-types.ts +82 -0
  197. package/src/attach/attach-server.js +106 -523
  198. package/src/attach/attach-server.ts +158 -0
  199. package/src/attach/index.js +18 -35
  200. package/src/attach/index.ts +18 -0
  201. package/src/attach/protocol.js +95 -184
  202. package/src/attach/protocol.ts +181 -0
  203. package/src/attach/ring-buffer.js +76 -102
  204. package/src/attach/ring-buffer.ts +109 -0
  205. package/src/attach/send-input.js +64 -75
  206. package/src/attach/send-input.ts +94 -0
  207. package/src/attach/socket-discovery.js +164 -218
  208. package/src/attach/socket-discovery.ts +230 -0
  209. package/src/attach/socket-paths.js +42 -61
  210. package/src/attach/socket-paths.ts +81 -0
  211. package/src/claude-credentials.js +51 -54
  212. package/src/claude-credentials.ts +89 -0
  213. package/src/cluster/generated/protocol-schema.ts +1 -1
  214. package/src/cluster/generated/protocol.ts +2 -1
  215. package/src/command-proofs.js +110 -141
  216. package/src/command-proofs.ts +216 -0
  217. package/src/config-router.js +81 -73
  218. package/src/config-router.ts +131 -0
  219. package/src/copy-worker.js +53 -29
  220. package/src/copy-worker.ts +75 -0
  221. package/src/darwin-keychain-boundary.js +80 -111
  222. package/src/darwin-keychain-boundary.ts +148 -0
  223. package/src/guidance-topics.js +4 -5
  224. package/src/guidance-topics.ts +10 -0
  225. package/src/input-helpers.js +33 -54
  226. package/src/input-helpers.ts +58 -0
  227. package/src/ledger-sequence.js +45 -48
  228. package/src/ledger-sequence.ts +63 -0
  229. package/src/legacy-lib/clusters-registry.ts +40 -0
  230. package/src/legacy-lib/completion.ts +148 -0
  231. package/src/legacy-lib/compose-utils.ts +102 -0
  232. package/src/legacy-lib/detached-startup.ts +449 -0
  233. package/src/legacy-lib/docker-config.ts +282 -0
  234. package/src/legacy-lib/docker-env-auth.ts +116 -0
  235. package/src/legacy-lib/git-remote-utils.ts +244 -0
  236. package/src/legacy-lib/id-detector.ts +57 -0
  237. package/src/legacy-lib/js-yaml.d.ts +3 -0
  238. package/src/legacy-lib/omelette.d.ts +15 -0
  239. package/src/legacy-lib/path-check.ts +89 -0
  240. package/src/legacy-lib/process-liveness.ts +36 -0
  241. package/src/legacy-lib/provider-credential-path.ts +57 -0
  242. package/src/legacy-lib/provider-defaults.ts +114 -0
  243. package/src/legacy-lib/provider-detection.ts +67 -0
  244. package/src/legacy-lib/provider-names.ts +126 -0
  245. package/src/legacy-lib/repo-settings.ts +88 -0
  246. package/src/legacy-lib/run-mode.ts +58 -0
  247. package/src/legacy-lib/run-plan.ts +49 -0
  248. package/src/legacy-lib/settings/claude-auth.ts +80 -0
  249. package/src/legacy-lib/settings-defaults.ts +212 -0
  250. package/src/legacy-lib/settings-error.ts +8 -0
  251. package/src/legacy-lib/settings-issue-providers.ts +18 -0
  252. package/src/legacy-lib/settings-models.ts +124 -0
  253. package/src/legacy-lib/settings-storage.ts +277 -0
  254. package/src/legacy-lib/settings-validation.ts +220 -0
  255. package/src/legacy-lib/settings.ts +87 -0
  256. package/src/legacy-lib/setup-apply-types.ts +70 -0
  257. package/src/legacy-lib/setup-apply.ts +456 -0
  258. package/src/legacy-lib/setup-journal.ts +185 -0
  259. package/src/legacy-lib/setup-plan-types.ts +96 -0
  260. package/src/legacy-lib/setup-plan.ts +500 -0
  261. package/src/legacy-lib/setup-undo.ts +142 -0
  262. package/src/legacy-lib/start-cluster-config.ts +124 -0
  263. package/src/legacy-lib/start-cluster-environment.ts +165 -0
  264. package/src/legacy-lib/start-cluster-run-options.ts +279 -0
  265. package/src/legacy-lib/start-cluster.ts +237 -0
  266. package/src/legacy-lib/stream-json-parser.ts +88 -0
  267. package/src/message-buffer.js +55 -71
  268. package/src/message-buffer.ts +107 -0
  269. package/src/message-bus-bridge.js +92 -133
  270. package/src/message-bus-bridge.ts +149 -0
  271. package/src/name-generator-shared.js +220 -0
  272. package/src/name-generator-shared.ts +231 -0
  273. package/src/name-generator.js +8 -217
  274. package/src/name-generator.ts +27 -0
  275. package/src/omp-blob-root.js +83 -64
  276. package/src/omp-blob-root.ts +116 -0
  277. package/src/omp-config-overlay.js +65 -38
  278. package/src/omp-config-overlay.ts +110 -0
  279. package/src/omp-execution-fingerprint.js +38 -43
  280. package/src/omp-execution-fingerprint.ts +92 -0
  281. package/src/omp-session-limits.js +10 -15
  282. package/src/omp-session-limits.ts +53 -0
  283. package/src/omp-session-partition.js +2 -2
  284. package/src/omp-session-verifier.js +1 -1
  285. package/src/orchestrator.js +19 -4
  286. package/src/providers/anthropic/index.js +3 -1
  287. package/src/providers/anthropic/index.ts +13 -0
  288. package/src/providers/capabilities.js +19 -27
  289. package/src/providers/capabilities.ts +44 -0
  290. package/src/providers/google/index.js +3 -1
  291. package/src/providers/google/index.ts +13 -0
  292. package/src/providers/openai/index.js +3 -1
  293. package/src/providers/openai/index.ts +13 -0
  294. package/src/providers/opencode/index.js +3 -1
  295. package/src/providers/opencode/index.ts +13 -0
  296. package/src/quality-gates.js +67 -127
  297. package/src/quality-gates.ts +149 -0
  298. package/src/repo-settings-access.js +40 -0
  299. package/src/repo-settings-access.ts +64 -0
  300. package/src/schemas/sub-cluster.js +127 -183
  301. package/src/schemas/sub-cluster.ts +238 -0
  302. package/src/state-snapshot-normalization.js +224 -0
  303. package/src/state-snapshot-normalization.ts +222 -0
  304. package/src/state-snapshot.js +192 -359
  305. package/src/state-snapshot.ts +291 -0
  306. package/src/state-snapshotter.js +118 -130
  307. package/src/state-snapshotter.ts +167 -0
  308. package/src/sub-cluster-wrapper.js +4 -13
  309. package/src/task-run-model-args.js +87 -124
  310. package/src/task-run-model-args.ts +204 -0
  311. package/src/task-runner.js +5 -25
  312. package/src/task-runner.ts +28 -0
  313. package/src/task-startup-error.js +73 -58
  314. package/src/task-startup-error.ts +126 -0
  315. package/src/template-validation/consensus-gate-contracts.js +2 -0
  316. package/src/template-validation/consensus-gate-contracts.ts +70 -0
  317. package/src/template-validation/consensus-gate-scenarios.js +76 -0
  318. package/src/template-validation/consensus-gate-scenarios.ts +130 -0
  319. package/src/template-validation/consensus-gate-stage.js +34 -0
  320. package/src/template-validation/consensus-gate-stage.ts +56 -0
  321. package/src/template-validation/random-topology-contracts.js +2 -0
  322. package/src/template-validation/random-topology-contracts.ts +54 -0
  323. package/src/template-validation/random-topology-dispatch.js +25 -0
  324. package/src/template-validation/random-topology-dispatch.ts +33 -0
  325. package/src/template-validation/random-topology-message-loop.js +53 -0
  326. package/src/template-validation/random-topology-message-loop.ts +73 -0
  327. package/src/template-validation/random-topology-operations.js +79 -0
  328. package/src/template-validation/random-topology-operations.ts +101 -0
  329. package/src/template-validation/random-topology-runtime.js +25 -0
  330. package/src/template-validation/random-topology-runtime.ts +43 -0
  331. package/src/template-validation/random-topology-scenario.js +52 -0
  332. package/src/template-validation/random-topology-scenario.ts +57 -0
  333. package/src/template-validation/random-topology-schema.js +159 -0
  334. package/src/template-validation/random-topology-schema.ts +190 -0
  335. package/src/template-validation/random-topology-state.js +28 -0
  336. package/src/template-validation/random-topology-state.ts +30 -0
  337. package/src/template-validation/random-topology-trigger-evaluation.js +45 -0
  338. package/src/template-validation/random-topology-trigger-evaluation.ts +65 -0
  339. package/src/template-validation/random-topology-trigger.js +75 -0
  340. package/src/template-validation/random-topology-trigger.ts +88 -0
  341. package/src/template-validation/report-formatter.js +40 -46
  342. package/src/template-validation/report-formatter.ts +101 -0
  343. package/src/template-validation/simulate-consensus-gates.js +111 -302
  344. package/src/template-validation/simulate-consensus-gates.ts +196 -0
  345. package/src/template-validation/simulate-random-topology.js +26 -519
  346. package/src/template-validation/simulate-random-topology.ts +57 -0
  347. package/src/template-validation/simulate-two-stage-validation.js +41 -265
  348. package/src/template-validation/simulate-two-stage-validation.ts +55 -0
  349. package/src/template-validation/simulation-agent-runtime.js +25 -0
  350. package/src/template-validation/simulation-agent-runtime.ts +40 -0
  351. package/src/template-validation/simulation-agent.js +29 -0
  352. package/src/template-validation/simulation-agent.ts +73 -0
  353. package/src/template-validation/simulation-runtime.js +34 -0
  354. package/src/template-validation/simulation-runtime.ts +72 -0
  355. package/src/template-validation/two-stage-contracts.js +2 -0
  356. package/src/template-validation/two-stage-contracts.ts +41 -0
  357. package/src/template-validation/two-stage-inputs.js +21 -0
  358. package/src/template-validation/two-stage-inputs.ts +29 -0
  359. package/src/template-validation/two-stage-results.js +30 -0
  360. package/src/template-validation/two-stage-results.ts +40 -0
  361. package/src/template-validation/two-stage-scenario.js +86 -0
  362. package/src/template-validation/two-stage-scenario.ts +120 -0
  363. package/src/worktree-claude-config.js +182 -220
  364. package/src/worktree-claude-config.ts +272 -0
  365. package/src/worktree-tooling-env.js +103 -125
  366. package/src/worktree-tooling-env.ts +142 -0
  367. package/task-lib/completion.js +2 -3
  368. package/task-lib/completion.ts +9 -0
  369. package/task-lib/config.js +1 -4
  370. package/task-lib/config.ts +11 -0
  371. package/task-lib/name-generator.js +4 -226
  372. package/task-lib/name-generator.ts +11 -0
  373. package/task-lib/omp-session-cleanup.js +1 -1
  374. package/task-lib/omp-storage-root.js +8 -12
  375. package/task-lib/omp-storage-root.ts +62 -0
  376. package/task-lib/process-termination.js +143 -166
  377. package/task-lib/process-termination.ts +268 -0
@@ -1,438 +1,265 @@
1
- /**
2
- * AttachClient - Terminal client for attaching to running tasks/agents
3
- *
4
- * Key sequences:
5
- * - Ctrl+C: Clean detach (return to shell, task continues running)
6
- * - Ctrl+B d: Also detach (for tmux muscle memory)
7
- * - Ctrl+B ?: Show help
8
- * - Ctrl+B c: Send SIGINT to process (interrupt agent - USE WITH CAUTION)
9
- * - Ctrl+Z: Forward SIGTSTP to process
10
- *
11
- * Features:
12
- * - Raw terminal mode (passes through all input)
13
- * - Output history replay on attach
14
- * - Terminal resize forwarding
15
- * - Graceful cleanup on exit
16
- */
17
-
18
- const net = require('net');
19
- const EventEmitter = require('events');
20
- const crypto = require('crypto');
21
-
22
- const protocol = require('./protocol');
23
-
24
- // Key codes
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ /** Terminal client for attaching to a running task or agent. */
6
+ const node_crypto_1 = __importDefault(require("node:crypto"));
7
+ const node_events_1 = require("node:events");
8
+ const node_net_1 = __importDefault(require("node:net"));
9
+ const protocol_1 = __importDefault(require("./protocol"));
25
10
  const CTRL_B = '\x02';
26
11
  const CTRL_C = '\x03';
27
12
  const CTRL_Z = '\x1a';
28
-
29
- // Detach timeout (ms) - how long to wait for second key after Ctrl+B
30
13
  const DETACH_TIMEOUT = 500;
31
-
32
- class AttachClient extends EventEmitter {
33
- /**
34
- * @param {object} options
35
- * @param {string} options.socketPath - Unix socket path to connect to
36
- * @param {object} [options.stdin] - Input stream (default process.stdin)
37
- * @param {object} [options.stdout] - Output stream (default process.stdout)
38
- */
39
- constructor(options) {
40
- super();
41
-
42
- if (!options.socketPath) {
43
- throw new Error('AttachClient: socketPath is required');
14
+ function readServerMessage(message) {
15
+ if ((typeof message !== 'object' && typeof message !== 'function') || message === null) {
16
+ throw new TypeError(`Cannot read properties of ${message}`);
44
17
  }
45
-
46
- this.socketPath = options.socketPath;
47
- this.stdin = options.stdin || process.stdin;
48
- this.stdout = options.stdout || process.stdout;
49
-
50
- this.clientId = crypto.randomUUID();
51
- this.socket = null;
52
- this.decoder = new protocol.MessageDecoder();
53
- this.connected = false;
54
- this.wasRawMode = null;
55
-
56
- // Ctrl+B sequence detection
57
- this.ctrlBPressed = false;
58
- this.ctrlBTimeout = null;
59
-
60
- // Bind handlers
61
- this._onSocketData = this._onSocketData.bind(this);
62
- this._onSocketClose = this._onSocketClose.bind(this);
63
- this._onSocketError = this._onSocketError.bind(this);
64
- this._onStdinData = this._onStdinData.bind(this);
65
- this._onResize = this._onResize.bind(this);
66
- }
67
-
68
- /**
69
- * Connect to the attach server
70
- * @returns {Promise<void>}
71
- */
72
- connect() {
73
- if (this.connected) {
74
- throw new Error('AttachClient: Already connected');
75
- }
76
-
77
- return new Promise((resolve, reject) => {
78
- this.socket = net.createConnection(this.socketPath);
79
-
80
- this.socket.on('connect', () => {
81
- this.connected = true;
82
-
83
- // Send attach message with terminal dimensions
84
- const cols = this.stdout.columns || 80;
85
- const rows = this.stdout.rows || 24;
86
-
87
- this.socket.write(protocol.encode(protocol.createAttachMessage(this.clientId, cols, rows)));
88
-
89
- // Set up terminal
90
- this._setupTerminal();
91
-
92
- // Set up socket handlers
93
- this.socket.on('data', this._onSocketData);
94
- this.socket.on('close', this._onSocketClose);
95
- this.socket.on('error', this._onSocketError);
96
-
97
- resolve();
98
- });
99
-
100
- this.socket.on('error', (err) => {
101
- if (!this.connected) {
102
- reject(err);
103
- }
104
- });
105
-
106
- // Connection timeout
107
- const timeout = setTimeout(() => {
108
- if (!this.connected) {
109
- this.socket.destroy();
110
- reject(new Error('Connection timeout'));
18
+ return {
19
+ code: Reflect.get(message, 'code'),
20
+ data: Reflect.get(message, 'data'),
21
+ message: Reflect.get(message, 'message'),
22
+ signal: Reflect.get(message, 'signal'),
23
+ type: Reflect.get(message, 'type'),
24
+ };
25
+ }
26
+ function dataMessage(data) {
27
+ if (data === undefined || !data)
28
+ return {};
29
+ if (typeof data === 'string')
30
+ return { data };
31
+ throw new TypeError('Attach protocol data must be a base64 string');
32
+ }
33
+ class AttachClient extends node_events_1.EventEmitter {
34
+ socketPath;
35
+ stdin;
36
+ stdout;
37
+ clientId;
38
+ socket = null;
39
+ decoder = new protocol_1.default.MessageDecoder();
40
+ connected = false;
41
+ wasRawMode = null;
42
+ ctrlBPressed = false;
43
+ ctrlBTimeout = null;
44
+ constructor(options) {
45
+ super();
46
+ if (!options.socketPath) {
47
+ throw new Error('AttachClient: socketPath is required');
111
48
  }
112
- }, 5000);
113
-
114
- this.socket.on('connect', () => clearTimeout(timeout));
115
- });
116
- }
117
-
118
- /**
119
- * Disconnect from the server
120
- */
121
- disconnect() {
122
- if (!this.connected) {
123
- return;
49
+ this.socketPath = options.socketPath;
50
+ this.stdin = options.stdin || process.stdin;
51
+ this.stdout = options.stdout || process.stdout;
52
+ this.clientId = node_crypto_1.default.randomUUID();
53
+ this._onSocketData = this._onSocketData.bind(this);
54
+ this._onSocketClose = this._onSocketClose.bind(this);
55
+ this._onSocketError = this._onSocketError.bind(this);
56
+ this._onStdinData = this._onStdinData.bind(this);
57
+ this._onResize = this._onResize.bind(this);
124
58
  }
125
-
126
- // Send detach message
127
- try {
128
- this.socket.write(protocol.encode(protocol.createDetachMessage(this.clientId)));
129
- } catch {
130
- // Ignore
131
- }
132
-
133
- this._cleanup();
134
- this.emit('detach');
135
- }
136
-
137
- /**
138
- * Send a signal to the remote process
139
- * @param {string} signal - Signal name
140
- */
141
- sendSignal(signal) {
142
- if (!this.connected) {
143
- return;
144
- }
145
-
146
- try {
147
- this.socket.write(protocol.encode(protocol.createSignalMessage(signal)));
148
- } catch {
149
- // Ignore
150
- }
151
- }
152
-
153
- // ─────────────────────────────────────────────────────────────────
154
- // Private methods
155
- // ─────────────────────────────────────────────────────────────────
156
-
157
- /**
158
- * Set up terminal for raw mode
159
- * @private
160
- */
161
- _setupTerminal() {
162
- // Enable raw mode if stdin is a TTY
163
- if (this.stdin.isTTY && this.stdin.setRawMode) {
164
- this.wasRawMode = this.stdin.isRaw;
165
- this.stdin.setRawMode(true);
59
+ connect() {
60
+ if (this.connected) {
61
+ throw new Error('AttachClient: Already connected');
62
+ }
63
+ return new Promise((resolve, reject) => {
64
+ const socket = node_net_1.default.createConnection(this.socketPath);
65
+ this.socket = socket;
66
+ socket.on('connect', () => {
67
+ this.connected = true;
68
+ const cols = this.stdout.columns || 80;
69
+ const rows = this.stdout.rows || 24;
70
+ socket.write(protocol_1.default.encode(protocol_1.default.createAttachMessage(this.clientId, cols, rows)));
71
+ this._setupTerminal();
72
+ socket.on('data', this._onSocketData);
73
+ socket.on('close', this._onSocketClose);
74
+ socket.on('error', this._onSocketError);
75
+ resolve();
76
+ });
77
+ socket.on('error', (error) => {
78
+ if (!this.connected)
79
+ reject(error);
80
+ });
81
+ const timeout = setTimeout(() => {
82
+ if (!this.connected) {
83
+ socket.destroy();
84
+ reject(new Error('Connection timeout'));
85
+ }
86
+ }, 5000);
87
+ socket.on('connect', () => clearTimeout(timeout));
88
+ });
166
89
  }
167
-
168
- // Resume stdin (may be paused)
169
- this.stdin.resume();
170
-
171
- // Listen for input
172
- this.stdin.on('data', this._onStdinData);
173
-
174
- // Listen for resize events
175
- if (this.stdout.isTTY) {
176
- this.stdout.on('resize', this._onResize);
90
+ disconnect() {
91
+ if (!this.connected)
92
+ return;
93
+ try {
94
+ this.socket?.write(protocol_1.default.encode(protocol_1.default.createDetachMessage(this.clientId)));
95
+ }
96
+ catch {
97
+ // Ignore transport failures during detach.
98
+ }
99
+ this._cleanup();
100
+ this.emit('detach');
177
101
  }
178
-
179
- // Handle process signals for cleanup
180
- process.on('SIGINT', () => {
181
- // Clean detach on Ctrl+C - task continues running
182
- this.disconnect();
183
- });
184
-
185
- process.on('SIGTERM', () => {
186
- this._cleanup();
187
- process.exit(0);
188
- });
189
- }
190
-
191
- /**
192
- * Restore terminal state
193
- * @private
194
- */
195
- _restoreTerminal() {
196
- // Restore raw mode
197
- if (this.stdin.isTTY && this.stdin.setRawMode && this.wasRawMode !== null) {
198
- this.stdin.setRawMode(this.wasRawMode);
102
+ sendSignal(signal) {
103
+ if (!this.connected)
104
+ return;
105
+ try {
106
+ this.socket?.write(protocol_1.default.encode(protocol_1.default.createSignalMessage(signal)));
107
+ }
108
+ catch {
109
+ // Ignore transport failures while signaling.
110
+ }
199
111
  }
200
-
201
- // Remove listeners
202
- this.stdin.removeListener('data', this._onStdinData);
203
- if (this.stdout.isTTY) {
204
- this.stdout.removeListener('resize', this._onResize);
112
+ _setupTerminal() {
113
+ if (this.stdin.isTTY && this.stdin.setRawMode) {
114
+ this.wasRawMode = this.stdin.isRaw;
115
+ this.stdin.setRawMode(true);
116
+ }
117
+ this.stdin.resume();
118
+ this.stdin.on('data', this._onStdinData);
119
+ if (this.stdout.isTTY)
120
+ this.stdout.on('resize', this._onResize);
121
+ process.on('SIGINT', () => this.disconnect());
122
+ process.on('SIGTERM', () => {
123
+ this._cleanup();
124
+ process.exit(0);
125
+ });
205
126
  }
206
-
207
- // Pause stdin
208
- this.stdin.pause();
209
- }
210
-
211
- /**
212
- * Handle data from socket
213
- * @private
214
- */
215
- _onSocketData(data) {
216
- try {
217
- const messages = this.decoder.feed(data);
218
- for (const msg of messages) {
219
- this._handleMessage(msg);
220
- }
221
- } catch (e) {
222
- this.emit('error', new Error(`Protocol error: ${e.message}`));
223
- this._cleanup();
127
+ _restoreTerminal() {
128
+ if (this.stdin.isTTY && this.stdin.setRawMode && this.wasRawMode !== null) {
129
+ Reflect.apply(this.stdin.setRawMode, this.stdin, [this.wasRawMode]);
130
+ }
131
+ this.stdin.removeListener('data', this._onStdinData);
132
+ if (this.stdout.isTTY)
133
+ this.stdout.removeListener('resize', this._onResize);
134
+ this.stdin.pause();
224
135
  }
225
- }
226
-
227
- /**
228
- * Handle message from server
229
- * @private
230
- */
231
- _handleMessage(message) {
232
- switch (message.type) {
233
- case protocol.MessageType.OUTPUT: {
234
- const data = protocol.decodeData(message);
235
- if (data) {
236
- this.stdout.write(data);
136
+ _onSocketData(data) {
137
+ try {
138
+ for (const message of this.decoder.feed(data))
139
+ this._handleMessage(message);
237
140
  }
238
- break;
239
- }
240
-
241
- case protocol.MessageType.HISTORY: {
242
- const data = protocol.decodeData(message);
243
- if (data) {
244
- this.stdout.write(data);
141
+ catch (error) {
142
+ const reason = error instanceof Error ? error.message : String(error);
143
+ this.emit('error', new Error(`Protocol error: ${reason}`));
144
+ this._cleanup();
245
145
  }
246
- break;
247
- }
248
-
249
- case protocol.MessageType.STATE: {
250
- this.emit('state', message);
251
- break;
252
- }
253
-
254
- case protocol.MessageType.EXIT: {
255
- const { code, signal } = message;
256
- this.emit('exit', { code, signal });
257
- this._cleanup();
258
- break;
259
- }
260
-
261
- case protocol.MessageType.ERROR: {
262
- this.emit('error', new Error(message.message));
263
- break;
264
- }
265
146
  }
266
- }
267
-
268
- /**
269
- * Handle stdin data
270
- * @private
271
- */
272
- _onStdinData(data) {
273
- const str = data.toString();
274
-
275
- // Handle Ctrl+B sequence
276
- if (this.ctrlBPressed) {
277
- this.ctrlBPressed = false;
278
- if (this.ctrlBTimeout) {
279
- clearTimeout(this.ctrlBTimeout);
280
- this.ctrlBTimeout = null;
281
- }
282
-
283
- // Check for command keys
284
- if (str === 'd' || str === 'D') {
285
- // Detach
286
- this.disconnect();
287
- return;
288
- }
289
-
290
- if (str === 'c' || str === 'C') {
291
- // Send SIGINT to process (interrupt agent - USE WITH CAUTION)
292
- this.stdout.write('\r\n⚠️ Sending SIGINT to agent (interrupting task)...\r\n');
293
- this.sendSignal('SIGINT');
294
- return;
295
- }
296
-
297
- if (str === '?') {
298
- // Show help
299
- this._showHelp();
300
- return;
301
- }
302
-
303
- // Not a recognized command, forward Ctrl+B + this key
304
- this._forwardInput(Buffer.from([0x02]));
305
- this._forwardInput(data);
306
- return;
147
+ _handleMessage(message) {
148
+ const serverMessage = readServerMessage(message);
149
+ switch (serverMessage.type) {
150
+ case protocol_1.default.MessageType.OUTPUT:
151
+ case protocol_1.default.MessageType.HISTORY: {
152
+ const data = protocol_1.default.decodeData(dataMessage(serverMessage.data));
153
+ if (data)
154
+ this.stdout.write(data);
155
+ break;
156
+ }
157
+ case protocol_1.default.MessageType.STATE:
158
+ this.emit('state', message);
159
+ break;
160
+ case protocol_1.default.MessageType.EXIT: {
161
+ const { code, signal } = serverMessage;
162
+ this.emit('exit', { code, signal });
163
+ this._cleanup();
164
+ break;
165
+ }
166
+ case protocol_1.default.MessageType.ERROR:
167
+ this.emit('error', new Error(serverMessage.message === undefined ? undefined : String(serverMessage.message)));
168
+ break;
169
+ }
307
170
  }
308
-
309
- // Check for Ctrl+B
310
- if (str === CTRL_B) {
311
- this.ctrlBPressed = true;
312
-
313
- // Set timeout to forward if no follow-up key
314
- this.ctrlBTimeout = setTimeout(() => {
171
+ _onStdinData(data) {
172
+ const input = data.toString();
315
173
  if (this.ctrlBPressed) {
316
- this.ctrlBPressed = false;
317
- this._forwardInput(data);
174
+ this.ctrlBPressed = false;
175
+ if (this.ctrlBTimeout) {
176
+ clearTimeout(this.ctrlBTimeout);
177
+ this.ctrlBTimeout = null;
178
+ }
179
+ if (input === 'd' || input === 'D')
180
+ return this.disconnect();
181
+ if (input === 'c' || input === 'C') {
182
+ this.stdout.write('\r\n⚠️ Sending SIGINT to agent (interrupting task)...\r\n');
183
+ return this.sendSignal('SIGINT');
184
+ }
185
+ if (input === '?')
186
+ return this._showHelp();
187
+ this._forwardInput(Buffer.from([0x02]));
188
+ this._forwardInput(data);
189
+ return;
318
190
  }
319
- }, DETACH_TIMEOUT);
320
- return;
321
- }
322
-
323
- // Check for Ctrl+C - clean detach (task continues running)
324
- if (str === CTRL_C) {
325
- this.disconnect();
326
- return;
327
- }
328
-
329
- // Check for Ctrl+Z
330
- if (str === CTRL_Z) {
331
- this.sendSignal('SIGTSTP');
332
- return;
333
- }
334
-
335
- // Forward other input (future interactive mode)
336
- this._forwardInput(data);
337
- }
338
-
339
- /**
340
- * Forward input to remote process
341
- * @private
342
- */
343
- _forwardInput(data) {
344
- if (!this.connected) {
345
- return;
191
+ if (input === CTRL_B) {
192
+ this.ctrlBPressed = true;
193
+ this.ctrlBTimeout = setTimeout(() => {
194
+ if (this.ctrlBPressed) {
195
+ this.ctrlBPressed = false;
196
+ this._forwardInput(data);
197
+ }
198
+ }, DETACH_TIMEOUT);
199
+ return;
200
+ }
201
+ if (input === CTRL_C)
202
+ return this.disconnect();
203
+ if (input === CTRL_Z)
204
+ return this.sendSignal('SIGTSTP');
205
+ this._forwardInput(data);
346
206
  }
347
-
348
- try {
349
- this.socket.write(protocol.encode(protocol.createStdinMessage(data)));
350
- } catch {
351
- // Ignore
207
+ _forwardInput(data) {
208
+ if (!this.connected)
209
+ return;
210
+ try {
211
+ this.socket?.write(protocol_1.default.encode(protocol_1.default.createStdinMessage(data)));
212
+ }
213
+ catch {
214
+ // Ignore transport failures while forwarding terminal input.
215
+ }
352
216
  }
353
- }
354
-
355
- /**
356
- * Handle terminal resize
357
- * @private
358
- */
359
- _onResize() {
360
- if (!this.connected) {
361
- return;
217
+ _onResize() {
218
+ if (!this.connected)
219
+ return;
220
+ try {
221
+ this.socket?.write(protocol_1.default.encode(protocol_1.default.createResizeMessage(this.stdout.columns, this.stdout.rows)));
222
+ }
223
+ catch {
224
+ // Ignore transport failures while forwarding terminal size.
225
+ }
362
226
  }
363
-
364
- const cols = this.stdout.columns;
365
- const rows = this.stdout.rows;
366
-
367
- try {
368
- this.socket.write(protocol.encode(protocol.createResizeMessage(cols, rows)));
369
- } catch {
370
- // Ignore
227
+ _onSocketClose() {
228
+ if (this.connected) {
229
+ this.emit('close');
230
+ this._cleanup();
231
+ }
371
232
  }
372
- }
373
-
374
- /**
375
- * Handle socket close
376
- * @private
377
- */
378
- _onSocketClose() {
379
- if (this.connected) {
380
- this.emit('close');
381
- this._cleanup();
233
+ _onSocketError(error) {
234
+ this.emit('error', error);
235
+ this._cleanup();
382
236
  }
383
- }
384
-
385
- /**
386
- * Handle socket error
387
- * @private
388
- */
389
- _onSocketError(err) {
390
- this.emit('error', err);
391
- this._cleanup();
392
- }
393
-
394
- /**
395
- * Show help message
396
- * @private
397
- */
398
- _showHelp() {
399
- const help = `
400
- \r\n╭──────────────────────────────────────────────────────────╮
237
+ _showHelp() {
238
+ const horizontal = '─'.repeat(58);
239
+ this.stdout.write(`
240
+ \r\n╭${horizontal}╮
401
241
  \r\n│ Vibe Attach - Key Bindings │
402
- \r\n├──────────────────────────────────────────────────────────┤
242
+ \r\n├${horizontal}┤
403
243
  \r\n│ Ctrl+C Detach (task continues running) │
404
244
  \r\n│ Ctrl+B d Also detach (for tmux muscle memory) │
405
245
  \r\n│ Ctrl+B ? Show this help │
406
246
  \r\n│ Ctrl+B c ⚠️ Interrupt agent (sends SIGINT) │
407
247
  \r\n│ Ctrl+Z Suspend process (sends SIGTSTP) │
408
- \r\n╰──────────────────────────────────────────────────────────╯
409
- \r\n`;
410
- this.stdout.write(help);
411
- }
412
-
413
- /**
414
- * Clean up resources
415
- * @private
416
- */
417
- _cleanup() {
418
- this.connected = false;
419
-
420
- // Clear Ctrl+B timeout
421
- if (this.ctrlBTimeout) {
422
- clearTimeout(this.ctrlBTimeout);
423
- this.ctrlBTimeout = null;
248
+ \r\n╰${horizontal}╯
249
+ \r\n`);
424
250
  }
425
-
426
- // Restore terminal
427
- this._restoreTerminal();
428
-
429
- // Close socket
430
- if (this.socket) {
431
- this.socket.removeAllListeners();
432
- this.socket.destroy();
433
- this.socket = null;
251
+ _cleanup() {
252
+ this.connected = false;
253
+ if (this.ctrlBTimeout) {
254
+ clearTimeout(this.ctrlBTimeout);
255
+ this.ctrlBTimeout = null;
256
+ }
257
+ this._restoreTerminal();
258
+ if (this.socket) {
259
+ this.socket.removeAllListeners();
260
+ this.socket.destroy();
261
+ this.socket = null;
262
+ }
434
263
  }
435
- }
436
264
  }
437
-
438
265
  module.exports = AttachClient;