@decibelsystems/tools 2.2.0-beta.0 → 3.1.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 (435) hide show
  1. package/CHANGELOG.md +226 -0
  2. package/dist/agentCommands.d.ts +0 -1
  3. package/dist/agentCommands.d.ts.map +1 -1
  4. package/dist/agentCommands.js +19 -8
  5. package/dist/agentCommands.js.map +1 -1
  6. package/dist/agentPresence.d.ts +82 -0
  7. package/dist/agentPresence.d.ts.map +1 -1
  8. package/dist/agentPresence.js +194 -26
  9. package/dist/agentPresence.js.map +1 -1
  10. package/dist/agentic/index.d.ts +18 -8
  11. package/dist/agentic/index.d.ts.map +1 -1
  12. package/dist/agentic/index.js +18 -144
  13. package/dist/agentic/index.js.map +1 -1
  14. package/dist/agentic/types.d.ts +106 -0
  15. package/dist/agentic/types.d.ts.map +1 -1
  16. package/dist/agentic/types.js +77 -1
  17. package/dist/agentic/types.js.map +1 -1
  18. package/dist/architectAdrs.d.ts +27 -3
  19. package/dist/architectAdrs.d.ts.map +1 -1
  20. package/dist/architectAdrs.js +92 -4
  21. package/dist/architectAdrs.js.map +1 -1
  22. package/dist/artifacts.d.ts +60 -0
  23. package/dist/artifacts.d.ts.map +1 -0
  24. package/dist/artifacts.js +208 -0
  25. package/dist/artifacts.js.map +1 -0
  26. package/dist/asks.d.ts +93 -0
  27. package/dist/asks.d.ts.map +1 -0
  28. package/dist/asks.js +383 -0
  29. package/dist/asks.js.map +1 -0
  30. package/dist/chat.d.ts +47 -0
  31. package/dist/chat.d.ts.map +1 -0
  32. package/dist/chat.js +288 -0
  33. package/dist/chat.js.map +1 -0
  34. package/dist/client/transports.d.ts.map +1 -1
  35. package/dist/client/transports.js +13 -3
  36. package/dist/client/transports.js.map +1 -1
  37. package/dist/daemon.d.ts +33 -3
  38. package/dist/daemon.d.ts.map +1 -1
  39. package/dist/daemon.js +225 -52
  40. package/dist/daemon.js.map +1 -1
  41. package/dist/daemonConfig.d.ts +46 -0
  42. package/dist/daemonConfig.d.ts.map +1 -1
  43. package/dist/daemonConfig.js +57 -12
  44. package/dist/daemonConfig.js.map +1 -1
  45. package/dist/decibelPaths.d.ts.map +1 -1
  46. package/dist/decibelPaths.js +39 -6
  47. package/dist/decibelPaths.js.map +1 -1
  48. package/dist/domain/issue.d.ts +81 -0
  49. package/dist/domain/issue.d.ts.map +1 -0
  50. package/dist/domain/issue.js +106 -0
  51. package/dist/domain/issue.js.map +1 -0
  52. package/dist/domain/issueCodec.d.ts +39 -0
  53. package/dist/domain/issueCodec.d.ts.map +1 -0
  54. package/dist/domain/issueCodec.js +308 -0
  55. package/dist/domain/issueCodec.js.map +1 -0
  56. package/dist/domain/issueRepository.d.ts +124 -0
  57. package/dist/domain/issueRepository.d.ts.map +1 -0
  58. package/dist/domain/issueRepository.js +296 -0
  59. package/dist/domain/issueRepository.js.map +1 -0
  60. package/dist/domain/uid.d.ts +16 -0
  61. package/dist/domain/uid.d.ts.map +1 -0
  62. package/dist/domain/uid.js +43 -0
  63. package/dist/domain/uid.js.map +1 -0
  64. package/dist/facades/definitions.d.ts +0 -1
  65. package/dist/facades/definitions.d.ts.map +1 -1
  66. package/dist/facades/definitions.js +140 -116
  67. package/dist/facades/definitions.js.map +1 -1
  68. package/dist/facades/index.d.ts +2 -1
  69. package/dist/facades/index.d.ts.map +1 -1
  70. package/dist/facades/index.js +1 -1
  71. package/dist/facades/index.js.map +1 -1
  72. package/dist/facades/types.d.ts +17 -0
  73. package/dist/facades/types.d.ts.map +1 -1
  74. package/dist/hq/defineAgent.d.ts.map +1 -1
  75. package/dist/hq/defineAgent.js +7 -11
  76. package/dist/hq/defineAgent.js.map +1 -1
  77. package/dist/httpArgs.d.ts +11 -0
  78. package/dist/httpArgs.d.ts.map +1 -0
  79. package/dist/httpArgs.js +39 -0
  80. package/dist/httpArgs.js.map +1 -0
  81. package/dist/httpServer.d.ts +1 -12
  82. package/dist/httpServer.d.ts.map +1 -1
  83. package/dist/httpServer.js +298 -144
  84. package/dist/httpServer.js.map +1 -1
  85. package/dist/identity.d.ts +123 -0
  86. package/dist/identity.d.ts.map +1 -0
  87. package/dist/identity.js +312 -0
  88. package/dist/identity.js.map +1 -0
  89. package/dist/kernel.d.ts +46 -1
  90. package/dist/kernel.d.ts.map +1 -1
  91. package/dist/kernel.js +334 -26
  92. package/dist/kernel.js.map +1 -1
  93. package/dist/killSwitch.d.ts +117 -0
  94. package/dist/killSwitch.d.ts.map +1 -0
  95. package/dist/killSwitch.js +161 -0
  96. package/dist/killSwitch.js.map +1 -0
  97. package/dist/lib/agent-services/assumptions.d.ts.map +1 -1
  98. package/dist/lib/agent-services/assumptions.js +8 -2
  99. package/dist/lib/agent-services/assumptions.js.map +1 -1
  100. package/dist/lib/atomicWrite.d.ts +49 -0
  101. package/dist/lib/atomicWrite.d.ts.map +1 -0
  102. package/dist/lib/atomicWrite.js +157 -0
  103. package/dist/lib/atomicWrite.js.map +1 -0
  104. package/dist/lib/envelope.d.ts +31 -0
  105. package/dist/lib/envelope.d.ts.map +1 -0
  106. package/dist/lib/envelope.js +80 -0
  107. package/dist/lib/envelope.js.map +1 -0
  108. package/dist/lib/fileLock.d.ts +38 -0
  109. package/dist/lib/fileLock.d.ts.map +1 -0
  110. package/dist/lib/fileLock.js +124 -0
  111. package/dist/lib/fileLock.js.map +1 -0
  112. package/dist/lib/recordIdAllocator.d.ts +102 -0
  113. package/dist/lib/recordIdAllocator.d.ts.map +1 -0
  114. package/dist/lib/recordIdAllocator.js +179 -0
  115. package/dist/lib/recordIdAllocator.js.map +1 -0
  116. package/dist/orgId.d.ts +23 -0
  117. package/dist/orgId.d.ts.map +1 -0
  118. package/dist/orgId.js +73 -0
  119. package/dist/orgId.js.map +1 -0
  120. package/dist/pairCli.d.ts +2 -0
  121. package/dist/pairCli.d.ts.map +1 -0
  122. package/dist/pairCli.js +97 -0
  123. package/dist/pairCli.js.map +1 -0
  124. package/dist/peerBroker.d.ts +40 -0
  125. package/dist/peerBroker.d.ts.map +1 -0
  126. package/dist/peerBroker.js +70 -0
  127. package/dist/peerBroker.js.map +1 -0
  128. package/dist/peerBrokerSupervisor.d.ts +21 -0
  129. package/dist/peerBrokerSupervisor.d.ts.map +1 -0
  130. package/dist/peerBrokerSupervisor.js +131 -0
  131. package/dist/peerBrokerSupervisor.js.map +1 -0
  132. package/dist/projectPaths.d.ts.map +1 -1
  133. package/dist/projectPaths.js +1 -19
  134. package/dist/projectPaths.js.map +1 -1
  135. package/dist/projectRegistry.d.ts +22 -0
  136. package/dist/projectRegistry.d.ts.map +1 -1
  137. package/dist/projectRegistry.js +69 -2
  138. package/dist/projectRegistry.js.map +1 -1
  139. package/dist/pty/boundary.d.ts +39 -0
  140. package/dist/pty/boundary.d.ts.map +1 -0
  141. package/dist/pty/boundary.js +100 -0
  142. package/dist/pty/boundary.js.map +1 -0
  143. package/dist/pty/errors.d.ts +6 -0
  144. package/dist/pty/errors.d.ts.map +1 -0
  145. package/dist/pty/errors.js +12 -0
  146. package/dist/pty/errors.js.map +1 -0
  147. package/dist/pty/fleet.d.ts +159 -0
  148. package/dist/pty/fleet.d.ts.map +1 -0
  149. package/dist/pty/fleet.js +543 -0
  150. package/dist/pty/fleet.js.map +1 -0
  151. package/dist/pty/launchProfile.d.ts +45 -0
  152. package/dist/pty/launchProfile.d.ts.map +1 -0
  153. package/dist/pty/launchProfile.js +149 -0
  154. package/dist/pty/launchProfile.js.map +1 -0
  155. package/dist/pty/openTerminal.d.ts +48 -0
  156. package/dist/pty/openTerminal.d.ts.map +1 -0
  157. package/dist/pty/openTerminal.js +185 -0
  158. package/dist/pty/openTerminal.js.map +1 -0
  159. package/dist/pty/pairDialog.d.ts +16 -0
  160. package/dist/pty/pairDialog.d.ts.map +1 -0
  161. package/dist/pty/pairDialog.js +121 -0
  162. package/dist/pty/pairDialog.js.map +1 -0
  163. package/dist/pty/pairing.d.ts +86 -0
  164. package/dist/pty/pairing.d.ts.map +1 -0
  165. package/dist/pty/pairing.js +351 -0
  166. package/dist/pty/pairing.js.map +1 -0
  167. package/dist/pty/routes.d.ts +49 -0
  168. package/dist/pty/routes.d.ts.map +1 -0
  169. package/dist/pty/routes.js +624 -0
  170. package/dist/pty/routes.js.map +1 -0
  171. package/dist/pty/sessions.d.ts +167 -0
  172. package/dist/pty/sessions.d.ts.map +1 -0
  173. package/dist/pty/sessions.js +513 -0
  174. package/dist/pty/sessions.js.map +1 -0
  175. package/dist/pty/tmux.d.ts +109 -0
  176. package/dist/pty/tmux.d.ts.map +1 -0
  177. package/dist/pty/tmux.js +271 -0
  178. package/dist/pty/tmux.js.map +1 -0
  179. package/dist/roster.d.ts +37 -0
  180. package/dist/roster.d.ts.map +1 -0
  181. package/dist/roster.js +126 -0
  182. package/dist/roster.js.map +1 -0
  183. package/dist/runtime/circuitBreaker.d.ts +95 -0
  184. package/dist/runtime/circuitBreaker.d.ts.map +1 -0
  185. package/dist/runtime/circuitBreaker.js +178 -0
  186. package/dist/runtime/circuitBreaker.js.map +1 -0
  187. package/dist/runtime/daemonMeta.d.ts +53 -0
  188. package/dist/runtime/daemonMeta.d.ts.map +1 -0
  189. package/dist/runtime/daemonMeta.js +121 -0
  190. package/dist/runtime/daemonMeta.js.map +1 -0
  191. package/dist/runtime/ensureRuntime.d.ts +103 -0
  192. package/dist/runtime/ensureRuntime.d.ts.map +1 -0
  193. package/dist/runtime/ensureRuntime.js +276 -0
  194. package/dist/runtime/ensureRuntime.js.map +1 -0
  195. package/dist/runtime/extensions.d.ts +57 -0
  196. package/dist/runtime/extensions.d.ts.map +1 -0
  197. package/dist/runtime/extensions.js +216 -0
  198. package/dist/runtime/extensions.js.map +1 -0
  199. package/dist/runtime/localHttp.d.ts +24 -0
  200. package/dist/runtime/localHttp.d.ts.map +1 -0
  201. package/dist/runtime/localHttp.js +84 -0
  202. package/dist/runtime/localHttp.js.map +1 -0
  203. package/dist/runtime/projectResolution.d.ts +29 -0
  204. package/dist/runtime/projectResolution.d.ts.map +1 -0
  205. package/dist/runtime/projectResolution.js +67 -0
  206. package/dist/runtime/projectResolution.js.map +1 -0
  207. package/dist/runtime/protocol.d.ts +62 -0
  208. package/dist/runtime/protocol.d.ts.map +1 -0
  209. package/dist/runtime/protocol.js +74 -0
  210. package/dist/runtime/protocol.js.map +1 -0
  211. package/dist/sentinelIssues.d.ts +42 -2
  212. package/dist/sentinelIssues.d.ts.map +1 -1
  213. package/dist/sentinelIssues.js +167 -65
  214. package/dist/sentinelIssues.js.map +1 -1
  215. package/dist/server.js +123 -15
  216. package/dist/server.js.map +1 -1
  217. package/dist/toolConfig.d.ts.map +1 -1
  218. package/dist/toolConfig.js +12 -0
  219. package/dist/toolConfig.js.map +1 -1
  220. package/dist/tools/agentic/agentQueue.d.ts.map +1 -1
  221. package/dist/tools/agentic/agentQueue.js +4 -0
  222. package/dist/tools/agentic/agentQueue.js.map +1 -1
  223. package/dist/tools/agentic/index.d.ts.map +1 -1
  224. package/dist/tools/agentic/index.js +28 -2
  225. package/dist/tools/agentic/index.js.map +1 -1
  226. package/dist/tools/architect/index.d.ts +1 -0
  227. package/dist/tools/architect/index.d.ts.map +1 -1
  228. package/dist/tools/architect/index.js +52 -3
  229. package/dist/tools/architect/index.js.map +1 -1
  230. package/dist/tools/architect.d.ts.map +1 -1
  231. package/dist/tools/architect.js +59 -8
  232. package/dist/tools/architect.js.map +1 -1
  233. package/dist/tools/artifacts.d.ts +5 -0
  234. package/dist/tools/artifacts.d.ts.map +1 -0
  235. package/dist/tools/artifacts.js +89 -0
  236. package/dist/tools/artifacts.js.map +1 -0
  237. package/dist/tools/asks.d.ts +6 -0
  238. package/dist/tools/asks.d.ts.map +1 -0
  239. package/dist/tools/asks.js +104 -0
  240. package/dist/tools/asks.js.map +1 -0
  241. package/dist/tools/context.d.ts +10 -5
  242. package/dist/tools/context.d.ts.map +1 -1
  243. package/dist/tools/context.js +45 -18
  244. package/dist/tools/context.js.map +1 -1
  245. package/dist/tools/coordinator/coordinator.d.ts.map +1 -1
  246. package/dist/tools/coordinator/coordinator.js +48 -19
  247. package/dist/tools/coordinator/coordinator.js.map +1 -1
  248. package/dist/tools/coordinator/index.d.ts +1 -0
  249. package/dist/tools/coordinator/index.d.ts.map +1 -1
  250. package/dist/tools/coordinator/index.js +42 -2
  251. package/dist/tools/coordinator/index.js.map +1 -1
  252. package/dist/tools/crit.d.ts +2 -1
  253. package/dist/tools/crit.d.ts.map +1 -1
  254. package/dist/tools/crit.js +19 -4
  255. package/dist/tools/crit.js.map +1 -1
  256. package/dist/tools/data-inspector.d.ts +1 -1
  257. package/dist/tools/data-inspector.d.ts.map +1 -1
  258. package/dist/tools/data-inspector.js +1 -1
  259. package/dist/tools/data-inspector.js.map +1 -1
  260. package/dist/tools/designer/index.d.ts.map +1 -1
  261. package/dist/tools/designer/index.js +4 -3
  262. package/dist/tools/designer/index.js.map +1 -1
  263. package/dist/tools/designer/lateral-tools.d.ts.map +1 -1
  264. package/dist/tools/designer/lateral-tools.js +4 -2
  265. package/dist/tools/designer/lateral-tools.js.map +1 -1
  266. package/dist/tools/designer.d.ts +2 -1
  267. package/dist/tools/designer.d.ts.map +1 -1
  268. package/dist/tools/designer.js +24 -12
  269. package/dist/tools/designer.js.map +1 -1
  270. package/dist/tools/dojo/index.d.ts.map +1 -1
  271. package/dist/tools/dojo/index.js +52 -3
  272. package/dist/tools/dojo/index.js.map +1 -1
  273. package/dist/tools/dojo.d.ts +65 -3
  274. package/dist/tools/dojo.d.ts.map +1 -1
  275. package/dist/tools/dojo.js +148 -23
  276. package/dist/tools/dojo.js.map +1 -1
  277. package/dist/tools/friction.d.ts.map +1 -1
  278. package/dist/tools/friction.js +16 -6
  279. package/dist/tools/friction.js.map +1 -1
  280. package/dist/tools/guardian.d.ts +7 -0
  281. package/dist/tools/guardian.d.ts.map +1 -1
  282. package/dist/tools/guardian.js +152 -11
  283. package/dist/tools/guardian.js.map +1 -1
  284. package/dist/tools/hygiene/oracle-hygiene.d.ts.map +1 -1
  285. package/dist/tools/hygiene/oracle-hygiene.js +8 -2
  286. package/dist/tools/hygiene/oracle-hygiene.js.map +1 -1
  287. package/dist/tools/index.d.ts.map +1 -1
  288. package/dist/tools/index.js +33 -18
  289. package/dist/tools/index.js.map +1 -1
  290. package/dist/tools/killswitch/index.d.ts +13 -0
  291. package/dist/tools/killswitch/index.d.ts.map +1 -0
  292. package/dist/tools/killswitch/index.js +138 -0
  293. package/dist/tools/killswitch/index.js.map +1 -0
  294. package/dist/tools/learnings.d.ts +2 -1
  295. package/dist/tools/learnings.d.ts.map +1 -1
  296. package/dist/tools/learnings.js +31 -15
  297. package/dist/tools/learnings.js.map +1 -1
  298. package/dist/tools/oracle/index.d.ts.map +1 -1
  299. package/dist/tools/oracle/index.js +8 -0
  300. package/dist/tools/oracle/index.js.map +1 -1
  301. package/dist/tools/oracle.d.ts +7 -0
  302. package/dist/tools/oracle.d.ts.map +1 -1
  303. package/dist/tools/oracle.js +41 -12
  304. package/dist/tools/oracle.js.map +1 -1
  305. package/dist/tools/policy.d.ts +2 -1
  306. package/dist/tools/policy.d.ts.map +1 -1
  307. package/dist/tools/policy.js +28 -9
  308. package/dist/tools/policy.js.map +1 -1
  309. package/dist/tools/postoffice/index.d.ts +10 -0
  310. package/dist/tools/postoffice/index.d.ts.map +1 -0
  311. package/dist/tools/postoffice/index.js +218 -0
  312. package/dist/tools/postoffice/index.js.map +1 -0
  313. package/dist/tools/postoffice.d.ts +78 -0
  314. package/dist/tools/postoffice.d.ts.map +1 -0
  315. package/dist/tools/postoffice.js +199 -0
  316. package/dist/tools/postoffice.js.map +1 -0
  317. package/dist/tools/provenance.d.ts +18 -2
  318. package/dist/tools/provenance.d.ts.map +1 -1
  319. package/dist/tools/provenance.js +68 -40
  320. package/dist/tools/provenance.js.map +1 -1
  321. package/dist/tools/registry/index.d.ts.map +1 -1
  322. package/dist/tools/registry/index.js +24 -0
  323. package/dist/tools/registry/index.js.map +1 -1
  324. package/dist/tools/sentinel/index.d.ts +1 -0
  325. package/dist/tools/sentinel/index.d.ts.map +1 -1
  326. package/dist/tools/sentinel/index.js +142 -6
  327. package/dist/tools/sentinel/index.js.map +1 -1
  328. package/dist/tools/sentinel.d.ts +152 -1
  329. package/dist/tools/sentinel.d.ts.map +1 -1
  330. package/dist/tools/sentinel.js +609 -328
  331. package/dist/tools/sentinel.js.map +1 -1
  332. package/dist/tools/shared/index.d.ts +2 -1
  333. package/dist/tools/shared/index.d.ts.map +1 -1
  334. package/dist/tools/shared/index.js +2 -1
  335. package/dist/tools/shared/index.js.map +1 -1
  336. package/dist/tools/shared/response.d.ts +24 -0
  337. package/dist/tools/shared/response.d.ts.map +1 -1
  338. package/dist/tools/shared/response.js +61 -7
  339. package/dist/tools/shared/response.js.map +1 -1
  340. package/dist/tools/shared/runTracker.d.ts +2 -0
  341. package/dist/tools/shared/runTracker.d.ts.map +1 -1
  342. package/dist/tools/shared/runTracker.js +38 -0
  343. package/dist/tools/shared/runTracker.js.map +1 -1
  344. package/dist/tools/shared/storeRead.d.ts +153 -0
  345. package/dist/tools/shared/storeRead.d.ts.map +1 -0
  346. package/dist/tools/shared/storeRead.js +242 -0
  347. package/dist/tools/shared/storeRead.js.map +1 -0
  348. package/dist/tools/swarm.d.ts +3 -1
  349. package/dist/tools/swarm.d.ts.map +1 -1
  350. package/dist/tools/swarm.js +6 -12
  351. package/dist/tools/swarm.js.map +1 -1
  352. package/dist/tools/testSpec.d.ts +3 -2
  353. package/dist/tools/testSpec.d.ts.map +1 -1
  354. package/dist/tools/testSpec.js +51 -14
  355. package/dist/tools/testSpec.js.map +1 -1
  356. package/dist/tools/vector.d.ts +33 -1
  357. package/dist/tools/vector.d.ts.map +1 -1
  358. package/dist/tools/vector.js +31 -5
  359. package/dist/tools/vector.js.map +1 -1
  360. package/dist/tools/voice/index.d.ts +1 -0
  361. package/dist/tools/voice/index.d.ts.map +1 -1
  362. package/dist/tools/voice/index.js +33 -2
  363. package/dist/tools/voice/index.js.map +1 -1
  364. package/dist/tools/voice.d.ts +48 -1
  365. package/dist/tools/voice.d.ts.map +1 -1
  366. package/dist/tools/voice.js +63 -3
  367. package/dist/tools/voice.js.map +1 -1
  368. package/dist/tools/zoom/index.d.ts +15 -0
  369. package/dist/tools/zoom/index.d.ts.map +1 -0
  370. package/dist/tools/zoom/index.js +174 -0
  371. package/dist/tools/zoom/index.js.map +1 -0
  372. package/dist/tools/zoom.d.ts +234 -0
  373. package/dist/tools/zoom.d.ts.map +1 -0
  374. package/dist/tools/zoom.js +627 -0
  375. package/dist/tools/zoom.js.map +1 -0
  376. package/dist/transports/bridge.d.ts +1 -1
  377. package/dist/transports/bridge.d.ts.map +1 -1
  378. package/dist/transports/bridge.js +4 -1
  379. package/dist/transports/bridge.js.map +1 -1
  380. package/dist/transports/http.d.ts +1 -1
  381. package/dist/transports/http.d.ts.map +1 -1
  382. package/dist/transports/http.js +3 -1
  383. package/dist/transports/http.js.map +1 -1
  384. package/dist/transports/index.d.ts +1 -0
  385. package/dist/transports/index.d.ts.map +1 -1
  386. package/dist/transports/index.js +1 -0
  387. package/dist/transports/index.js.map +1 -1
  388. package/dist/transports/mcp.d.ts +1 -1
  389. package/dist/transports/mcp.d.ts.map +1 -1
  390. package/dist/transports/mcp.js +9 -4
  391. package/dist/transports/mcp.js.map +1 -1
  392. package/dist/transports/stdio.d.ts +1 -1
  393. package/dist/transports/stdio.d.ts.map +1 -1
  394. package/dist/transports/stdio.js +2 -0
  395. package/dist/transports/stdio.js.map +1 -1
  396. package/dist/transports/thinStdio.d.ts +22 -0
  397. package/dist/transports/thinStdio.d.ts.map +1 -0
  398. package/dist/transports/thinStdio.js +218 -0
  399. package/dist/transports/thinStdio.js.map +1 -0
  400. package/dist/transports/types.d.ts +8 -1
  401. package/dist/transports/types.d.ts.map +1 -1
  402. package/dist/types/agent-services.d.ts +7 -0
  403. package/dist/types/agent-services.d.ts.map +1 -1
  404. package/dist/version.d.ts +5 -0
  405. package/dist/version.d.ts.map +1 -0
  406. package/dist/version.js +23 -0
  407. package/dist/version.js.map +1 -0
  408. package/package.json +20 -4
  409. package/templates/AGENT.md +3 -0
  410. package/templates/CLAUDE-decibel.md +11 -0
  411. package/templates/com.decibel.daemon.plist +6 -1
  412. package/dist/tools/deck.d.ts +0 -11
  413. package/dist/tools/deck.d.ts.map +0 -1
  414. package/dist/tools/deck.js +0 -1656
  415. package/dist/tools/deck.js.map +0 -1
  416. package/dist/tools/mother.d.ts +0 -11
  417. package/dist/tools/mother.d.ts.map +0 -1
  418. package/dist/tools/mother.js +0 -503
  419. package/dist/tools/mother.js.map +0 -1
  420. package/dist/tools/registry.d.ts +0 -3
  421. package/dist/tools/registry.d.ts.map +0 -1
  422. package/dist/tools/registry.js +0 -189
  423. package/dist/tools/registry.js.map +0 -1
  424. package/dist/tools/senken.d.ts +0 -11
  425. package/dist/tools/senken.d.ts.map +0 -1
  426. package/dist/tools/senken.js +0 -482
  427. package/dist/tools/senken.js.map +0 -1
  428. package/dist/tools/terminal.d.ts +0 -17
  429. package/dist/tools/terminal.d.ts.map +0 -1
  430. package/dist/tools/terminal.js +0 -968
  431. package/dist/tools/terminal.js.map +0 -1
  432. package/dist/tools/toolsIndex.d.ts +0 -5
  433. package/dist/tools/toolsIndex.d.ts.map +0 -1
  434. package/dist/tools/toolsIndex.js +0 -37
  435. package/dist/tools/toolsIndex.js.map +0 -1
@@ -0,0 +1,149 @@
1
+ // ============================================================================
2
+ // Launch profile — the flags every daemon spawn gets (decibel-hq ADR-0018 D3)
3
+ // ============================================================================
4
+ // ~/.decibel/launch.json, written by Ben, read by the daemon. Kept apart from
5
+ // config.yaml and env so it holds no secrets and can be read and diffed freely.
6
+ //
7
+ // The schema is CLOSED: an unknown key, a mode Claude Code does not have, or a
8
+ // channel that is not `server:<name>` makes the whole file invalid, and every
9
+ // spawn then refuses with LAUNCH_PROFILE_INVALID rather than silently starting
10
+ // claude without the flags Ben chose. HQ and the CLI never send argv or a
11
+ // profile; caller-chosen flags plus `claude` is code execution.
12
+ //
13
+ // No file means today's behaviour: no extra flags.
14
+ //
15
+ // The `tmux` block configures the daemon's own tmux server, which starts with
16
+ // -f /dev/null and so never reads ~/.tmux.conf. Mouse on lets the wheel scroll
17
+ // a session attached from Ghostty; HQ's pane scrolls through its own frames
18
+ // either way, and copies with Option-drag once tmux owns the mouse.
19
+ // ============================================================================
20
+ import { existsSync, readFileSync } from 'fs';
21
+ import { homedir } from 'os';
22
+ import { join } from 'path';
23
+ import { SessionError } from './errors.js';
24
+ /** `claude --permission-mode` choices, Claude Code 2.1.281. */
25
+ export const PERMISSION_MODES = ['acceptEdits', 'auto', 'bypassPermissions', 'manual', 'dontAsk', 'plan'];
26
+ const CHANNEL_RE = /^server:[a-z0-9-]+$/;
27
+ const KEYS = new Set(['permission_mode', 'dev_channels', 'period_gap_hours', 'restore_on_start', 'tmux']);
28
+ const TMUX_KEYS = new Set(['mouse', 'history_limit']);
29
+ export const DEFAULT_PERIOD_GAP_HOURS = 4;
30
+ /** Scrollback lines per pane. A pane's limit is fixed when it is created. */
31
+ export const DEFAULT_HISTORY_LIMIT = 50_000;
32
+ const MIN_HISTORY_LIMIT = 2_000;
33
+ const MAX_HISTORY_LIMIT = 1_000_000;
34
+ export function defaultProfile() {
35
+ return {
36
+ dev_channels: [],
37
+ period_gap_hours: DEFAULT_PERIOD_GAP_HOURS,
38
+ restore_on_start: false,
39
+ // Mouse on by default: Ben asked for wheel scrolling in Ghostty twice.
40
+ tmux: { mouse: true, history_limit: DEFAULT_HISTORY_LIMIT },
41
+ };
42
+ }
43
+ /** Resolved per call so tests (and a changed $HOME) are honoured. */
44
+ export function launchProfilePath() {
45
+ return process.env.DECIBEL_LAUNCH_PATH || join(homedir(), '.decibel', 'launch.json');
46
+ }
47
+ /** Validate a parsed launch.json. Throws a message naming the first problem. */
48
+ export function parseLaunchProfile(raw) {
49
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
50
+ throw new Error('launch.json must be a JSON object');
51
+ const o = raw;
52
+ for (const k of Object.keys(o)) {
53
+ if (!KEYS.has(k))
54
+ throw new Error(`unknown key "${k}" (allowed: ${[...KEYS].join(', ')})`);
55
+ }
56
+ const p = defaultProfile();
57
+ if (o.permission_mode !== undefined) {
58
+ if (!PERMISSION_MODES.includes(o.permission_mode)) {
59
+ throw new Error(`permission_mode must be one of ${PERMISSION_MODES.join(', ')}`);
60
+ }
61
+ p.permission_mode = o.permission_mode;
62
+ }
63
+ if (o.dev_channels !== undefined) {
64
+ if (!Array.isArray(o.dev_channels) || !o.dev_channels.every((c) => typeof c === 'string' && CHANNEL_RE.test(c))) {
65
+ throw new Error('dev_channels must be a list of "server:<name>" entries ([a-z0-9-] names)');
66
+ }
67
+ p.dev_channels = [...new Set(o.dev_channels)];
68
+ }
69
+ if (o.period_gap_hours !== undefined) {
70
+ const h = o.period_gap_hours;
71
+ if (typeof h !== 'number' || !Number.isFinite(h) || h < 0.5 || h > 72) {
72
+ throw new Error('period_gap_hours must be a number between 0.5 and 72');
73
+ }
74
+ p.period_gap_hours = h;
75
+ }
76
+ if (o.restore_on_start !== undefined) {
77
+ if (typeof o.restore_on_start !== 'boolean')
78
+ throw new Error('restore_on_start must be true or false');
79
+ p.restore_on_start = o.restore_on_start;
80
+ }
81
+ if (o.tmux !== undefined) {
82
+ const t = o.tmux;
83
+ if (!t || typeof t !== 'object' || Array.isArray(t))
84
+ throw new Error('tmux must be an object');
85
+ const to = t;
86
+ for (const k of Object.keys(to)) {
87
+ if (!TMUX_KEYS.has(k))
88
+ throw new Error(`unknown key "tmux.${k}" (allowed: ${[...TMUX_KEYS].join(', ')})`);
89
+ }
90
+ if (to.mouse !== undefined) {
91
+ if (typeof to.mouse !== 'boolean')
92
+ throw new Error('tmux.mouse must be true or false');
93
+ p.tmux.mouse = to.mouse;
94
+ }
95
+ if (to.history_limit !== undefined) {
96
+ const n = to.history_limit;
97
+ if (typeof n !== 'number' || !Number.isInteger(n) || n < MIN_HISTORY_LIMIT || n > MAX_HISTORY_LIMIT) {
98
+ throw new Error(`tmux.history_limit must be a whole number from ${MIN_HISTORY_LIMIT} to ${MAX_HISTORY_LIMIT}`);
99
+ }
100
+ p.tmux.history_limit = n;
101
+ }
102
+ }
103
+ return p;
104
+ }
105
+ /**
106
+ * The profile, read per call (the file is tiny and spawns are rare, so an edit
107
+ * takes effect without a restart). Throws LAUNCH_PROFILE_INVALID when the file
108
+ * exists and is wrong.
109
+ */
110
+ export function loadLaunchProfile() {
111
+ const path = launchProfilePath();
112
+ if (!existsSync(path))
113
+ return defaultProfile();
114
+ try {
115
+ return parseLaunchProfile(JSON.parse(readFileSync(path, 'utf-8')));
116
+ }
117
+ catch (err) {
118
+ throw new SessionError(500, 'LAUNCH_PROFILE_INVALID', `${path} is invalid: ${err instanceof Error ? err.message : String(err)}. Fix or remove it; no session starts until then.`);
119
+ }
120
+ }
121
+ /**
122
+ * claude flags for a profile. Each channel gets its own flag, placed last: the
123
+ * flag is undocumented, and repeating it is safe whether it takes one value or
124
+ * many, where a second bare value could otherwise be read as a prompt.
125
+ */
126
+ export function profileArgs(p) {
127
+ const out = [];
128
+ if (p.permission_mode)
129
+ out.push('--permission-mode', p.permission_mode);
130
+ for (const c of p.dev_channels)
131
+ out.push('--dangerously-load-development-channels', c);
132
+ return out;
133
+ }
134
+ /**
135
+ * Lets tmux pass OSC 8 hyperlinks (which Claude Code emits) through to an
136
+ * xterm-family client, so links are clickable in Ghostty and HQ's pane. Always
137
+ * on; it costs nothing. A FIXED index, not `set -as`: this runs before every
138
+ * spawn, and appending would grow the array by one entry each time.
139
+ */
140
+ export const HYPERLINKS_FEATURE_INDEX = 20;
141
+ /** Options for the owned server, as one ';'-separated tmux invocation. */
142
+ export function tmuxOptionArgs(t) {
143
+ return [
144
+ 'set-option', '-g', 'history-limit', String(t.history_limit), ';',
145
+ 'set-option', '-g', 'mouse', t.mouse ? 'on' : 'off', ';',
146
+ 'set-option', '-s', `terminal-features[${HYPERLINKS_FEATURE_INDEX}]`, 'xterm*:hyperlinks',
147
+ ];
148
+ }
149
+ //# sourceMappingURL=launchProfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchProfile.js","sourceRoot":"","sources":["../../src/pty/launchProfile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { type HostedSession } from './sessions.js';
2
+ export declare const MAX_OPEN = 12;
3
+ export declare const GHOSTTY_APP = "/Applications/Ghostty.app";
4
+ export declare const GHOSTTY_TERM = "xterm-ghostty";
5
+ export type OpenStatus = 'opened' | 'already_open' | 'failed';
6
+ export type OpenCode = 'NOT_LIVE' | 'NOT_OWNED' | 'GHOSTTY_NOT_INSTALLED' | 'AUTOMATION_DENIED' | 'OSASCRIPT_FAILED' | 'BAD_PATH';
7
+ export interface OpenRow {
8
+ session_key: string;
9
+ status: OpenStatus;
10
+ code?: OpenCode;
11
+ error?: string;
12
+ }
13
+ export interface RunResult {
14
+ code: number;
15
+ stderr: string;
16
+ }
17
+ export interface OpenDeps {
18
+ sessions?: () => Promise<HostedSession[]>;
19
+ /** Session names that already have a Ghostty client on the owned server. */
20
+ ghosttyAttached?: () => Promise<Set<string>>;
21
+ ghosttyInstalled?: () => boolean;
22
+ /** Runs an AppleScript (tabs). */
23
+ osascript?: (script: string) => Promise<RunResult>;
24
+ /** Runs `open` with these args (windows). */
25
+ open?: (args: string[]) => Promise<RunResult>;
26
+ ensureTitles?: () => Promise<void>;
27
+ sleep?: (ms: number) => Promise<void>;
28
+ }
29
+ /** Global on the owned server, so sessions spawned before this also get titles. */
30
+ export declare function ensureTitles(): Promise<void>;
31
+ /** One shell word. Ghostty runs `command` through a shell. */
32
+ export declare function shellWord(s: string): string;
33
+ /**
34
+ * An AppleScript string literal. AppleScript has no \u escape, so JSON-style
35
+ * quoting breaks on anything it would escape that way; only backslash and the
36
+ * double quote are escaped, and control characters are refused outright.
37
+ */
38
+ export declare function appleString(s: string): string;
39
+ export declare function tabScript(command: string, cwd: string): string;
40
+ export declare function windowArgs(argv: string[], cwd: string): string[];
41
+ export declare function validateOpen(body: unknown): {
42
+ keys: string[];
43
+ layout: 'tabs' | 'windows';
44
+ };
45
+ export declare function openTerminal(body: unknown, deps?: OpenDeps): Promise<{
46
+ results: OpenRow[];
47
+ }>;
48
+ //# sourceMappingURL=openTerminal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openTerminal.d.ts","sourceRoot":"","sources":["../../src/pty/openTerminal.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAEvE,eAAO,MAAM,QAAQ,KAAK,CAAC;AAC3B,eAAO,MAAM,WAAW,8BAA8B,CAAC;AACvD,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAG5C,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,cAAc,GAAG,QAAQ,CAAC;AAC9D,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,uBAAuB,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,UAAU,CAAC;AAElI,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1C,4EAA4E;IAC5E,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAC;IACjC,kCAAkC;IAClC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACnD,6CAA6C;IAC7C,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAMD,mFAAmF;AACnF,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAGlD;AAMD,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAc9D;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAEhE;AAiCD,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAc1F;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,CA6DtG"}
@@ -0,0 +1,185 @@
1
+ // ============================================================================
2
+ // POST /sessions/open-terminal: open hosted sessions in desktop Ghostty
3
+ // ============================================================================
4
+ // decibel-hq ADR-0018 D5, amended 2026-10-14 (tools ISS-0210). A browser
5
+ // cannot run AppleScript, so HQ asks the daemon to open a Ghostty tab or
6
+ // window attached to a live session the daemon itself spawned.
7
+ //
8
+ // What the caller controls is only WHICH sessions and the layout. The command
9
+ // is always the daemon's own attach argv and the cwd the daemon recorded, so
10
+ // no request text reaches a shell. Titles are not in the command either: the
11
+ // owned tmux server runs with set-titles on (see ensureTitles), so tmux titles
12
+ // every client itself, including tabs that were already open.
13
+ //
14
+ // tabs AppleScript: new tab in the front window, or a new window if
15
+ // none is open. Needs a macOS Automation (TCC) grant for whatever
16
+ // process macOS holds responsible: under launchd, node.
17
+ // windows `open -na Ghostty.app --args ...`: LaunchServices, not Apple
18
+ // Events, so no Automation grant. One window per session.
19
+ //
20
+ // After one AUTOMATION_DENIED, the rest of the batch is not attempted: every
21
+ // further try would raise the same macOS prompt or fail the same way.
22
+ // ============================================================================
23
+ import { execFile } from 'child_process';
24
+ import { existsSync } from 'fs';
25
+ import { log } from '../config.js';
26
+ import { SessionError } from './errors.js';
27
+ import { tmux, TITLE_FORMAT } from './tmux.js';
28
+ import { listHostedSessions } from './sessions.js';
29
+ export const MAX_OPEN = 12;
30
+ export const GHOSTTY_APP = '/Applications/Ghostty.app';
31
+ export const GHOSTTY_TERM = 'xterm-ghostty';
32
+ const STAGGER_MS = 300;
33
+ // ----------------------------------------------------------------------------
34
+ // Titles: tmux sends OSC 2 to every client on the owned server
35
+ // ----------------------------------------------------------------------------
36
+ /** Global on the owned server, so sessions spawned before this also get titles. */
37
+ export async function ensureTitles() {
38
+ const r = await tmux('owned', ['set-option', '-g', 'set-titles', 'on', ';', 'set-option', '-g', 'set-titles-string', TITLE_FORMAT]);
39
+ if (!r.ok)
40
+ log(`Sessions: could not turn on tmux titles: ${r.stderr.trim()}`);
41
+ }
42
+ // ----------------------------------------------------------------------------
43
+ // Quoting
44
+ // ----------------------------------------------------------------------------
45
+ /** One shell word. Ghostty runs `command` through a shell. */
46
+ export function shellWord(s) {
47
+ return `'${s.replace(/'/g, `'\\''`)}'`;
48
+ }
49
+ /**
50
+ * An AppleScript string literal. AppleScript has no \u escape, so JSON-style
51
+ * quoting breaks on anything it would escape that way; only backslash and the
52
+ * double quote are escaped, and control characters are refused outright.
53
+ */
54
+ export function appleString(s) {
55
+ if (/[\u0000-\u001f\u007f]/.test(s))
56
+ throw new Error('control character in AppleScript string');
57
+ return `"${s.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
58
+ }
59
+ export function tabScript(command, cwd) {
60
+ return [
61
+ 'tell application "Ghostty"',
62
+ ' set cfg to new surface configuration',
63
+ ` set command of cfg to ${appleString(command)}`,
64
+ ` set initial working directory of cfg to ${appleString(cwd)}`,
65
+ ' if (count of windows) = 0 then',
66
+ ' new window with configuration cfg',
67
+ ' else',
68
+ ' new tab in front window with configuration cfg',
69
+ ' end if',
70
+ 'end tell',
71
+ '',
72
+ ].join('\n');
73
+ }
74
+ export function windowArgs(argv, cwd) {
75
+ return ['-na', GHOSTTY_APP, '--args', `--working-directory=${cwd}`, `--command=${argv.map(shellWord).join(' ')}`];
76
+ }
77
+ // ----------------------------------------------------------------------------
78
+ // Default deps
79
+ // ----------------------------------------------------------------------------
80
+ function run(bin, args, input) {
81
+ return new Promise((resolve) => {
82
+ const child = execFile(bin, args, { timeout: 30_000 }, (err, _stdout, stderr) => {
83
+ // On a non-zero exit, execFile's error carries the exit code as `code`.
84
+ const exit = err?.code;
85
+ const code = !err ? 0 : typeof exit === 'number' ? exit : 1;
86
+ resolve({ code, stderr: String(stderr ?? '') || (err ? err.message : '') });
87
+ });
88
+ if (input !== undefined)
89
+ child.stdin?.end(input);
90
+ });
91
+ }
92
+ async function ghosttyAttachedDefault() {
93
+ const r = await tmux('owned', ['list-clients', '-F', '#{client_session}\t#{client_termname}']);
94
+ const out = new Set();
95
+ if (!r.ok)
96
+ return out;
97
+ for (const line of r.stdout.split('\n')) {
98
+ const [session, term] = line.split('\t');
99
+ if (session && term === GHOSTTY_TERM)
100
+ out.add(session);
101
+ }
102
+ return out;
103
+ }
104
+ // ----------------------------------------------------------------------------
105
+ // The route
106
+ // ----------------------------------------------------------------------------
107
+ export function validateOpen(body) {
108
+ const b = (body ?? {});
109
+ const layout = b.layout === undefined ? 'tabs' : b.layout;
110
+ if (layout !== 'tabs' && layout !== 'windows') {
111
+ throw new SessionError(400, 'BAD_REQUEST', 'layout must be "tabs" or "windows".');
112
+ }
113
+ if (!Array.isArray(b.session_keys) || b.session_keys.length === 0 || !b.session_keys.every((k) => typeof k === 'string' && k)) {
114
+ throw new SessionError(400, 'BAD_REQUEST', 'session_keys must be a non-empty array of session keys.');
115
+ }
116
+ const keys = [...new Set(b.session_keys)];
117
+ if (keys.length > MAX_OPEN) {
118
+ throw new SessionError(400, 'BAD_REQUEST', `At most ${MAX_OPEN} sessions per call.`);
119
+ }
120
+ return { keys, layout };
121
+ }
122
+ export async function openTerminal(body, deps = {}) {
123
+ const { keys, layout } = validateOpen(body);
124
+ const installed = (deps.ghosttyInstalled ?? (() => existsSync(GHOSTTY_APP)))();
125
+ if (!installed) {
126
+ return { results: keys.map((k) => ({ session_key: k, status: 'failed', code: 'GHOSTTY_NOT_INSTALLED', error: `${GHOSTTY_APP} not found.` })) };
127
+ }
128
+ await (deps.ensureTitles ?? ensureTitles)();
129
+ const [rows, attached] = await Promise.all([
130
+ (deps.sessions ?? (() => listHostedSessions()))(),
131
+ (deps.ghosttyAttached ?? ghosttyAttachedDefault)(),
132
+ ]);
133
+ const byKey = new Map(rows.map((r) => [r.session_key, r]));
134
+ const osascript = deps.osascript ?? ((script) => run('osascript', ['-'], script));
135
+ const open = deps.open ?? ((args) => run('open', args));
136
+ const sleep = deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
137
+ const results = [];
138
+ let denied = false;
139
+ let opened = 0;
140
+ for (const key of keys) {
141
+ const row = byKey.get(key);
142
+ if (!row || row.state !== 'live') {
143
+ results.push({ session_key: key, status: 'failed', code: 'NOT_LIVE', error: 'Not a live session.' });
144
+ continue;
145
+ }
146
+ if (row.origin !== 'spawned' || !row.attach_argv || !row.cwd) {
147
+ results.push({ session_key: key, status: 'failed', code: 'NOT_OWNED', error: 'Only sessions the daemon spawned can be opened.' });
148
+ continue;
149
+ }
150
+ if (attached.has(key)) {
151
+ results.push({ session_key: key, status: 'already_open' });
152
+ continue;
153
+ }
154
+ if (denied) {
155
+ results.push({ session_key: key, status: 'failed', code: 'AUTOMATION_DENIED', error: 'macOS denied control of Ghostty.' });
156
+ continue;
157
+ }
158
+ if (opened > 0)
159
+ await sleep(STAGGER_MS);
160
+ let r;
161
+ try {
162
+ r = layout === 'tabs'
163
+ ? await osascript(tabScript(row.attach_argv.map(shellWord).join(' '), row.cwd))
164
+ : await open(windowArgs(row.attach_argv, row.cwd));
165
+ }
166
+ catch (err) {
167
+ results.push({ session_key: key, status: 'failed', code: 'BAD_PATH', error: err instanceof Error ? err.message : String(err) });
168
+ continue;
169
+ }
170
+ if (r.code === 0) {
171
+ opened++;
172
+ results.push({ session_key: key, status: 'opened' });
173
+ }
174
+ else if (/-1743/.test(r.stderr)) {
175
+ denied = true;
176
+ results.push({ session_key: key, status: 'failed', code: 'AUTOMATION_DENIED', error: 'macOS denied control of Ghostty.' });
177
+ }
178
+ else {
179
+ results.push({ session_key: key, status: 'failed', code: 'OSASCRIPT_FAILED', error: r.stderr.trim().slice(0, 300) || `exit ${r.code}` });
180
+ }
181
+ }
182
+ log(`Sessions: open-terminal (${layout}) ${results.map((r) => `${r.session_key}=${r.status}`).join(' ')}`);
183
+ return { results };
184
+ }
185
+ //# sourceMappingURL=openTerminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openTerminal.js","sourceRoot":"","sources":["../../src/pty/openTerminal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export type DialogAnswer = 'allow' | 'deny' | 'timeout' | 'error';
2
+ export interface DialogDeps {
3
+ /** Runs the AppleScript; resolves with what the user did. */
4
+ run?: (script: string, timeoutSec: number) => Promise<DialogAnswer>;
5
+ platform?: string;
6
+ enabled?: boolean;
7
+ }
8
+ /** For tests. */
9
+ export declare function _resetPairDialog(): void;
10
+ export declare function dialogScript(origin: string, label: string, code: string, timeoutSec: number): string;
11
+ /**
12
+ * Ask the user on this Mac. Fire and forget from the /pair/request route: the
13
+ * HTTP response never waits on the dialog, and nothing here throws.
14
+ */
15
+ export declare function confirmPairingLocally(pairingId: string, deps?: DialogDeps): Promise<DialogAnswer | 'skipped'>;
16
+ //# sourceMappingURL=pairDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairDialog.d.ts","sourceRoot":"","sources":["../../src/pty/pairDialog.ts"],"names":[],"mappings":"AA2BA,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAID,iBAAiB;AACjB,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAOD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAkBpG;AAmBD;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAqCvH"}
@@ -0,0 +1,121 @@
1
+ // ============================================================================
2
+ // Native pairing approval on macOS (ADR-0012 amendment, tools ISS-0228)
3
+ // ============================================================================
4
+ // ADR-0012's gate is that NO HTTP ROUTE APPROVES A PAIRING: a compromised HQ
5
+ // page can ask to pair, but it cannot say yes. Until now the yes was
6
+ // `decibel-tools pair approve <code>`, a developer command. On macOS the
7
+ // daemon now shows a native dialog on the user's own screen instead:
8
+ //
9
+ // "HQ (https://hq.example) wants to connect to Decibel on this Mac.
10
+ // Code 123456. Allow only if HQ shows the same code." [Deny] [Allow]
11
+ //
12
+ // The gate is unchanged. The request arrives over HTTP, but the approval is a
13
+ // local click in a window HQ cannot see or drive. Allow approves only the
14
+ // exact pending request that was shown, by id AND code, so a request replaced
15
+ // while the dialog was open is not approved by it. Deny removes the request.
16
+ // No answer within the pending window (10 min) leaves it to expire.
17
+ //
18
+ // One dialog at a time; while one is open, further requests still work through
19
+ // the CLI. Linux and Windows keep the CLI until each gets a native prompt.
20
+ // DECIBEL_PAIR_DIALOG=0 turns the dialog off.
21
+ // ============================================================================
22
+ import { execFile } from 'child_process';
23
+ import { log } from '../config.js';
24
+ import { appleString } from './openTerminal.js';
25
+ import { approvePendingLocally, revokePairing, listPairings, PENDING_TTL_MS } from './pairing.js';
26
+ let open = false;
27
+ /** For tests. */
28
+ export function _resetPairDialog() {
29
+ open = false;
30
+ }
31
+ /** Strip anything that could not, or should not, be shown in a dialog. */
32
+ function shown(s, max) {
33
+ return s.replace(/[\u0000-\u001f\u007f]/g, ' ').trim().slice(0, max);
34
+ }
35
+ export function dialogScript(origin, label, code, timeoutSec) {
36
+ const who = label && label !== 'HQ' ? `${shown(label, 60)} (${shown(origin, 200)})` : `HQ (${shown(origin, 200)})`;
37
+ const lines = [
38
+ `${who} wants to connect to Decibel on this Mac.`,
39
+ '',
40
+ `Code: ${code}`,
41
+ '',
42
+ "Allow only if HQ shows exactly this code. If you didn't just ask to connect, choose Deny.",
43
+ ];
44
+ // Lines joined in AppleScript itself: appleString escapes backslashes, so a
45
+ // "\n" inside the literal would show as text, not a line break.
46
+ const body = lines.map((l) => appleString(l)).join(' & linefeed & ');
47
+ return [
48
+ `display dialog (${body}) ` +
49
+ `with title "Decibel" buttons {"Deny", "Allow"} default button "Deny" cancel button "Deny" ` +
50
+ `with icon caution giving up after ${timeoutSec}`,
51
+ '',
52
+ ].join('\n');
53
+ }
54
+ function runDefault(script, timeoutSec) {
55
+ return new Promise((resolve) => {
56
+ const child = execFile('osascript', ['-'], { timeout: (timeoutSec + 30) * 1000 }, (err, stdout, stderr) => {
57
+ if (err) {
58
+ // The cancel button ("Deny") ends osascript with error -128.
59
+ resolve(/-128/.test(String(stderr)) ? 'deny' : 'error');
60
+ return;
61
+ }
62
+ const out = String(stdout);
63
+ if (/gave up:true/.test(out))
64
+ resolve('timeout');
65
+ else if (/button returned:Allow/.test(out))
66
+ resolve('allow');
67
+ else
68
+ resolve('deny');
69
+ });
70
+ child.stdin?.end(script);
71
+ });
72
+ }
73
+ /**
74
+ * Ask the user on this Mac. Fire and forget from the /pair/request route: the
75
+ * HTTP response never waits on the dialog, and nothing here throws.
76
+ */
77
+ export async function confirmPairingLocally(pairingId, deps = {}) {
78
+ const platform = deps.platform ?? process.platform;
79
+ const enabled = deps.enabled ?? process.env.DECIBEL_PAIR_DIALOG !== '0';
80
+ if (platform !== 'darwin' || !enabled || open)
81
+ return 'skipped';
82
+ const p = listPairings().find((x) => x.id === pairingId && x.status === 'pending');
83
+ if (!p || !p.code)
84
+ return 'skipped';
85
+ open = true;
86
+ try {
87
+ const timeoutSec = Math.floor(PENDING_TTL_MS / 1000);
88
+ let script;
89
+ try {
90
+ script = dialogScript(p.origin, p.label, p.code, timeoutSec);
91
+ }
92
+ catch (err) {
93
+ log(`Pairing: dialog not shown: ${err instanceof Error ? err.message : String(err)}`);
94
+ return 'error';
95
+ }
96
+ const answer = await (deps.run ?? runDefault)(script, timeoutSec);
97
+ if (answer === 'allow') {
98
+ try {
99
+ await approvePendingLocally(p.id, p.code);
100
+ log(`Pairing: ${p.origin} approved in the native dialog`);
101
+ }
102
+ catch (err) {
103
+ log(`Pairing: dialog approval not applied: ${err instanceof Error ? err.message : String(err)}`);
104
+ return 'error';
105
+ }
106
+ }
107
+ else if (answer === 'deny') {
108
+ await revokePairing(p.id);
109
+ log(`Pairing: ${p.origin} denied in the native dialog`);
110
+ }
111
+ return answer;
112
+ }
113
+ catch (err) {
114
+ log(`Pairing: dialog failed: ${err instanceof Error ? err.message : String(err)}`);
115
+ return 'error';
116
+ }
117
+ finally {
118
+ open = false;
119
+ }
120
+ }
121
+ //# sourceMappingURL=pairDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairDialog.js","sourceRoot":"","sources":["../../src/pty/pairDialog.ts"],"names":[],"mappings":"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"}