@raidiant/notifai 11.7.1 → 12.0.0-beta.11

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 (409) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/NOTICE +16 -0
  3. package/THIRD_PARTY_NOTICES +725 -0
  4. package/bin/notifai.mjs +11420 -0
  5. package/data/install.ps1 +318 -0
  6. package/data/release.json +1 -0
  7. package/inventory.json +1 -0
  8. package/npm-adapter-files.json +52 -0
  9. package/package.json +14 -44
  10. package/README.md +0 -168
  11. package/dist/agent-update-notice.d.ts +0 -7
  12. package/dist/agent-update-notice.js +0 -77
  13. package/dist/agent-update-notice.js.map +0 -1
  14. package/dist/atomic-file.d.ts +0 -30
  15. package/dist/atomic-file.js +0 -148
  16. package/dist/atomic-file.js.map +0 -1
  17. package/dist/attendant-update.d.ts +0 -15
  18. package/dist/attendant-update.js +0 -96
  19. package/dist/attendant-update.js.map +0 -1
  20. package/dist/claude-wake.d.ts +0 -108
  21. package/dist/claude-wake.js +0 -369
  22. package/dist/claude-wake.js.map +0 -1
  23. package/dist/cli-bin.d.ts +0 -26
  24. package/dist/cli-bin.js +0 -220
  25. package/dist/cli-bin.js.map +0 -1
  26. package/dist/cli-contract.d.ts +0 -16
  27. package/dist/cli-contract.js +0 -27
  28. package/dist/cli-contract.js.map +0 -1
  29. package/dist/cli-release.d.ts +0 -36
  30. package/dist/cli-release.js +0 -85
  31. package/dist/cli-release.js.map +0 -1
  32. package/dist/client.d.ts +0 -109
  33. package/dist/client.js +0 -217
  34. package/dist/client.js.map +0 -1
  35. package/dist/codex-answer-control.d.ts +0 -14
  36. package/dist/codex-answer-control.js +0 -41
  37. package/dist/codex-answer-control.js.map +0 -1
  38. package/dist/codex-answer-presentation.d.ts +0 -18
  39. package/dist/codex-answer-presentation.js +0 -113
  40. package/dist/codex-answer-presentation.js.map +0 -1
  41. package/dist/codex-input-lifecycle.d.ts +0 -10
  42. package/dist/codex-input-lifecycle.js +0 -63
  43. package/dist/codex-input-lifecycle.js.map +0 -1
  44. package/dist/codex-native-control.d.ts +0 -13
  45. package/dist/codex-native-control.js +0 -120
  46. package/dist/codex-native-control.js.map +0 -1
  47. package/dist/codex-native-turn.d.ts +0 -37
  48. package/dist/codex-native-turn.js +0 -155
  49. package/dist/codex-native-turn.js.map +0 -1
  50. package/dist/codex-question-bindings.d.ts +0 -76
  51. package/dist/codex-question-bindings.js +0 -151
  52. package/dist/codex-question-bindings.js.map +0 -1
  53. package/dist/codex-queue-control.d.ts +0 -21
  54. package/dist/codex-queue-control.js +0 -59
  55. package/dist/codex-queue-control.js.map +0 -1
  56. package/dist/codex-tool-messages.d.ts +0 -7
  57. package/dist/codex-tool-messages.js +0 -126
  58. package/dist/codex-tool-messages.js.map +0 -1
  59. package/dist/codex-wake.d.ts +0 -58
  60. package/dist/codex-wake.js +0 -135
  61. package/dist/codex-wake.js.map +0 -1
  62. package/dist/command-session.d.ts +0 -14
  63. package/dist/command-session.js +0 -31
  64. package/dist/command-session.js.map +0 -1
  65. package/dist/commands-acknowledge.d.ts +0 -13
  66. package/dist/commands-acknowledge.js +0 -116
  67. package/dist/commands-acknowledge.js.map +0 -1
  68. package/dist/commands-agent-sessions.d.ts +0 -6
  69. package/dist/commands-agent-sessions.js +0 -51
  70. package/dist/commands-agent-sessions.js.map +0 -1
  71. package/dist/commands-ask.d.ts +0 -62
  72. package/dist/commands-ask.js +0 -503
  73. package/dist/commands-ask.js.map +0 -1
  74. package/dist/commands-auth.d.ts +0 -76
  75. package/dist/commands-auth.js +0 -421
  76. package/dist/commands-auth.js.map +0 -1
  77. package/dist/commands-close.d.ts +0 -6
  78. package/dist/commands-close.js +0 -273
  79. package/dist/commands-close.js.map +0 -1
  80. package/dist/commands-config.d.ts +0 -31
  81. package/dist/commands-config.js +0 -272
  82. package/dist/commands-config.js.map +0 -1
  83. package/dist/commands-core.d.ts +0 -145
  84. package/dist/commands-core.js +0 -190
  85. package/dist/commands-core.js.map +0 -1
  86. package/dist/commands-devices.d.ts +0 -41
  87. package/dist/commands-devices.js +0 -144
  88. package/dist/commands-devices.js.map +0 -1
  89. package/dist/commands-doctor.d.ts +0 -25
  90. package/dist/commands-doctor.js +0 -1553
  91. package/dist/commands-doctor.js.map +0 -1
  92. package/dist/commands-guidance.d.ts +0 -27
  93. package/dist/commands-guidance.js +0 -150
  94. package/dist/commands-guidance.js.map +0 -1
  95. package/dist/commands-harness-context.d.ts +0 -57
  96. package/dist/commands-harness-context.js +0 -102
  97. package/dist/commands-harness-context.js.map +0 -1
  98. package/dist/commands-hook-attend.d.ts +0 -70
  99. package/dist/commands-hook-attend.js +0 -655
  100. package/dist/commands-hook-attend.js.map +0 -1
  101. package/dist/commands-hook-diagnostics.d.ts +0 -37
  102. package/dist/commands-hook-diagnostics.js +0 -136
  103. package/dist/commands-hook-diagnostics.js.map +0 -1
  104. package/dist/commands-hook-install.d.ts +0 -26
  105. package/dist/commands-hook-install.js +0 -784
  106. package/dist/commands-hook-install.js.map +0 -1
  107. package/dist/commands-hook-run.d.ts +0 -29
  108. package/dist/commands-hook-run.js +0 -933
  109. package/dist/commands-hook-run.js.map +0 -1
  110. package/dist/commands-hook-shape.d.ts +0 -19
  111. package/dist/commands-hook-shape.js +0 -48
  112. package/dist/commands-hook-shape.js.map +0 -1
  113. package/dist/commands-init.d.ts +0 -42
  114. package/dist/commands-init.js +0 -901
  115. package/dist/commands-init.js.map +0 -1
  116. package/dist/commands-io.d.ts +0 -2
  117. package/dist/commands-io.js +0 -117
  118. package/dist/commands-io.js.map +0 -1
  119. package/dist/commands-logs.d.ts +0 -30
  120. package/dist/commands-logs.js +0 -201
  121. package/dist/commands-logs.js.map +0 -1
  122. package/dist/commands-native-acknowledge.d.ts +0 -8
  123. package/dist/commands-native-acknowledge.js +0 -114
  124. package/dist/commands-native-acknowledge.js.map +0 -1
  125. package/dist/commands-project.d.ts +0 -4
  126. package/dist/commands-project.js +0 -41
  127. package/dist/commands-project.js.map +0 -1
  128. package/dist/commands-receive.d.ts +0 -3
  129. package/dist/commands-receive.js +0 -59
  130. package/dist/commands-receive.js.map +0 -1
  131. package/dist/commands-send-support.d.ts +0 -59
  132. package/dist/commands-send-support.js +0 -258
  133. package/dist/commands-send-support.js.map +0 -1
  134. package/dist/commands-send.d.ts +0 -34
  135. package/dist/commands-send.js +0 -900
  136. package/dist/commands-send.js.map +0 -1
  137. package/dist/commands-setup-proof.d.ts +0 -43
  138. package/dist/commands-setup-proof.js +0 -134
  139. package/dist/commands-setup-proof.js.map +0 -1
  140. package/dist/commands-skill.d.ts +0 -21
  141. package/dist/commands-skill.js +0 -199
  142. package/dist/commands-skill.js.map +0 -1
  143. package/dist/commands-sounds.d.ts +0 -12
  144. package/dist/commands-sounds.js +0 -35
  145. package/dist/commands-sounds.js.map +0 -1
  146. package/dist/commands-update-check.d.ts +0 -6
  147. package/dist/commands-update-check.js +0 -102
  148. package/dist/commands-update-check.js.map +0 -1
  149. package/dist/commands-update-resume.d.ts +0 -7
  150. package/dist/commands-update-resume.js +0 -143
  151. package/dist/commands-update-resume.js.map +0 -1
  152. package/dist/commands-update-skill.d.ts +0 -5
  153. package/dist/commands-update-skill.js +0 -36
  154. package/dist/commands-update-skill.js.map +0 -1
  155. package/dist/commands-update.d.ts +0 -11
  156. package/dist/commands-update.js +0 -286
  157. package/dist/commands-update.js.map +0 -1
  158. package/dist/commands.d.ts +0 -26
  159. package/dist/commands.js +0 -27
  160. package/dist/commands.js.map +0 -1
  161. package/dist/config-schema.d.ts +0 -62
  162. package/dist/config-schema.js +0 -302
  163. package/dist/config-schema.js.map +0 -1
  164. package/dist/config.d.ts +0 -181
  165. package/dist/config.js +0 -357
  166. package/dist/config.js.map +0 -1
  167. package/dist/credentials.d.ts +0 -96
  168. package/dist/credentials.js +0 -342
  169. package/dist/credentials.js.map +0 -1
  170. package/dist/file-lock.d.ts +0 -34
  171. package/dist/file-lock.js +0 -367
  172. package/dist/file-lock.js.map +0 -1
  173. package/dist/generated-session-label.d.ts +0 -2
  174. package/dist/generated-session-label.js +0 -152
  175. package/dist/generated-session-label.js.map +0 -1
  176. package/dist/guidance-content.d.ts +0 -53
  177. package/dist/guidance-content.js +0 -248
  178. package/dist/guidance-content.js.map +0 -1
  179. package/dist/guidance-render.d.ts +0 -25
  180. package/dist/guidance-render.js +0 -47
  181. package/dist/guidance-render.js.map +0 -1
  182. package/dist/guidance.d.ts +0 -69
  183. package/dist/guidance.js +0 -173
  184. package/dist/guidance.js.map +0 -1
  185. package/dist/harness-session-title.d.ts +0 -22
  186. package/dist/harness-session-title.js +0 -74
  187. package/dist/harness-session-title.js.map +0 -1
  188. package/dist/harnesses.d.ts +0 -65
  189. package/dist/harnesses.js +0 -159
  190. package/dist/harnesses.js.map +0 -1
  191. package/dist/hermes-attendant.d.ts +0 -38
  192. package/dist/hermes-attendant.js +0 -337
  193. package/dist/hermes-attendant.js.map +0 -1
  194. package/dist/hermes-plugin.d.ts +0 -11
  195. package/dist/hermes-plugin.js +0 -299
  196. package/dist/hermes-plugin.js.map +0 -1
  197. package/dist/hook-acknowledgements.d.ts +0 -70
  198. package/dist/hook-acknowledgements.js +0 -490
  199. package/dist/hook-acknowledgements.js.map +0 -1
  200. package/dist/hook-adapter.d.ts +0 -48
  201. package/dist/hook-adapter.js +0 -419
  202. package/dist/hook-adapter.js.map +0 -1
  203. package/dist/hook-events.d.ts +0 -105
  204. package/dist/hook-events.js +0 -130
  205. package/dist/hook-events.js.map +0 -1
  206. package/dist/hook-gates.d.ts +0 -7
  207. package/dist/hook-gates.js +0 -20
  208. package/dist/hook-gates.js.map +0 -1
  209. package/dist/hook-input.d.ts +0 -10
  210. package/dist/hook-input.js +0 -64
  211. package/dist/hook-input.js.map +0 -1
  212. package/dist/hook-lifecycle.d.ts +0 -112
  213. package/dist/hook-lifecycle.js +0 -2031
  214. package/dist/hook-lifecycle.js.map +0 -1
  215. package/dist/hook-project-sessions.d.ts +0 -28
  216. package/dist/hook-project-sessions.js +0 -141
  217. package/dist/hook-project-sessions.js.map +0 -1
  218. package/dist/hook-question-lock.d.ts +0 -29
  219. package/dist/hook-question-lock.js +0 -217
  220. package/dist/hook-question-lock.js.map +0 -1
  221. package/dist/hook-question-retirement.d.ts +0 -74
  222. package/dist/hook-question-retirement.js +0 -314
  223. package/dist/hook-question-retirement.js.map +0 -1
  224. package/dist/hook-question-state.d.ts +0 -58
  225. package/dist/hook-question-state.js +0 -239
  226. package/dist/hook-question-state.js.map +0 -1
  227. package/dist/hook-session-state.d.ts +0 -127
  228. package/dist/hook-session-state.js +0 -488
  229. package/dist/hook-session-state.js.map +0 -1
  230. package/dist/hook-types.d.ts +0 -476
  231. package/dist/hook-types.js +0 -4
  232. package/dist/hook-types.js.map +0 -1
  233. package/dist/injection-render.d.ts +0 -36
  234. package/dist/injection-render.js +0 -61
  235. package/dist/injection-render.js.map +0 -1
  236. package/dist/install-hooks.d.ts +0 -470
  237. package/dist/install-hooks.js +0 -1622
  238. package/dist/install-hooks.js.map +0 -1
  239. package/dist/integration-health.d.ts +0 -26
  240. package/dist/integration-health.js +0 -133
  241. package/dist/integration-health.js.map +0 -1
  242. package/dist/interactive.d.ts +0 -22
  243. package/dist/interactive.js +0 -644
  244. package/dist/interactive.js.map +0 -1
  245. package/dist/invocation-context.d.ts +0 -47
  246. package/dist/invocation-context.js +0 -164
  247. package/dist/invocation-context.js.map +0 -1
  248. package/dist/local-path.d.ts +0 -7
  249. package/dist/local-path.js +0 -27
  250. package/dist/local-path.js.map +0 -1
  251. package/dist/logging.d.ts +0 -157
  252. package/dist/logging.js +0 -599
  253. package/dist/logging.js.map +0 -1
  254. package/dist/main-run.d.ts +0 -1
  255. package/dist/main-run.js +0 -42
  256. package/dist/main-run.js.map +0 -1
  257. package/dist/main.d.ts +0 -2
  258. package/dist/main.js +0 -12
  259. package/dist/main.js.map +0 -1
  260. package/dist/native-answer-operation.d.ts +0 -70
  261. package/dist/native-answer-operation.js +0 -247
  262. package/dist/native-answer-operation.js.map +0 -1
  263. package/dist/native-skills.d.ts +0 -64
  264. package/dist/native-skills.js +0 -167
  265. package/dist/native-skills.js.map +0 -1
  266. package/dist/node-floor.d.ts +0 -19
  267. package/dist/node-floor.js +0 -32
  268. package/dist/node-floor.js.map +0 -1
  269. package/dist/npm-invocation.d.ts +0 -34
  270. package/dist/npm-invocation.js +0 -53
  271. package/dist/npm-invocation.js.map +0 -1
  272. package/dist/openclaw-continuation-bridge.d.ts +0 -7
  273. package/dist/openclaw-continuation-bridge.js +0 -64
  274. package/dist/openclaw-continuation-bridge.js.map +0 -1
  275. package/dist/openclaw-gateway-readiness.d.ts +0 -1
  276. package/dist/openclaw-gateway-readiness.js +0 -24
  277. package/dist/openclaw-gateway-readiness.js.map +0 -1
  278. package/dist/openclaw-generation.d.ts +0 -21
  279. package/dist/openclaw-generation.js +0 -115
  280. package/dist/openclaw-generation.js.map +0 -1
  281. package/dist/openclaw-message-bridge.d.ts +0 -8
  282. package/dist/openclaw-message-bridge.js +0 -93
  283. package/dist/openclaw-message-bridge.js.map +0 -1
  284. package/dist/openclaw-pending.d.ts +0 -8
  285. package/dist/openclaw-pending.js +0 -47
  286. package/dist/openclaw-pending.js.map +0 -1
  287. package/dist/openclaw-plugin.d.ts +0 -75
  288. package/dist/openclaw-plugin.js +0 -1353
  289. package/dist/openclaw-plugin.js.map +0 -1
  290. package/dist/openclaw-session-access.d.ts +0 -12
  291. package/dist/openclaw-session-access.js +0 -79
  292. package/dist/openclaw-session-access.js.map +0 -1
  293. package/dist/opencode-plugin.d.ts +0 -88
  294. package/dist/opencode-plugin.js +0 -286
  295. package/dist/opencode-plugin.js.map +0 -1
  296. package/dist/orca-session-title.d.ts +0 -11
  297. package/dist/orca-session-title.js +0 -111
  298. package/dist/orca-session-title.js.map +0 -1
  299. package/dist/pack-feedback-slice.d.ts +0 -35
  300. package/dist/pack-feedback-slice.js +0 -126
  301. package/dist/pack-feedback-slice.js.map +0 -1
  302. package/dist/pairing-qr.d.ts +0 -5
  303. package/dist/pairing-qr.js +0 -24
  304. package/dist/pairing-qr.js.map +0 -1
  305. package/dist/pending-pairing.d.ts +0 -38
  306. package/dist/pending-pairing.js +0 -70
  307. package/dist/pending-pairing.js.map +0 -1
  308. package/dist/platform.d.ts +0 -67
  309. package/dist/platform.js +0 -140
  310. package/dist/platform.js.map +0 -1
  311. package/dist/process-identity.d.ts +0 -26
  312. package/dist/process-identity.js +0 -82
  313. package/dist/process-identity.js.map +0 -1
  314. package/dist/program.d.ts +0 -59
  315. package/dist/program.js +0 -691
  316. package/dist/program.js.map +0 -1
  317. package/dist/project-enablement.d.ts +0 -21
  318. package/dist/project-enablement.js +0 -71
  319. package/dist/project-enablement.js.map +0 -1
  320. package/dist/question-settlement-process.d.ts +0 -17
  321. package/dist/question-settlement-process.js +0 -35
  322. package/dist/question-settlement-process.js.map +0 -1
  323. package/dist/question-timing.d.ts +0 -46
  324. package/dist/question-timing.js +0 -48
  325. package/dist/question-timing.js.map +0 -1
  326. package/dist/readiness.d.ts +0 -153
  327. package/dist/readiness.js +0 -149
  328. package/dist/readiness.js.map +0 -1
  329. package/dist/release.d.ts +0 -31
  330. package/dist/release.js +0 -52
  331. package/dist/release.js.map +0 -1
  332. package/dist/send-attempts.d.ts +0 -26
  333. package/dist/send-attempts.js +0 -139
  334. package/dist/send-attempts.js.map +0 -1
  335. package/dist/send.d.ts +0 -115
  336. package/dist/send.js +0 -421
  337. package/dist/send.js.map +0 -1
  338. package/dist/session-activation.d.ts +0 -13
  339. package/dist/session-activation.js +0 -64
  340. package/dist/session-activation.js.map +0 -1
  341. package/dist/session-attendant-probe.d.ts +0 -85
  342. package/dist/session-attendant-probe.js +0 -173
  343. package/dist/session-attendant-probe.js.map +0 -1
  344. package/dist/session-attendant-state.d.ts +0 -70
  345. package/dist/session-attendant-state.js +0 -256
  346. package/dist/session-attendant-state.js.map +0 -1
  347. package/dist/session-attendant.d.ts +0 -143
  348. package/dist/session-attendant.js +0 -520
  349. package/dist/session-attendant.js.map +0 -1
  350. package/dist/session-delivery.d.ts +0 -249
  351. package/dist/session-delivery.js +0 -576
  352. package/dist/session-delivery.js.map +0 -1
  353. package/dist/session-handoff.d.ts +0 -98
  354. package/dist/session-handoff.js +0 -118
  355. package/dist/session-handoff.js.map +0 -1
  356. package/dist/session-input-wakes.d.ts +0 -78
  357. package/dist/session-input-wakes.js +0 -239
  358. package/dist/session-input-wakes.js.map +0 -1
  359. package/dist/session-inputs.d.ts +0 -57
  360. package/dist/session-inputs.js +0 -434
  361. package/dist/session-inputs.js.map +0 -1
  362. package/dist/session-labels.d.ts +0 -56
  363. package/dist/session-labels.js +0 -396
  364. package/dist/session-labels.js.map +0 -1
  365. package/dist/session-message-handoff.d.ts +0 -39
  366. package/dist/session-message-handoff.js +0 -107
  367. package/dist/session-message-handoff.js.map +0 -1
  368. package/dist/setup-destinations.d.ts +0 -23
  369. package/dist/setup-destinations.js +0 -44
  370. package/dist/setup-destinations.js.map +0 -1
  371. package/dist/skill-integrity.d.ts +0 -54
  372. package/dist/skill-integrity.js +0 -164
  373. package/dist/skill-integrity.js.map +0 -1
  374. package/dist/skill-source/manifest.json +0 -40
  375. package/dist/skill-source/notifai/SKILL.md +0 -350
  376. package/dist/skill-source/notifai/references/diagnostics.md +0 -36
  377. package/dist/skill-source/notifai/references/harness-setup.md +0 -384
  378. package/dist/skill-source/notifai/references/native-questions.md +0 -51
  379. package/dist/skill-source/notifai/references/notes-and-edits.md +0 -54
  380. package/dist/skill-source/notifai/references/send-details.md +0 -14
  381. package/dist/skill-source/notifai/references/updates.md +0 -116
  382. package/dist/skill-source/notifai/references/writing-examples.md +0 -56
  383. package/dist/sound-ref.d.ts +0 -23
  384. package/dist/sound-ref.js +0 -28
  385. package/dist/sound-ref.js.map +0 -1
  386. package/dist/ui/banner.d.ts +0 -22
  387. package/dist/ui/banner.js +0 -87
  388. package/dist/ui/banner.js.map +0 -1
  389. package/dist/ui/config-view.d.ts +0 -30
  390. package/dist/ui/config-view.js +0 -108
  391. package/dist/ui/config-view.js.map +0 -1
  392. package/dist/ui/help.d.ts +0 -44
  393. package/dist/ui/help.js +0 -107
  394. package/dist/ui/help.js.map +0 -1
  395. package/dist/ui/theme.d.ts +0 -90
  396. package/dist/ui/theme.js +0 -244
  397. package/dist/ui/theme.js.map +0 -1
  398. package/dist/update-handoff.d.ts +0 -29
  399. package/dist/update-handoff.js +0 -69
  400. package/dist/update-handoff.js.map +0 -1
  401. package/dist/url-policy.d.ts +0 -85
  402. package/dist/url-policy.js +0 -369
  403. package/dist/url-policy.js.map +0 -1
  404. package/dist/version.d.ts +0 -40
  405. package/dist/version.js +0 -132
  406. package/dist/version.js.map +0 -1
  407. package/dist/wake-support.d.ts +0 -40
  408. package/dist/wake-support.js +0 -95
  409. package/dist/wake-support.js.map +0 -1
package/dist/program.js DELETED
@@ -1,691 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { Command } from 'commander';
3
- import { acknowledgeCommand, receiveCommand, askCommand, accessStatusCommand, agentSessionRenameCommand, authStatusCommand, capabilitiesCommand, closeCommand, cliUpdateCommand, cliUpdateCheckCommand, updateSkillCommand, updateResumeCommand, configExplainCommand, configSetCommand, configShowCommand, configUnsetCommand, devicesCommand, doctorCommand, guidanceSetCommand, guidanceShowCommand, guidanceUnsetCommand, hookDefersDiagnosticsUntilAfterCleanup, hookRunCommand, hooksInstallCommand, hooksUninstallCommand, initCommand, loginCommand, logoutCommand, projectDisableCommand, projectEnableCommand, projectStatusCommand, logsCommand, repliesCommand, reportAskFailure, sendCommand, soundsCommand, statusCommand, } from './commands.js';
4
- import { packageVersion } from './release.js';
5
- import { HOOK_INSTALLABLE_HARNESSES } from './harnesses.js';
6
- import { GROUP, SEND_GROUP, helpConfiguration, rootHelpFooter } from './ui/help.js';
7
- import { readStdinWithTimeout } from './hook-input.js';
8
- import { argvFlagNames } from './logging.js';
9
- import { QUESTION_SETTLEMENT_INPUT_ENV } from './question-settlement-process.js';
10
- import { resumeAttendantCommand } from './attendant-update.js';
11
- /**
12
- * One source of truth for the version: the manifest npm actually published.
13
- *
14
- * It was hardcoded here as well, and the first patch release proved why that
15
- * does not hold — `package.json` moved and `notifai --version` kept reporting
16
- * the old number, which is exactly the string someone pastes into a bug report
17
- * to say what they are running.
18
- *
19
- * `unknown` is the display form of "this build cannot tell"; the skill pin
20
- * derived from the same source refuses instead, because a wrong ref installs
21
- * the wrong thing while a wrong version string only misinforms.
22
- */
23
- function version() {
24
- return packageVersion() ?? 'unknown';
25
- }
26
- /**
27
- * The full command path, e.g. `config set`, so a filter on `cmd` distinguishes
28
- * subcommands that share a leaf name.
29
- */
30
- function commandPath(command) {
31
- const parts = [];
32
- for (let node = command; node?.parent != null; node = node.parent) {
33
- parts.unshift(node.name());
34
- }
35
- return parts.join(' ') || 'notifai';
36
- }
37
- /**
38
- * Every command implementation the tree dispatches to, injectable so a test
39
- * can parse real argv and assert the exact flags a command would receive —
40
- * the layer where `--no-wait` disentangling and collector defaults live, which
41
- * unit tests on the commands themselves can never see.
42
- */
43
- const defaultRunners = {
44
- init: initCommand,
45
- doctor: doctorCommand,
46
- update: cliUpdateCommand,
47
- updateCheck: cliUpdateCheckCommand,
48
- updateSkill: updateSkillCommand,
49
- updateResume: updateResumeCommand,
50
- login: loginCommand,
51
- logout: logoutCommand,
52
- authStatus: authStatusCommand,
53
- accessStatus: accessStatusCommand,
54
- devices: devicesCommand,
55
- sounds: soundsCommand,
56
- capabilities: capabilitiesCommand,
57
- projectEnable: projectEnableCommand,
58
- projectDisable: projectDisableCommand,
59
- projectStatus: projectStatusCommand,
60
- agentSessionRename: agentSessionRenameCommand,
61
- send: sendCommand,
62
- replies: repliesCommand,
63
- acknowledge: acknowledgeCommand,
64
- receive: receiveCommand,
65
- status: statusCommand,
66
- ask: askCommand,
67
- close: closeCommand,
68
- hookRun: hookRunCommand,
69
- hooksInstall: hooksInstallCommand,
70
- hooksUninstall: hooksUninstallCommand,
71
- logs: logsCommand,
72
- configShow: configShowCommand,
73
- configExplain: configExplainCommand,
74
- configSet: configSetCommand,
75
- configUnset: configUnsetCommand,
76
- guidanceShow: guidanceShowCommand,
77
- guidanceSet: guidanceSetCommand,
78
- guidanceUnset: guidanceUnsetCommand,
79
- /**
80
- * Dynamic so that the prompt library, the banner and the whole interactive
81
- * tree cost nothing to the paths that never draw them — `send`, `ask`, and
82
- * the hook that runs in front of every prompt the user types.
83
- */
84
- interactive: async (deps, versionString) => {
85
- const { interactiveCommand } = await import('./interactive.js');
86
- return interactiveCommand(deps, versionString);
87
- },
88
- };
89
- export function buildProgram(deps, options = {}) {
90
- const exit = options.exit ?? ((code) => process.exit(code));
91
- const runners = { ...defaultRunners, ...options.runners };
92
- const logger = deps.logger;
93
- const program = new Command('notifai')
94
- .description('Send native device notifications from agents and local programs')
95
- .version(version())
96
- .configureHelp(helpConfiguration)
97
- // Lazy on purpose. `addHelpText` also takes a string, but that builds the
98
- // footer on every invocation — including the hook that runs in front of
99
- // every prompt the user types, which never renders help at all.
100
- .addHelpText('after', () => rootHelpFooter())
101
- // Commander's default is to print the full help and exit 0 for an unknown
102
- // `help` topic, so `notifai help nonsense` looked like it had worked. A
103
- // reader who mistyped a command deserves to be told, and a script deserves
104
- // a nonzero code.
105
- .showSuggestionAfterError(true)
106
- // Commander drops the implicit `help [command]` as soon as the program
107
- // itself has an action handler — which the interactive default below gives
108
- // it. Without this, adding that default would silently break
109
- // `notifai help send` for everyone who reaches for it before `--help`.
110
- .helpCommand(true)
111
- .hook('preAction', (_program, actionCommand) => {
112
- logger?.bind({ cmd: commandPath(actionCommand) });
113
- // SessionEnd uses the hook policy shared with commands.ts: local cleanup
114
- // precedes every diagnostic that can wait on the shared log lock.
115
- const deferDiagnostics = actionCommand.name() === 'hook' &&
116
- hookDefersDiagnosticsUntilAfterCleanup(actionCommand.processedArgs[0]);
117
- // Values only at `debug`; `cli.end` carries the flag names at every level.
118
- if (!deferDiagnostics) {
119
- logger?.debug('cli.start', {
120
- version: version(),
121
- flags: argvFlagNames(process.argv.slice(2)),
122
- cwd: process.cwd(),
123
- });
124
- }
125
- });
126
- /**
127
- * Commander exits 1 for every usage error it detects itself, which contradicts
128
- * the exit vocabulary this CLI documents and every hand-written usage error it
129
- * returns. A caller branching on exit codes should not have to know which layer
130
- * rejected it. Help and version stay successful.
131
- */
132
- program.exitOverride((err) => {
133
- exit(err.exitCode === 0 ? 0 : 2);
134
- });
135
- /**
136
- * Bare `notifai`.
137
- *
138
- * At a human terminal this opens the interactive app, which enters `init`
139
- * when the machine is not yet paired and otherwise offers daily actions.
140
- * Anywhere else it prints help exactly as before. The check is the same one
141
- * every other prompt in this CLI is gated on — stdin and stdout both TTYs,
142
- * not CI, `NOTIFAI_NO_INPUT` unset — because an agent that reaches a prompt
143
- * does not fail, it hangs for ever waiting on a stdin nobody is typing into.
144
- */
145
- /**
146
- * An unrecognised subcommand reaches the root as an excess argument, and
147
- * "expected 0 arguments but got 1" tells a caller nothing about what it typed
148
- * or what exists. Naming it — with the nearest real command when there is one —
149
- * turns a dead end into one more try.
150
- */
151
- program.usage('[options] [command]');
152
- program.argument('[command]').action(async (command) => {
153
- if (command !== undefined) {
154
- const names = program.commands.map((cmd) => cmd.name());
155
- const near = names.filter((name) => name.startsWith(command.slice(0, 2)) ||
156
- command.startsWith(name.slice(0, 2)) ||
157
- name.includes(command) ||
158
- command.includes(name));
159
- deps.io.err(`Unknown command "${command}".` +
160
- (near.length > 0 ? ` Did you mean: ${near.slice(0, 3).join(', ')}?` : '') +
161
- ' Run notifai --help for the full list.');
162
- return exit(2);
163
- }
164
- if (deps.io.interactive !== true) {
165
- program.outputHelp();
166
- return;
167
- }
168
- exit(await runners.interactive(deps, version()));
169
- });
170
- // Setup leads: `init` is the single entry command for first-run friendliness.
171
- program
172
- .command('init')
173
- .helpGroup(GROUP.start)
174
- .summary('Set this project up, step by step')
175
- .description('Set up Notifai here, idempotently: sign-in, project id, hooks, device readiness, live receipt proof. ' +
176
- 'Interactive at a human terminal; never prompts otherwise (agents: pass flags)')
177
- .option('--project-id <id>', 'Project identifier slug (default: derived from the directory name)')
178
- .option('--json', 'machine-readable final readiness; never prompts')
179
- .option('--approval <route>', 'computer approval route: qr (default), notification, or browser')
180
- .option('--approval-email <email>', 'Account email for the selected notification approval route')
181
- .option('--skills', 'install/update the agent skill from its pinned public release')
182
- .option('--no-skills', 'suppress the optional agent-skill status line')
183
- .option('--skills-scope <scope>', 'unattended agent-skill scope: project or global. Lifecycle wiring has no scope — it is installed for this machine')
184
- .option('--hooks', 'install supported harness lifecycle hooks')
185
- .option('--no-hooks', 'skip the hooks without being asked')
186
- .action(async (opts) => {
187
- exit(await runners.init(deps, opts));
188
- });
189
- program
190
- .command('doctor')
191
- .helpGroup(GROUP.daily)
192
- .summary('Check every part of the setup')
193
- .description('Audit config, credential, server, contract, device, hook, and saved receipt proof; exits nonzero when any line is FAIL (no live send)')
194
- .option('--json', 'machine-readable output')
195
- .action(async (opts) => {
196
- exit(await runners.doctor(deps, opts));
197
- });
198
- program
199
- .command('update')
200
- .helpGroup(GROUP.start)
201
- .summary('Update the Notifai command this shell uses')
202
- .description('Update the effective global Notifai installation and keep Question Routing on it')
203
- .option('--json', 'machine-readable installation and session handoff')
204
- .option('--check', 'inspect release notes, guidance, and session effects without installing')
205
- .option('--refresh-skill', 'refresh the existing skill scope without login, hooks, or delivery setup')
206
- .option('--resume', 'finish integration in the existing installation without reinstalling or changing channel')
207
- .option('--channel <channel>', 'choose stable or beta; explicit stable can switch from a newer beta (default: stable)')
208
- .option('--from <version>', 'show installed changelog entries after this version (requires --check or --resume)')
209
- .action(async (opts) => {
210
- if (opts.channel !== undefined && opts.channel !== 'stable' && opts.channel !== 'beta') {
211
- deps.io.err('--channel must be stable or beta');
212
- exit(2);
213
- return;
214
- }
215
- if (opts.channel !== undefined && (opts.check || opts.resume || opts.refreshSkill || opts.from !== undefined)) {
216
- deps.io.err('--channel can only be used when installing an update');
217
- exit(2);
218
- return;
219
- }
220
- if ((opts.refreshSkill && (opts.check || opts.resume || opts.from !== undefined)) || (opts.resume && opts.check)) {
221
- deps.io.err('Choose only one of --check, --resume, or --refresh-skill; --from is available with --check or --resume');
222
- exit(2);
223
- return;
224
- }
225
- if (opts.from !== undefined && opts.check !== true && opts.resume !== true) {
226
- deps.io.err('--from requires --check or --resume');
227
- exit(2);
228
- return;
229
- }
230
- exit(opts.resume ? await runners.updateResume(deps, opts) : opts.refreshSkill ? await runners.updateSkill(deps, opts) : opts.check ? await runners.updateCheck(deps, opts) : runners.update(deps, opts));
231
- });
232
- // Owned updater subprocess; never an agent-facing lifecycle or session-creation API.
233
- program.command('attendant-resume <session-id> <incarnation-key>', { hidden: true })
234
- .action(async (sessionId, key) => { exit(await resumeAttendantCommand(deps, sessionId, key)); });
235
- const project = program
236
- .command('project')
237
- .helpGroup(GROUP.daily)
238
- .summary('Control Notifai for this Project')
239
- .description('Inspect or change this Project\'s User-owned lifecycle enablement');
240
- project.command('enable').description('Enable lifecycle guidance for this Project').action(() => {
241
- exit(runners.projectEnable(deps));
242
- });
243
- project.command('disable').description('Disable lifecycle guidance for this Project').action(() => {
244
- exit(runners.projectDisable(deps));
245
- });
246
- project.command('status').description('Show lifecycle enablement for this Project').option('--json').action((opts) => {
247
- exit(runners.projectStatus(deps, opts.json === true));
248
- });
249
- const session = program
250
- .command('session')
251
- .helpGroup(GROUP.agent)
252
- .summary('Inspect or rename the current Agent Session')
253
- .description('Operate on the exact Agent Session owned by the active harness');
254
- session
255
- .command('rename <label>')
256
- .description('Rename this exact Agent Session; agents use this only after its job changes completely enough that the old label would mislead')
257
- .option('--json', 'machine-readable output')
258
- .action(async (label, opts) => {
259
- exit(await runners.agentSessionRename(deps, label, opts));
260
- });
261
- program
262
- .command('login')
263
- .helpGroup(GROUP.advanced)
264
- .summary('Sign in and pair this machine')
265
- .description('Connect this computer by QR, approval notification, or browser approval')
266
- .option('--name <name>', 'machine name shown in the dashboard (default: hostname)')
267
- .option('--base-url <url>', 'pairing override for the service origin (also NOTIFAI_BASE_URL)')
268
- .option('--approval <route>', 'computer approval route: qr (default), notification, or browser')
269
- .option('--approval-email <email>', 'Account email for the selected notification approval route')
270
- .option('--no-open', 'do not open the approval page in a browser')
271
- .action(async (opts) => {
272
- exit(await runners.login(deps, opts));
273
- });
274
- program
275
- .command('logout')
276
- .helpGroup(GROUP.advanced)
277
- .summary('Remove the stored machine credential')
278
- .description('Remove the stored machine credential')
279
- .action(() => {
280
- exit(runners.logout(deps));
281
- });
282
- const auth = program
283
- .command('auth')
284
- .description('Authentication helpers')
285
- .summary('Machine identity and account plan')
286
- .helpGroup(GROUP.advanced);
287
- auth
288
- .command('status')
289
- .description('Show the stored machine identity')
290
- .option('--json', 'machine-readable output')
291
- .action((opts) => {
292
- exit(runners.authStatus(deps, opts));
293
- });
294
- auth
295
- .command('access')
296
- .description('Show the account plan and access decision')
297
- .option('--json', 'machine-readable output')
298
- .action(async (opts) => {
299
- exit(await runners.accessStatus(deps, opts));
300
- });
301
- program
302
- .command('devices')
303
- .helpGroup(GROUP.daily)
304
- .summary('List your devices and whether they can receive')
305
- .description('List registered devices and their delivery readiness')
306
- .option('--platform <platform>', 'show only devices on one supported platform')
307
- .option('--json', 'machine-readable output')
308
- .action(async (opts) => {
309
- exit(await runners.devices(deps, opts));
310
- });
311
- program
312
- .command('sounds')
313
- .helpGroup(GROUP.daily)
314
- .summary('List shipped and Account custom sounds')
315
- .description('List the sounds --sound and the saved sound key accept: shipped names and this Account\'s custom sounds')
316
- .option('--json', 'machine-readable output')
317
- .action(async (opts) => {
318
- exit(await runners.sounds(deps, opts));
319
- });
320
- program
321
- .command('capabilities')
322
- .helpGroup(GROUP.advanced)
323
- .summary('Show what a platform can render')
324
- .description('Show a platform capability contract')
325
- .option('--platform <platform>', 'platform to describe (default: ios)')
326
- .option('--json', 'machine-readable output')
327
- .action(async (opts) => {
328
- exit(await runners.capabilities(deps, opts));
329
- });
330
- const send = program
331
- .command('send')
332
- .helpGroup(GROUP.agent)
333
- .summary('Send a notification')
334
- .description('Send a notification')
335
- .optionsGroup(SEND_GROUP.content)
336
- .requiredOption('--title <title>', 'brief title whose substance is immediately understandable')
337
- .requiredOption('--summary <text>', 'short one-line plain-text summary for banners and lists')
338
- .option('--body <markdown>', 'optional standalone Markdown body for focused detail')
339
- .option('--body-file <path>', 'read the optional standalone Markdown body from a file (use - for stdin)')
340
- .option('--literal-backslash-n', 'allow the two-character sequence \\n in --body instead of treating it as a mistaken escaped newline')
341
- .option('--image <path|url|media_id>', 'upload or attach an image in collection order (repeatable, maximum 8)', (v, all = []) => [...all, v])
342
- .option('--image-alt <text>', 'alt text paired with --image occurrences by position (repeatable)', (v, all = []) => [...all, v])
343
- .optionsGroup(SEND_GROUP.routing)
344
- .option('--kind <kind>', 'what this is (required): update | done | failed | blocked (no User reply would resume it) — question is set by --reply')
345
- .option('--project <id>', 'Project identifier override (otherwise configured or inferred)')
346
- .option('--projectless', 'deliberately omit Project identity for this notification')
347
- .option('--device <id>', 'target a device id (repeatable)', (v, all = []) => [...all, v])
348
- .option('--all', 'target all routable devices (overrides configured devices)')
349
- .option('--session-id <id>', 'low-level automation override for an opaque exact Agent Session (env: NOTIFAI_SESSION_ID)')
350
- .option('--session-label <text>', 'initial Agent Session name; repeat the same name, use session rename for a changed job (env: NOTIFAI_SESSION_LABEL)')
351
- .optionsGroup(SEND_GROUP.presentation)
352
- .option('--collapse-key <key>', 'replace earlier notifications with the same key')
353
- .option('--thread-id <id>', 'group related notifications')
354
- .option('--ttl <seconds>', 'delivery window in seconds', (v) => Number(v))
355
- .option('--platform <platform>', 'limit optional fields to one supported platform')
356
- .optionsGroup(SEND_GROUP.reply)
357
- .option('--reply', 'enable the inline reply action and block for the answer')
358
- .option('--reply-timeout <seconds>', 'how long to wait for a reply (default: 900)', (v) => Number(v))
359
- .option('--reply-window <seconds>', 'how long an answer is still accepted, 60-259200 (default: reply_window_seconds, a day)', (v) => Number(v))
360
- .option('--choice <label>', 'with --reply, ask a closed question; repeat the flag once per answer (2-6)', (v, all = []) => [...all, v])
361
- .option('--multi', 'with --choice, several answers may be selected')
362
- .optionsGroup(SEND_GROUP.advanced)
363
- .option('--sound <sound>', 'override saved sound: default | done | attention | alert | none, or a custom name or id from notifai sounds')
364
- .option('--level <level>', 'Apple-only interruption level: passive | active | time_sensitive (unsupported with --platform android)')
365
- .option('--wait <seconds>', 'how long to wait for provider outcomes', (v) => Number(v))
366
- .option('--no-wait', 'return immediately after acceptance')
367
- .option('--data <key=value>', 'custom data (repeatable)', (v, all = []) => [...all, v])
368
- .option('--idempotency-key <key>', 'safe-retry key (default: random)')
369
- .option('--retry', 'explicitly retry one unresolved exact semantic send using its opaque saved attempt')
370
- .option('--base-url <url>', 'pairing override for the service origin; ignored when this machine is already paired (also NOTIFAI_BASE_URL)')
371
- .option('--json', 'print the full submission receipt as JSON')
372
- .action(async (opts) => {
373
- // commander maps --no-wait onto the same "wait" flag; disentangle.
374
- const noWait = opts['wait'] === false;
375
- const wait = typeof opts['wait'] === 'number' ? opts['wait'] : undefined;
376
- const sendOpts = { ...opts };
377
- // Commander collectors default to []; an empty list means "not passed".
378
- for (const key of ['choice', 'image', 'imageAlt']) {
379
- if (Array.isArray(sendOpts[key]) && sendOpts[key].length === 0)
380
- delete sendOpts[key];
381
- }
382
- const bodyFile = sendOpts['bodyFile'];
383
- delete sendOpts['bodyFile'];
384
- if (typeof bodyFile === 'string') {
385
- if (sendOpts['body'] !== undefined) {
386
- deps.io.err('Pass either --body or --body-file, not both.');
387
- return exit(2);
388
- }
389
- try {
390
- sendOpts['body'] = readFileSync(bodyFile === '-' ? 0 : bodyFile, 'utf8');
391
- }
392
- catch (err) {
393
- deps.io.err(`Could not read ${bodyFile}: ${String(err)}`);
394
- return exit(2);
395
- }
396
- }
397
- const flags = { ...sendOpts, noWait };
398
- if (wait === undefined)
399
- delete flags.wait;
400
- else
401
- flags.wait = wait;
402
- exit(await runners.send(deps, flags));
403
- });
404
- send.addHelpText('after', `\nKind is required, and it selects the sound the notification arrives with: done rings the completion chime, failed the most insistent tone, blocked and question a distinct attention tone, update Device default.\nAn explicit --sound or saved sound preference outranks that default. --sound accepts a shipped name, an Account custom sound name or id from \`notifai sounds\`, or none. --level is Apple-only; Android attention is owned by kind, product channels, and device settings.\n`);
405
- program
406
- .command('replies [request_id]')
407
- .helpGroup(GROUP.agent)
408
- .summary('Retrieve replies to a question')
409
- .description('Retrieve replies for a notification request')
410
- .option('--pending', 'use the pushed question pending for this Project and Agent Session')
411
- .option('--wait <seconds>', 'how long to wait for a reply', (v) => Number(v))
412
- .option('--after <seq>', 'return replies after this sequence number', (v) => Number(v))
413
- .option('--handoff', 're-present the selected answer to this exact Agent Session and record its hand-off')
414
- .option('--json', 'machine-readable output')
415
- .action(async (requestId, opts) => {
416
- exit(await runners.replies(deps, requestId, opts));
417
- });
418
- program
419
- .command('receive')
420
- .description('Read pending user input for the current Agent Session')
421
- .action(async () => { exit(await runners.receive(deps)); });
422
- program
423
- .command('acknowledge <question_request_or_message_id>')
424
- .helpGroup(GROUP.agent)
425
- .summary("Tell the user what you'll do because of their reply or note")
426
- .description('Record the required Agent Acknowledgement for a notification reply (req_…), Session Message (sm_…), or explicitly reported answer to an exactly bound native question (q_…); never prompts')
427
- .option('--text <text>', 'concrete work you will do because of the reply or message')
428
- .option('--operation-id <id>', 'native submission identity: reuse on retry, choose a new ID for a distinct answer')
429
- .option('--native-answers <json>', 'actual native answers using the registered question/choice IDs; omit only to retry a saved operation')
430
- .option('--json', 'machine-readable output')
431
- .action(async (id, opts) => {
432
- exit(await runners.acknowledge(deps, id, opts));
433
- });
434
- program
435
- .command('status <question_or_request_id>')
436
- .helpGroup(GROUP.agent)
437
- .summary('Show question state or request evidence')
438
- .description('Show local question state and, once submitted, the notification request evidence trail')
439
- .option('--json', 'machine-readable output')
440
- .action(async (requestId, opts) => {
441
- exit(await runners.status(deps, requestId, opts));
442
- });
443
- program
444
- .command('ask [question]')
445
- .helpGroup(GROUP.agent)
446
- .summary('Ask now and continue independent work')
447
- .description('Register a question and immediately start background submission, subject to your question-routing settings')
448
- .option('--choice <label>', 'answers to offer instead of free text; repeat the flag once per answer (2-6)', (v, all = []) => [...all, v])
449
- .option('--multi', 'with --choice, several answers may be selected')
450
- .option('--json', 'machine-readable output')
451
- .option('--body <markdown>', 'optional standalone Markdown body for focused detail')
452
- .option('--body-file <path>', 'read the optional standalone Markdown body from a file (use - for stdin)')
453
- .option('--literal-backslash-n', 'allow the two-character sequence \\n in --body instead of treating it as a mistaken escaped newline')
454
- .option('--form <path>', 'ask several questions as one form; JSON file (use - for stdin)')
455
- .option('--image <path|url|media_id>', 'upload or attach an image in collection order (repeatable, maximum 8)', (v, all = []) => [...all, v])
456
- .option('--image-alt <text>', 'alt text paired with --image occurrences by position (repeatable)', (v, all = []) => [...all, v])
457
- .option('--project <id>', 'Project identifier override (otherwise configured or inferred)')
458
- .option('--session-label <text>', 'initial Agent Session name; repeat the same name, use session rename for a changed job (env: NOTIFAI_SESSION_LABEL)')
459
- .action(async (question, opts) => {
460
- let body = opts.body;
461
- if (typeof opts.bodyFile === 'string') {
462
- if (body !== undefined) {
463
- return exit(reportAskFailure(deps, opts, {
464
- code: 'invalid_input', check_id: 'body', exit_code: 2,
465
- remedy: 'pass either --body or --body-file, then retry',
466
- message: 'Pass either --body or --body-file, not both.',
467
- }));
468
- }
469
- try {
470
- body = readFileSync(opts.bodyFile === '-' ? 0 : opts.bodyFile, 'utf8');
471
- }
472
- catch (err) {
473
- return exit(reportAskFailure(deps, opts, {
474
- code: 'input_unreadable', check_id: 'body_file', exit_code: 2,
475
- remedy: 'fix the body-file path or permissions, then retry',
476
- message: `Could not read ${opts.bodyFile}: ${String(err)}`,
477
- }));
478
- }
479
- }
480
- let form;
481
- if (typeof opts.form === 'string') {
482
- try {
483
- form = readFileSync(opts.form === '-' ? 0 : opts.form, 'utf8');
484
- }
485
- catch (err) {
486
- return exit(reportAskFailure(deps, opts, {
487
- code: 'input_unreadable', check_id: 'form_file', exit_code: 2,
488
- remedy: 'fix the form-file path or permissions, then retry',
489
- message: `Could not read ${opts.form}: ${String(err)}`,
490
- }));
491
- }
492
- }
493
- // Commander collectors default to []; an empty list means "not passed".
494
- const flags = {
495
- ...(opts.choice?.length ? { choice: opts.choice } : {}),
496
- ...(opts.multi ? { multi: true } : {}),
497
- ...(body !== undefined ? { body } : {}),
498
- ...(form !== undefined ? { form } : {}),
499
- ...(opts.image?.length ? { image: opts.image } : {}),
500
- ...(opts.imageAlt?.length ? { imageAlt: opts.imageAlt } : {}),
501
- ...(opts.project !== undefined ? { project: opts.project } : {}),
502
- ...(opts.sessionLabel !== undefined ? { sessionLabel: opts.sessionLabel } : {}),
503
- ...(opts.json === true ? { json: true } : {}),
504
- ...(opts.literalBackslashN === true ? { literalBackslashN: true } : {}),
505
- };
506
- exit(await runners.ask(deps, question, flags));
507
- });
508
- program
509
- .command('close [question_or_request_id]')
510
- .helpGroup(GROUP.agent)
511
- .summary('Retire a question so late answers are rejected')
512
- .description('Retire a question so late answers are rejected rather than lost. Pass --pending to withdraw this Agent Session\'s outstanding registrations, including ones Question Routing has not submitted yet.')
513
- .option('--pending', 'retire this Agent Session\'s outstanding questions, including ones not yet pushed')
514
- .option('--json', 'machine-readable output')
515
- .action(async (requestId, opts) => {
516
- exit(await runners.close(deps, requestId, opts));
517
- });
518
- // Hidden, not removed. It is an entry point the hook installer writes into a
519
- // harness config file, never something a person types — and listing it beside
520
- // `send` invited exactly one reading, which is that you were supposed to.
521
- program
522
- .command('hook <event>', { hidden: true })
523
- .description('Internal: run a harness hook (reads hook JSON on stdin)')
524
- // Inert, and the point of it is that it is inert: the installed command line
525
- // carries a marker that says "Notifai wrote this" independently of which
526
- // checkout wrote it.
527
- .option('--owner <name>', 'internal ownership marker')
528
- .option('--harness <name>', 'internal harness output adapter')
529
- .action(async (event, opts) => {
530
- if (event === 'hermes-attend' && opts.harness === 'hermes') {
531
- const { hermesAttendCommand } = await import('./hermes-attendant.js');
532
- exit(await hermesAttendCommand(deps, process.stdin, process.stdout));
533
- return;
534
- }
535
- const harness = HOOK_INSTALLABLE_HARNESSES.find((candidate) => candidate === opts.harness);
536
- const settlementInput = deps.env[QUESTION_SETTLEMENT_INPUT_ENV];
537
- if (event === 'question-settlement' || event === 'question-submission') {
538
- delete deps.env[QUESTION_SETTLEMENT_INPUT_ENV];
539
- }
540
- exit(await runners.hookRun(deps, event, (event === 'question-settlement' || event === 'question-submission') && settlementInput !== undefined
541
- ? async () => settlementInput
542
- : () => readStdinWithTimeout(), harness));
543
- });
544
- const hooks = program
545
- .command('hooks')
546
- .description('Install harness lifecycle hooks once per machine')
547
- .summary('Wire a harness to Notifai lifecycle events')
548
- .helpGroup(GROUP.advanced);
549
- hooks
550
- .command('install')
551
- .description('Wire this harness to Notifai lifecycle events on this machine. ' +
552
- 'Whether Notifai acts in a project is `notifai project enable`, not an install scope')
553
- .option('--harness <name>', 'claude-code | codex | cursor | opencode | openclaw | hermes | grok (default: every detected harness)')
554
- .action((opts) => {
555
- exit(runners.hooksInstall(deps, opts));
556
- });
557
- hooks
558
- .command('uninstall')
559
- .description('Remove the hooks this CLI installed for this machine')
560
- .option('--harness <name>', 'claude-code | codex | cursor | opencode | openclaw | hermes | grok (default: detected)')
561
- .action((opts) => {
562
- exit(runners.hooksUninstall(deps, opts));
563
- });
564
- program
565
- .command('logs')
566
- .helpGroup(GROUP.daily)
567
- .summary('Show what this machine recorded about what it did')
568
- .description('Read the local record of commands, notifications, and the question decisions harness hooks made. ' +
569
- 'Bounded and scoped to this project by default; never leaves this machine')
570
- .option('-n, --limit <count>', 'how many records to show (default: 30)', (v) => Number(v))
571
- .option('--all', 'lift the default limit, up to a hard cap')
572
- .option('--since <when>', 'only records newer than this: 10m, 2h, 1d, or an ISO 8601 instant')
573
- .option('--level <level>', 'minimum severity: error | info | debug (error shows only failures)')
574
- .option('--event <name>', 'only this event; repeatable', (v, all = []) => [...all, v])
575
- .option('--run <id>', 'everything one command invocation did')
576
- .option('--request <id>', 'everything about one notification request')
577
- .option('--session <id>', 'only this Agent Session')
578
- .option('--project <id>', 'only this Project')
579
- .option('--all-projects', 'do not scope to the Project in this directory')
580
- .option('--grep <text>', 'only records containing this text')
581
- .option('--json', 'one JSON record per line on stdout')
582
- .option('--path', 'print the log file paths instead of the records')
583
- .option('--clear', 'delete the log files')
584
- .action((opts) => {
585
- const flags = { ...opts };
586
- if (Array.isArray(flags.event) && flags.event.length === 0)
587
- delete flags.event;
588
- exit(runners.logs(deps, flags));
589
- });
590
- const config = program
591
- .command('config')
592
- .description('Show or change settings')
593
- .summary('Show or change settings')
594
- .helpGroup(GROUP.daily);
595
- config
596
- .command('show')
597
- .description('Show every setting, what it does, and where its value came from')
598
- .option('--explain', 'include advanced settings and the file each value came from')
599
- .option('--plain', 'the flat key = value form, even at a terminal')
600
- .option('--json', 'machine-readable output')
601
- .action((opts) => {
602
- exit(runners.configShow(deps, opts));
603
- });
604
- config
605
- .command('explain <key>')
606
- .description('Explain one setting in full: what it does, what it accepts, what it is now')
607
- .option('--json', 'machine-readable output')
608
- .action((key, opts) => {
609
- exit(runners.configExplain(deps, key, opts));
610
- });
611
- config
612
- .command('set <key> <value>')
613
- .description('Set a configuration value (choose a layer interactively; unattended defaults machine-global and requires --yes)')
614
- .option('--project', 'write to the shared .notifai/config.toml instead')
615
- .option('--local', 'write a personal project preference on this machine (not in the repo)')
616
- .option('--session <id>', 'apply only to one Agent Session')
617
- .option('--yes', 'skip the confirmation gate')
618
- .action(async (key, value, opts) => {
619
- exit(await runners.configSet(deps, key, value, opts));
620
- });
621
- config
622
- .command('unset <key>')
623
- .description('Remove a configuration value so the next layer or shipped default applies (choose a layer interactively; unattended defaults machine-global and requires --yes)')
624
- .option('--project', 'remove from the shared .notifai/config.toml instead')
625
- .option('--local', 'remove a personal project preference stored on this machine')
626
- .option('--session <id>', 'remove from one Agent Session')
627
- .option('--yes', 'skip the confirmation gate')
628
- .action(async (key, opts) => {
629
- exit(await runners.configUnset(deps, key, opts));
630
- });
631
- const guidance = program
632
- .command('guidance')
633
- .description('How notifications are written: the shipped guidance and your overrides, per topic')
634
- .summary('Show or change how notifications are written')
635
- .helpGroup(GROUP.daily);
636
- guidance
637
- .command('show', { isDefault: true })
638
- .description('Print the effective guidance, every topic under the layer that supplied it')
639
- .option('--json', 'machine-readable output')
640
- .action(async (opts) => {
641
- exit(await runners.guidanceShow(deps, opts));
642
- });
643
- guidance
644
- .command('set <topic> [text]')
645
- .description('Write one guidance topic in your words; it replaces the shipped topic of the same name for that scope ' +
646
- '(choose a layer interactively; unattended defaults machine-global and requires --yes)')
647
- .option('--file <path>', 'read the guidance text from a file (use - for stdin)')
648
- .option('--project', 'write to the shared .notifai/guidance/ instead')
649
- .option('--local', 'write a personal project preference on this machine (not in the repo)')
650
- .option('--yes', 'skip the confirmation gate')
651
- .action(async (topic, text, opts) => {
652
- let content = text;
653
- if (typeof opts.file === 'string') {
654
- if (content !== undefined) {
655
- deps.io.err('Pass either the text or --file, not both.');
656
- exit(2);
657
- return;
658
- }
659
- try {
660
- content = readFileSync(opts.file === '-' ? 0 : opts.file, 'utf8');
661
- }
662
- catch (err) {
663
- deps.io.err(`Could not read ${opts.file}: ${String(err)}`);
664
- exit(2);
665
- return;
666
- }
667
- }
668
- if (content === undefined) {
669
- deps.io.err('Pass the guidance text, or --file <path|-> to read it.');
670
- exit(2);
671
- return;
672
- }
673
- exit(await runners.guidanceSet(deps, topic, content, {
674
- project: opts.project,
675
- local: opts.local,
676
- yes: opts.yes,
677
- }));
678
- });
679
- guidance
680
- .command('unset <topic>')
681
- .description('Remove a guidance override so the next layer or the shipped topic applies ' +
682
- '(choose a layer interactively; unattended defaults machine-global and requires --yes)')
683
- .option('--project', 'remove from the shared .notifai/guidance/ instead')
684
- .option('--local', 'remove a personal project preference stored on this machine')
685
- .option('--yes', 'skip the confirmation gate')
686
- .action(async (topic, opts) => {
687
- exit(await runners.guidanceUnset(deps, topic, opts));
688
- });
689
- return program;
690
- }
691
- //# sourceMappingURL=program.js.map