@raidiant/notifai 11.7.1 → 12.0.0-beta.5

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 +48 -0
  2. package/NOTICE +16 -0
  3. package/THIRD_PARTY_NOTICES +725 -0
  4. package/bin/notifai.mjs +11387 -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
@@ -1,644 +0,0 @@
1
- /**
2
- * The interactive app — what `notifai` does when a person runs it.
3
- *
4
- * Everything here is a shell around commands that already exist. `init`,
5
- * `login`, `doctor`, `send`, `hooks install` and `config set` keep their
6
- * behaviour, their validation and their exit codes; this module decides what to
7
- * offer, in what order, and how to say it. That is deliberate: a second
8
- * implementation of "set a config value" would be a second set of bugs, and the
9
- * menu would slowly stop agreeing with the flags.
10
- *
11
- * The module is imported dynamically, only after the caller is known to be a
12
- * human at a terminal. Nothing an agent runs — `send`, `ask`, and above all the
13
- * hook that runs in front of every prompt the user types — may pay to load a
14
- * prompt library it will never draw.
15
- *
16
- * Three things shape the layout:
17
- *
18
- * First-run is `init`, not a second sign-in/device split. An unsigned machine
19
- * enters that journey immediately; a remaining blocker is offered as Finish
20
- * setup. Once send-prerequisites are ready, the menu leads with the test
21
- * notification, because seeing the thing arrive on a device is what makes the
22
- * product real.
23
- *
24
- * Detail is earned, not given. A settings group shows fourteen one-line
25
- * summaries, and the paragraph explaining a key appears once the reader has
26
- * picked that key.
27
- *
28
- * Cancelling always goes back one level and never leaves the terminal in a
29
- * strange state.
30
- */
31
- import * as clack from '@clack/prompts';
32
- import { EXIT, assessReadiness, canDeviceReceive, configSetCommand, deviceInventory, doctorCommand, hooksInstallCommand, hooksUninstallCommand, initCommand, loginCommand, logoutCommand, sendCommand, } from './commands.js';
33
- import { loadConfig } from './config.js';
34
- import { detectedHarnesses, findInstallations, } from './install-hooks.js';
35
- import { CONFIG_GROUPS, acceptedValues, boundsHint, configInfo, configKeysByGroup, describeSource, formatValue, } from './config-schema.js';
36
- import { firstBlocker, refreshAfterMenuAction, } from './readiness.js';
37
- import { printBanner, tagline } from './ui/banner.js';
38
- import { card, glyph, mark, style } from './ui/theme.js';
39
- /** Clack returns a symbol when the user pressed Ctrl-C or Escape. */
40
- function cancelled(value) {
41
- return clack.isCancel(value);
42
- }
43
- /**
44
- * Which hook actions this directory and setup can actually perform.
45
- *
46
- * Install is offered only when a harness is detectable here. Uninstall is
47
- * offered only when Notifai is actually wired, and it names what it removes:
48
- * there is one installation per harness, for this machine.
49
- */
50
- export function routingHookActions(input) {
51
- const options = [];
52
- const wired = input.installations.length > 0;
53
- if (input.canInstall) {
54
- options.push({
55
- value: 'install',
56
- label: input.hooksReady || wired ? 'Re-install hooks' : 'Install hooks',
57
- hint: 'this machine; enable or disable Notifai per project separately',
58
- });
59
- }
60
- if (wired) {
61
- options.push({
62
- value: 'uninstall',
63
- label: 'Uninstall hooks on this machine',
64
- hint: harnessHint(input.installations),
65
- });
66
- }
67
- options.push({ value: 'settings', label: 'Change question settings', hint: 'when a question may leave this terminal' }, { value: 'back', label: '← Back' });
68
- return options;
69
- }
70
- function harnessHint(installations) {
71
- return [...new Set(installations.map((installation) => installation.harness))].join(', ');
72
- }
73
- export async function interactiveCommand(deps, version) {
74
- await printBanner();
75
- process.stdout.write(` ${tagline(version)}\n`);
76
- let readiness = await assess(deps);
77
- if (stateById(readiness, 'credential')?.status !== 'ready') {
78
- await initCommand(deps, {});
79
- readiness = await assess(deps);
80
- }
81
- let first = true;
82
- for (;;) {
83
- renderStatus(readiness, { compact: !first });
84
- first = false;
85
- const choice = await clack.select({
86
- message: 'What would you like to do?',
87
- options: menuFor(readiness),
88
- });
89
- // Root is the only place Escape/Ctrl-C quits. Every nested prompt returns.
90
- if (cancelled(choice))
91
- return farewell();
92
- switch (choice) {
93
- case 'quit':
94
- return farewell();
95
- case 'setup':
96
- await initCommand(deps, {});
97
- readiness = await refresh(deps, readiness, refreshAfterMenuAction('setup', true));
98
- break;
99
- case 'account': {
100
- const changed = await accountScreen(deps, readiness);
101
- readiness = await refresh(deps, readiness, refreshAfterMenuAction('account', changed));
102
- break;
103
- }
104
- case 'test':
105
- await testNotificationScreen(deps);
106
- break;
107
- case 'devices':
108
- await devicesScreen(deps);
109
- break;
110
- case 'settings': {
111
- const result = await settingsScreen(deps);
112
- readiness = await refresh(deps, readiness, refreshAfterMenuAction('settings', result !== 'unchanged', { remote: result === 'remote' }));
113
- break;
114
- }
115
- case 'routing': {
116
- const changed = await routingScreen(deps, readiness);
117
- readiness = await refresh(deps, readiness, refreshAfterMenuAction('routing', changed));
118
- break;
119
- }
120
- case 'doctor':
121
- // One assessment serves the report and the redraw. Doctor does not
122
- // change setup, so running the graph again would only wait.
123
- readiness = await assess(deps);
124
- await doctorCommand(deps, {}, { readiness });
125
- break;
126
- }
127
- }
128
- }
129
- function farewell() {
130
- clack.outro(style.dim(`${glyph.bullet} bye`));
131
- return EXIT.ok;
132
- }
133
- async function assess(deps, options = {}) {
134
- const spinner = clack.spinner();
135
- spinner.start('Checking your setup');
136
- try {
137
- return await assessReadiness(deps, options);
138
- }
139
- finally {
140
- spinner.stop(style.dim('Setup checked'));
141
- }
142
- }
143
- async function refresh(deps, previous, next) {
144
- return next === null ? previous : assess(deps, { previous, refresh: next });
145
- }
146
- // ---------------------------------------------------------------------------
147
- // Status
148
- // ---------------------------------------------------------------------------
149
- function stateById(readiness, id) {
150
- return readiness.states.find((state) => state.id === id);
151
- }
152
- function toneOf(state) {
153
- if (state === undefined)
154
- return 'pending';
155
- switch (state.status) {
156
- case 'ready':
157
- return 'ok';
158
- case 'gap':
159
- return 'bad';
160
- case 'optional-gap':
161
- return 'warn';
162
- case 'unknown':
163
- return 'pending';
164
- }
165
- }
166
- /**
167
- * The status card: four lines that answer "is this working", with the detail
168
- * behind `doctor` rather than in front of everyone.
169
- *
170
- * `doctor` reports fourteen states because that is what a report is for. Home
171
- * shows the four that change what you would do next, which is why this reads
172
- * the same readiness model rather than a second one that could disagree.
173
- */
174
- function renderStatus(readiness, options) {
175
- const rows = [
176
- {
177
- label: 'Account',
178
- state: stateById(readiness, 'credential'),
179
- summary: (s) => (s?.status === 'ready' ? accountSummary(readiness) : 'not signed in'),
180
- },
181
- {
182
- label: 'Devices',
183
- state: stateById(readiness, 'devices'),
184
- summary: (s) => shorten(s?.detail ?? 'unknown'),
185
- },
186
- {
187
- label: 'Project',
188
- state: stateById(readiness, 'project'),
189
- summary: (s) => (s?.status === 'ready' ? firstQuoted(s.detail) : 'not named'),
190
- },
191
- {
192
- label: 'Questions',
193
- state: stateById(readiness, 'hooks'),
194
- summary: (s) => (s?.status === 'ready' ? 'routing to your devices' : shorten(s?.detail ?? 'not wired')),
195
- },
196
- ];
197
- if (options.compact === true) {
198
- const summary = rows.map((row) => `${mark(toneOf(row.state))} ${style.dim(row.label)}`).join(' ');
199
- process.stdout.write(`\n ${summary}\n\n`);
200
- return;
201
- }
202
- const labelWidth = Math.max(...rows.map((row) => row.label.length));
203
- const body = rows.map((row) => `${mark(toneOf(row.state))} ${style.dim(row.label.padEnd(labelWidth))} ${row.summary(row.state)}`);
204
- process.stdout.write('\n');
205
- for (const line of card('Status', body))
206
- process.stdout.write(`${line}\n`);
207
- process.stdout.write('\n');
208
- }
209
- function accountSummary(readiness) {
210
- const auth = stateById(readiness, 'auth');
211
- const email = auth?.detail.match(/\(([^)]+@[^)]+)\)/)?.[1];
212
- return email ?? 'signed in';
213
- }
214
- function firstQuoted(text) {
215
- return text.match(/"([^"]+)"/)?.[1] ?? text;
216
- }
217
- function shorten(text, limit = 46) {
218
- const flat = text.replace(/\s+/g, ' ').trim();
219
- const clipped = flat.split(' — ')[0] ?? flat;
220
- return clipped.length > limit ? `${clipped.slice(0, limit - 1)}…` : clipped;
221
- }
222
- /**
223
- * The menu, ordered by what is actually in the way.
224
- *
225
- * A fixed menu would put "Send a test notification" first for someone who has
226
- * not signed in — an action that cannot succeed, offered ahead of the one that
227
- * would unblock it.
228
- */
229
- function menuFor(readiness) {
230
- const signedIn = stateById(readiness, 'credential')?.status === 'ready';
231
- const devices = stateById(readiness, 'devices');
232
- const hasDevice = devices?.status === 'ready';
233
- const routing = stateById(readiness, 'hooks');
234
- const blocker = firstBlocker(readiness);
235
- const options = [];
236
- if (blocker !== null) {
237
- options.push({
238
- value: 'setup',
239
- label: 'Finish setup',
240
- hint: shorten(blocker.title.toLowerCase(), 40),
241
- });
242
- }
243
- else if (signedIn && hasDevice) {
244
- options.push({
245
- value: 'test',
246
- label: 'Send a test notification',
247
- hint: 'prove the whole path, end to end',
248
- });
249
- }
250
- options.push({ value: 'settings', label: 'Settings', hint: 'sounds, timing, presence, project' }, {
251
- value: 'routing',
252
- label: 'Question routing',
253
- hint: routing?.status === 'ready' ? 'wired — review or change' : 'let agents reach you when you step away',
254
- });
255
- if (signedIn && hasDevice) {
256
- options.push({ value: 'devices', label: 'Devices', hint: 'what can receive right now' });
257
- }
258
- options.push({ value: 'doctor', label: 'Run diagnostics', hint: 'check every part of the setup' });
259
- if (signedIn) {
260
- options.push({ value: 'account', label: 'Account', hint: 'plan, machine, sign out' });
261
- }
262
- options.push({ value: 'quit', label: 'Quit' });
263
- return options;
264
- }
265
- // ---------------------------------------------------------------------------
266
- // Test notification
267
- // ---------------------------------------------------------------------------
268
- async function testNotificationScreen(deps) {
269
- const config = loadConfig({ cwd: deps.cwd, env: deps.env });
270
- const project = config.project.value;
271
- const title = await clack.text({
272
- message: 'Title',
273
- placeholder: 'Test from Notifai',
274
- defaultValue: 'Test from Notifai',
275
- });
276
- if (cancelled(title))
277
- return;
278
- const summary = await clack.text({
279
- message: 'Summary',
280
- placeholder: 'If you can read this on your device, it works.',
281
- defaultValue: 'If you can read this on your device, it works.',
282
- });
283
- if (cancelled(summary))
284
- return;
285
- const kind = await clack.select({
286
- message: 'Kind',
287
- options: [
288
- { value: 'update', label: 'Update', hint: 'something happened' },
289
- { value: 'done', label: 'Done', hint: 'work finished' },
290
- ],
291
- initialValue: 'done',
292
- });
293
- if (cancelled(kind))
294
- return;
295
- clack.log.step('Sending, then waiting for your devices to confirm…');
296
- const code = await sendCommand(deps, {
297
- title: String(title),
298
- summary: String(summary),
299
- kind: String(kind),
300
- ...(project !== null ? { project } : {}),
301
- });
302
- if (code === EXIT.ok)
303
- clack.log.success('Delivered. Check the device it landed on.');
304
- else
305
- clack.log.error('That did not get through — `Run diagnostics` will say why.');
306
- }
307
- // ---------------------------------------------------------------------------
308
- // Devices
309
- // ---------------------------------------------------------------------------
310
- async function devicesScreen(deps) {
311
- const spinner = clack.spinner();
312
- spinner.start('Loading your devices');
313
- const devices = await deviceInventory(deps);
314
- spinner.stop(style.dim('Devices loaded'));
315
- if (devices === null) {
316
- clack.log.warn('Could not reach the service. Sign in, or check the connection.');
317
- return;
318
- }
319
- if (devices.length === 0) {
320
- clack.note('No devices are registered yet.\n\n' +
321
- 'Install a supported Notifai Companion App, sign in with the same\n' +
322
- 'Account, and allow notifications when it asks.', 'No devices');
323
- return;
324
- }
325
- const body = devices
326
- .map((device) => {
327
- const ready = canDeviceReceive(device);
328
- const detail = ready ? 'ready' : `not ready ${glyph.bullet} permission: ${device.permission_status}`;
329
- return (`${mark(ready ? 'ok' : 'warn')} ${style.value(device.display_name)} ${style.dim(`(${device.platform})`)}\n` +
330
- ` ${style.dim(detail)}\n` +
331
- ` ${style.dim(device.device_id)}`);
332
- })
333
- .join('\n\n');
334
- clack.note(body, `${devices.length} device${devices.length === 1 ? '' : 's'}`);
335
- }
336
- // ---------------------------------------------------------------------------
337
- // Settings
338
- // ---------------------------------------------------------------------------
339
- async function settingsScreen(deps) {
340
- let result = 'unchanged';
341
- for (;;) {
342
- const config = loadConfig({ cwd: deps.cwd, env: deps.env });
343
- const group = await clack.select({
344
- message: 'Settings',
345
- options: [
346
- ...CONFIG_GROUPS.map((entry) => ({
347
- value: entry.id,
348
- label: entry.title,
349
- hint: changedCount(config, entry.id),
350
- })),
351
- { value: 'back', label: '← Back' },
352
- ],
353
- });
354
- if (cancelled(group) || group === 'back')
355
- return result;
356
- const next = await settingsGroupScreen(deps, group);
357
- if (next === 'remote')
358
- result = 'remote';
359
- else if (next === 'local' && result === 'unchanged')
360
- result = 'local';
361
- }
362
- }
363
- /** "3 changed" beats repeating the group blurb the reader already saw. */
364
- function changedCount(config, group) {
365
- const keys = configKeysByGroup(group);
366
- const changed = keys.filter((info) => config[info.key].source !== 'default').length;
367
- return changed === 0 ? style.dim('all default') : style.dim(`${changed} changed`);
368
- }
369
- async function settingsGroupScreen(deps, group) {
370
- let result = 'unchanged';
371
- for (;;) {
372
- const config = loadConfig({ cwd: deps.cwd, env: deps.env });
373
- const info = CONFIG_GROUPS.find((entry) => entry.id === group);
374
- const keys = configKeysByGroup(group);
375
- const key = await clack.select({
376
- message: info.title,
377
- options: [
378
- ...keys.map((entry) => {
379
- const resolved = config[entry.key];
380
- const source = describeSource(resolved.source);
381
- const value = formatValue(entry.key, resolved.value);
382
- return {
383
- value: entry.key,
384
- label: entry.label,
385
- hint: source.label === 'default' ? style.dim(value) : `${value} ${style.dim(`(${source.label})`)}`,
386
- };
387
- }),
388
- { value: 'back', label: '← Back' },
389
- ],
390
- });
391
- if (cancelled(key) || key === 'back')
392
- return result;
393
- const next = await settingDetailScreen(deps, key);
394
- if (next === 'remote')
395
- result = 'remote';
396
- else if (next === 'local' && result === 'unchanged')
397
- result = 'local';
398
- }
399
- }
400
- /**
401
- * One key, fully explained, with the option to change it.
402
- *
403
- * This is where the paragraph lives. Everything above stayed one line per key
404
- * so that arriving here means the reader has already said which key they care
405
- * about.
406
- */
407
- async function settingDetailScreen(deps, key) {
408
- const config = loadConfig({ cwd: deps.cwd, env: deps.env });
409
- const info = configInfo(key);
410
- const resolved = config[key];
411
- const source = describeSource(resolved.source);
412
- const lines = [
413
- info.detail,
414
- '',
415
- `${style.dim('Now')} ${style.value(formatValue(key, resolved.value))} ${style.dim(`${glyph.bullet} ${source.label}`)}`,
416
- `${style.dim('Accepts')} ${acceptedValues(key)}`,
417
- `${style.dim('Key')} ${style.code(key)}`,
418
- ];
419
- clack.note(lines.join('\n'), info.label);
420
- const action = await clack.select({
421
- message: 'Change it?',
422
- options: [
423
- // Not lower-cased: "Change only when i have stepped away" is what
424
- // `toLowerCase` makes of a label that starts a sentence.
425
- { value: 'change', label: `Change this setting`, hint: style.code(info.key) },
426
- { value: 'back', label: '← Back' },
427
- ],
428
- initialValue: 'back',
429
- });
430
- if (cancelled(action) || action === 'back')
431
- return 'unchanged';
432
- const value = await promptForValue(deps, key);
433
- if (value === null)
434
- return 'unchanged';
435
- const layer = await chooseLayer();
436
- if (layer === null)
437
- return 'unchanged';
438
- const code = await configSetCommand(deps, key, value, {
439
- yes: true,
440
- ...(layer === 'project' ? { project: true } : {}),
441
- ...(layer === 'local' ? { local: true } : {}),
442
- });
443
- if (code !== EXIT.ok)
444
- return 'unchanged';
445
- clack.log.success(`${info.label} is now ${formatValueRaw(key, value)}`);
446
- return 'local';
447
- }
448
- function formatValueRaw(key, raw) {
449
- const info = configInfo(key);
450
- if (info.kind === 'boolean')
451
- return raw === 'true' ? 'yes' : 'no';
452
- return raw;
453
- }
454
- /** The prompt shape follows the key's type; validation stays in `config set`. */
455
- async function promptForValue(deps, key) {
456
- const info = configInfo(key);
457
- if (info.kind === 'boolean') {
458
- const answer = await clack.select({
459
- message: info.label,
460
- options: [
461
- { value: 'true', label: 'Yes' },
462
- { value: 'false', label: 'No' },
463
- ],
464
- });
465
- return cancelled(answer) ? null : String(answer);
466
- }
467
- if (info.kind === 'enum') {
468
- const answer = await clack.select({
469
- message: info.label,
470
- options: (info.choices ?? []).map((choice) => ({
471
- value: choice,
472
- label: choice,
473
- ...(info.choiceHints?.[choice] !== undefined ? { hint: info.choiceHints[choice] } : {}),
474
- })),
475
- });
476
- return cancelled(answer) ? null : String(answer);
477
- }
478
- // The one key whose legal values the machine knows better than the reader.
479
- if (key === 'devices')
480
- return await promptForDevices(deps);
481
- const bounds = boundsHint(key);
482
- const answer = await clack.text({
483
- message: info.label,
484
- ...(info.example !== undefined ? { placeholder: info.example } : {}),
485
- validate: (input) => {
486
- const trimmed = (input ?? '').trim();
487
- if (trimmed === '')
488
- return 'Enter a value, or press Escape to go back.';
489
- if (info.kind === 'integer') {
490
- if (!/^-?\d+$/.test(trimmed))
491
- return `${info.label} is a whole number of seconds.`;
492
- const range = boundsRange(key);
493
- if (bounds !== null && range !== null) {
494
- const parsed = Number(trimmed);
495
- if (parsed < range.min || parsed > range.max)
496
- return `Must be between ${bounds}.`;
497
- }
498
- }
499
- if (info.kind === 'url' && !/^https?:\/\//.test(trimmed))
500
- return 'Must start with http:// or https://.';
501
- return undefined;
502
- },
503
- });
504
- return cancelled(answer) ? null : String(answer).trim();
505
- }
506
- function boundsRange(key) {
507
- const hint = boundsHint(key);
508
- if (hint === null)
509
- return null;
510
- const [min, max] = hint.replace(/[^\d–]/g, '').split('–');
511
- if (min === undefined || max === undefined)
512
- return null;
513
- return { min: Number(min), max: Number(max) };
514
- }
515
- async function promptForDevices(deps) {
516
- const spinner = clack.spinner();
517
- spinner.start('Loading your devices');
518
- const devices = await deviceInventory(deps);
519
- spinner.stop(style.dim('Devices loaded'));
520
- if (devices === null || devices.length === 0) {
521
- clack.log.warn('No devices to choose from yet.');
522
- return null;
523
- }
524
- const picked = await clack.multiselect({
525
- message: 'Which devices should receive by default?',
526
- options: devices.map((device) => ({
527
- value: device.device_id,
528
- label: device.display_name,
529
- hint: canDeviceReceive(device) ? device.platform : `${device.platform} ${glyph.bullet} not ready`,
530
- })),
531
- required: true,
532
- });
533
- return cancelled(picked) ? null : picked.join(',');
534
- }
535
- /**
536
- * Which layer the value lands in.
537
- *
538
- * Asked every time rather than defaulting, because the difference between
539
- * "my machine" and "everyone who clones this repository" is not recoverable by
540
- * guessing, and the shared file is the one that ends up in a commit.
541
- */
542
- async function chooseLayer() {
543
- const layer = await clack.select({
544
- message: 'Where should this apply?',
545
- options: [
546
- { value: 'global', label: 'This machine', hint: 'every project you work on here' },
547
- { value: 'project', label: 'This project, shared', hint: '.notifai/config.toml — commit it' },
548
- { value: 'local', label: 'This project, just me', hint: 'stored on this machine, not in the repo' },
549
- ],
550
- initialValue: 'global',
551
- });
552
- return cancelled(layer) ? null : layer;
553
- }
554
- // ---------------------------------------------------------------------------
555
- // Question routing
556
- // ---------------------------------------------------------------------------
557
- /**
558
- * Which harnesses are wired, without the install paths.
559
- *
560
- * The underlying state lists every installation with its absolute file path,
561
- * which is the right level of detail for `doctor` and far too much for a
562
- * summary card — four paths wrap across six lines and push the settings
563
- * underneath them out of alignment.
564
- */
565
- function wiringSummary(hooks) {
566
- if (hooks === undefined)
567
- return 'unknown';
568
- const named = hooks.detail.replace(/\s*\([^)]*\)/g, '').trim();
569
- return named === '' ? hooks.detail : named;
570
- }
571
- /** Returns true when something changed and the status card needs refreshing. */
572
- async function routingScreen(deps, readiness) {
573
- const hooks = stateById(readiness, 'hooks');
574
- const config = loadConfig({ cwd: deps.cwd, env: deps.env });
575
- const installations = findInstallations(deps.env, deps.hookAdapterHome);
576
- const row = (label, value) => `${style.dim(label.padEnd(16))}${value}`;
577
- clack.note('When an agent registers a question, it appears in your terminal first.\n' +
578
- 'After the grace below, it goes to your Companion devices as a\n' +
579
- 'notification with a supported native or in-app answer surface, and\n' +
580
- 'your answer comes back to the agent —\n' +
581
- 'whether or not you are still at this machine.\n\n' +
582
- [
583
- row('Wired to', wiringSummary(hooks)),
584
- row('Send', config.ask_notifications.value ? 'yes' : 'no — questions stay in the terminal'),
585
- row('Grace', formatValue('ask_grace_seconds', config.ask_grace_seconds.value)),
586
- ].join('\n'), 'Question routing');
587
- const action = await clack.select({
588
- message: 'Question routing',
589
- options: routingHookActions({
590
- canInstall: detectedHarnesses(deps.cwd, deps.env).length > 0,
591
- installations,
592
- hooksReady: hooks?.status === 'ready',
593
- }),
594
- });
595
- if (cancelled(action) || action === 'back')
596
- return false;
597
- if (action === 'settings') {
598
- await settingsGroupScreen(deps, 'questions');
599
- return true;
600
- }
601
- if (action === 'install') {
602
- hooksInstallCommand(deps, {});
603
- return true;
604
- }
605
- for (const installation of installations) {
606
- hooksUninstallCommand(deps, { harness: installation.harness });
607
- }
608
- return true;
609
- }
610
- // ---------------------------------------------------------------------------
611
- // Account
612
- // ---------------------------------------------------------------------------
613
- /** Returns true when something changed and the status card needs refreshing. */
614
- async function accountScreen(deps, readiness) {
615
- const signedIn = stateById(readiness, 'credential')?.status === 'ready';
616
- if (!signedIn) {
617
- await initCommand(deps, {});
618
- return true;
619
- }
620
- const auth = stateById(readiness, 'auth');
621
- const credential = stateById(readiness, 'credential');
622
- clack.note(`${style.dim('Machine')} ${credential?.detail ?? 'unknown'}\n${style.dim('Account')} ${auth?.detail ?? 'unknown'}`, 'Account');
623
- const action = await clack.select({
624
- message: 'Account',
625
- options: [
626
- { value: 'relogin', label: 'Pair this machine again' },
627
- { value: 'logout', label: 'Sign out', hint: 'removes the stored credential' },
628
- { value: 'back', label: '← Back' },
629
- ],
630
- initialValue: 'back',
631
- });
632
- if (cancelled(action) || action === 'back')
633
- return false;
634
- if (action === 'logout') {
635
- const sure = await clack.confirm({ message: 'Remove the stored credential?', initialValue: false });
636
- if (cancelled(sure) || sure !== true)
637
- return false;
638
- logoutCommand(deps);
639
- return true;
640
- }
641
- await loginCommand(deps, {});
642
- return true;
643
- }
644
- //# sourceMappingURL=interactive.js.map