@skrr-ai/cli 0.1.110 → 0.1.113

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 (399) hide show
  1. package/bin/run.js +15 -1
  2. package/dist/base-command.d.ts +31 -3
  3. package/dist/base-command.js +136 -22
  4. package/dist/commands/actions/list.js +2 -1
  5. package/dist/commands/agenda/trigger/create.js +1 -1
  6. package/dist/commands/agenda/trigger/list.js +2 -1
  7. package/dist/commands/agent-groups/list.js +2 -1
  8. package/dist/commands/agents/actions/list.js +2 -1
  9. package/dist/commands/agents/always-on/status.js +5 -0
  10. package/dist/commands/agents/chat.js +4 -1
  11. package/dist/commands/agents/create.d.ts +3 -1
  12. package/dist/commands/agents/create.js +36 -3
  13. package/dist/commands/agents/duplicate.js +4 -0
  14. package/dist/commands/agents/eval/list.js +2 -1
  15. package/dist/commands/agents/files/list.js +2 -1
  16. package/dist/commands/agents/folders/list.js +2 -1
  17. package/dist/commands/agents/goals/list.js +2 -1
  18. package/dist/commands/agents/intuitions/list.js +8 -5
  19. package/dist/commands/agents/list.d.ts +12 -0
  20. package/dist/commands/agents/list.js +45 -8
  21. package/dist/commands/agents/releases/known-issues/list.js +2 -1
  22. package/dist/commands/agents/releases/list.js +5 -1
  23. package/dist/commands/agents/releases/trusted-publishers/list.js +2 -1
  24. package/dist/commands/agents/roles/list.js +2 -1
  25. package/dist/commands/agents/skills/list.js +2 -1
  26. package/dist/commands/agents/todos/list.js +2 -1
  27. package/dist/commands/agents/triggers/list.js +2 -1
  28. package/dist/commands/api-keys/list.js +2 -1
  29. package/dist/commands/apps/channel.d.ts +20 -0
  30. package/dist/commands/apps/channel.js +64 -0
  31. package/dist/commands/apps/check-draft.d.ts +12 -0
  32. package/dist/commands/apps/check-draft.js +41 -0
  33. package/dist/commands/apps/check.d.ts +42 -0
  34. package/dist/commands/apps/check.js +91 -0
  35. package/dist/commands/apps/create.d.ts +15 -0
  36. package/dist/commands/apps/create.js +59 -0
  37. package/dist/commands/apps/data/put.d.ts +18 -0
  38. package/dist/commands/apps/data/put.js +72 -0
  39. package/dist/commands/apps/data/query.d.ts +20 -0
  40. package/dist/commands/apps/data/query.js +88 -0
  41. package/dist/commands/apps/disclosure.d.ts +16 -0
  42. package/dist/commands/apps/disclosure.js +71 -0
  43. package/dist/commands/apps/file/cat.d.ts +15 -0
  44. package/dist/commands/apps/file/cat.js +50 -0
  45. package/dist/commands/apps/file/ls.d.ts +13 -0
  46. package/dist/commands/apps/file/ls.js +47 -0
  47. package/dist/commands/apps/file/mv.d.ts +15 -0
  48. package/dist/commands/apps/file/mv.js +49 -0
  49. package/dist/commands/apps/file/rm.d.ts +15 -0
  50. package/dist/commands/apps/file/rm.js +53 -0
  51. package/dist/commands/apps/file/write.d.ts +17 -0
  52. package/dist/commands/apps/file/write.js +81 -0
  53. package/dist/commands/apps/install.d.ts +19 -0
  54. package/dist/commands/apps/install.js +136 -0
  55. package/dist/commands/apps/installations/list.d.ts +11 -0
  56. package/dist/commands/apps/installations/list.js +49 -0
  57. package/dist/commands/apps/installations/show.d.ts +12 -0
  58. package/dist/commands/apps/installations/show.js +61 -0
  59. package/dist/commands/apps/layout/set.d.ts +11 -0
  60. package/dist/commands/apps/layout/set.js +125 -0
  61. package/dist/commands/apps/layout/show.d.ts +9 -0
  62. package/dist/commands/apps/layout/show.js +33 -0
  63. package/dist/commands/apps/list.d.ts +10 -0
  64. package/dist/commands/apps/list.js +45 -0
  65. package/dist/commands/apps/logs.d.ts +13 -0
  66. package/dist/commands/apps/logs.js +55 -0
  67. package/dist/commands/apps/preview.d.ts +12 -0
  68. package/dist/commands/apps/preview.js +39 -0
  69. package/dist/commands/apps/publish/propose.d.ts +14 -0
  70. package/dist/commands/apps/publish/propose.js +45 -0
  71. package/dist/commands/apps/pull.d.ts +14 -0
  72. package/dist/commands/apps/pull.js +56 -0
  73. package/dist/commands/apps/push.d.ts +15 -0
  74. package/dist/commands/apps/push.js +75 -0
  75. package/dist/commands/apps/reconsent.d.ts +13 -0
  76. package/dist/commands/apps/reconsent.js +67 -0
  77. package/dist/commands/apps/report.d.ts +20 -0
  78. package/dist/commands/apps/report.js +63 -0
  79. package/dist/commands/apps/resume.d.ts +12 -0
  80. package/dist/commands/apps/resume.js +36 -0
  81. package/dist/commands/apps/settings/set.d.ts +13 -0
  82. package/dist/commands/apps/settings/set.js +54 -0
  83. package/dist/commands/apps/settings/show.d.ts +11 -0
  84. package/dist/commands/apps/settings/show.js +31 -0
  85. package/dist/commands/apps/show.d.ts +12 -0
  86. package/dist/commands/apps/show.js +49 -0
  87. package/dist/commands/apps/suspend.d.ts +12 -0
  88. package/dist/commands/apps/suspend.js +35 -0
  89. package/dist/commands/apps/uninstall.d.ts +13 -0
  90. package/dist/commands/apps/uninstall.js +43 -0
  91. package/dist/commands/apps/upgrade.d.ts +14 -0
  92. package/dist/commands/apps/upgrade.js +49 -0
  93. package/dist/commands/apps/version/create.d.ts +14 -0
  94. package/dist/commands/apps/version/create.js +53 -0
  95. package/dist/commands/apps/version/show.d.ts +12 -0
  96. package/dist/commands/apps/version/show.js +39 -0
  97. package/dist/commands/apps/versions.d.ts +12 -0
  98. package/dist/commands/apps/versions.js +40 -0
  99. package/dist/commands/apps/webhooks/list.d.ts +12 -0
  100. package/dist/commands/apps/webhooks/list.js +47 -0
  101. package/dist/commands/characters/list.js +2 -1
  102. package/dist/commands/chats/files/list.js +2 -1
  103. package/dist/commands/chats/folders/list.js +2 -1
  104. package/dist/commands/chats/list.js +2 -1
  105. package/dist/commands/chats/spaces/list.js +2 -1
  106. package/dist/commands/chats/widgets/list.js +2 -1
  107. package/dist/commands/code/jobs/list.js +4 -1
  108. package/dist/commands/commerce/incidents/list.js +2 -1
  109. package/dist/commands/commitments/accounting.js +3 -0
  110. package/dist/commands/commitments/action-proposals.d.ts +8 -0
  111. package/dist/commands/commitments/action-proposals.js +17 -2
  112. package/dist/commands/commitments/cost.d.ts +11 -0
  113. package/dist/commands/commitments/cost.js +25 -0
  114. package/dist/commands/commitments/create.js +6 -1
  115. package/dist/commands/commitments/endpoints/list.js +2 -1
  116. package/dist/commands/commitments/links/list.js +2 -1
  117. package/dist/commands/commitments/list.js +2 -1
  118. package/dist/commands/commitments/liveness.d.ts +30 -0
  119. package/dist/commands/commitments/liveness.js +22 -5
  120. package/dist/commands/commitments/pack/list.js +2 -1
  121. package/dist/commands/commitments/preflight.js +6 -2
  122. package/dist/commands/commitments/update.js +10 -1
  123. package/dist/commands/compass/list.js +2 -1
  124. package/dist/commands/context.js +7 -1
  125. package/dist/commands/convos/list.js +3 -2
  126. package/dist/commands/dm/list.js +2 -1
  127. package/dist/commands/dm/work.d.ts +19 -0
  128. package/dist/commands/dm/work.js +54 -0
  129. package/dist/commands/feeds/list.js +2 -1
  130. package/dist/commands/followups/list.js +2 -1
  131. package/dist/commands/followups/plans/cancel.d.ts +13 -0
  132. package/dist/commands/followups/plans/cancel.js +26 -0
  133. package/dist/commands/followups/plans/create.d.ts +11 -0
  134. package/dist/commands/followups/plans/create.js +37 -0
  135. package/dist/commands/followups/plans/example.d.ts +6 -0
  136. package/dist/commands/followups/plans/example.js +12 -0
  137. package/dist/commands/followups/plans/list.d.ts +13 -0
  138. package/dist/commands/followups/plans/list.js +50 -0
  139. package/dist/commands/followups/plans/observability.d.ts +11 -0
  140. package/dist/commands/followups/plans/observability.js +46 -0
  141. package/dist/commands/followups/plans/revise.d.ts +14 -0
  142. package/dist/commands/followups/plans/revise.js +38 -0
  143. package/dist/commands/followups/plans/show.d.ts +11 -0
  144. package/dist/commands/followups/plans/show.js +32 -0
  145. package/dist/commands/goals/key-results/list.js +2 -1
  146. package/dist/commands/goals/labels/list.js +3 -2
  147. package/dist/commands/goals/list.js +3 -2
  148. package/dist/commands/grants/list.js +2 -1
  149. package/dist/commands/harnesses/grants/list.js +2 -1
  150. package/dist/commands/harnesses/leases/list.js +2 -1
  151. package/dist/commands/harnesses/list.js +10 -1
  152. package/dist/commands/ingress/list.js +2 -1
  153. package/dist/commands/initiatives/list.js +2 -1
  154. package/dist/commands/instruction-blocks/list.js +2 -1
  155. package/dist/commands/instructions/list.js +2 -1
  156. package/dist/commands/integrations/connections/list.js +2 -1
  157. package/dist/commands/integrations/tools/list.js +2 -1
  158. package/dist/commands/labels/list.js +3 -2
  159. package/dist/commands/learning/adapters.d.ts +16 -0
  160. package/dist/commands/learning/adapters.js +44 -0
  161. package/dist/commands/machines/dedicated/list.js +2 -1
  162. package/dist/commands/machines/hosted/list.js +2 -1
  163. package/dist/commands/machines/list.js +2 -1
  164. package/dist/commands/machines/show.js +5 -2
  165. package/dist/commands/measures/list.js +2 -1
  166. package/dist/commands/memory/list.js +2 -1
  167. package/dist/commands/memory/proposals/list.js +2 -1
  168. package/dist/commands/memory/stores/list.js +2 -1
  169. package/dist/commands/memory/topics/list.js +2 -1
  170. package/dist/commands/memory/versions/list.js +2 -1
  171. package/dist/commands/messages/list.js +2 -1
  172. package/dist/commands/northstars/intents/list.js +2 -1
  173. package/dist/commands/northstars/list.js +2 -1
  174. package/dist/commands/northstars/recommendations/list.js +2 -1
  175. package/dist/commands/outbox/list.js +2 -1
  176. package/dist/commands/profiles/list.js +2 -1
  177. package/dist/commands/projects/docs/list.js +8 -1
  178. package/dist/commands/projects/updates/list.js +2 -1
  179. package/dist/commands/proposals/list.js +2 -1
  180. package/dist/commands/requests/comments/list.js +2 -1
  181. package/dist/commands/requests/list.js +2 -1
  182. package/dist/commands/shares/list.js +2 -1
  183. package/dist/commands/shortcuts/list.js +2 -1
  184. package/dist/commands/signals/monitors/list.js +2 -1
  185. package/dist/commands/signals/schemas/list.js +2 -1
  186. package/dist/commands/signals/sources/list.js +2 -1
  187. package/dist/commands/space-directory-views/list.js +2 -1
  188. package/dist/commands/spaces/actions/list.js +4 -3
  189. package/dist/commands/spaces/briefs/list.js +2 -1
  190. package/dist/commands/spaces/cycles/list.js +2 -1
  191. package/dist/commands/spaces/files/folders/list.js +2 -1
  192. package/dist/commands/spaces/files/list.js +3 -2
  193. package/dist/commands/spaces/heartbeats/list.js +3 -2
  194. package/dist/commands/spaces/labels/list.js +3 -2
  195. package/dist/commands/spaces/list.d.ts +3 -18
  196. package/dist/commands/spaces/list.js +28 -35
  197. package/dist/commands/spaces/live/cards/list.js +2 -1
  198. package/dist/commands/spaces/members/list.d.ts +1 -0
  199. package/dist/commands/spaces/members/list.js +4 -1
  200. package/dist/commands/spaces/show.js +2 -2
  201. package/dist/commands/spaces/skills/list.js +6 -2
  202. package/dist/commands/spaces/states/list.js +2 -1
  203. package/dist/commands/spaces/views/list.js +2 -1
  204. package/dist/commands/spaces/widgets/list.js +3 -2
  205. package/dist/commands/spaces/workflow-templates/list.js +2 -1
  206. package/dist/commands/spaces/workflows/fixtures/list.js +2 -1
  207. package/dist/commands/spaces/workflows/list.js +3 -2
  208. package/dist/commands/spaces/workflows/proposals/list.js +2 -1
  209. package/dist/commands/spaces/workflows/triggers/list.js +2 -1
  210. package/dist/commands/store/acquisitions/list.js +2 -1
  211. package/dist/commands/store/admissions/list.js +17 -1
  212. package/dist/commands/store/advisories/list.js +2 -1
  213. package/dist/commands/store/follows/list.js +2 -1
  214. package/dist/commands/store/publishers/domains/list.js +2 -1
  215. package/dist/commands/store/reports/list.js +2 -1
  216. package/dist/commands/subscriptions/list.js +2 -1
  217. package/dist/commands/tasks/actionability.js +7 -30
  218. package/dist/commands/tasks/activity.js +3 -7
  219. package/dist/commands/tasks/approvals/list.js +2 -1
  220. package/dist/commands/tasks/assign.d.ts +1 -0
  221. package/dist/commands/tasks/assign.js +43 -7
  222. package/dist/commands/tasks/attachments/list.js +2 -1
  223. package/dist/commands/tasks/chat/send.js +34 -0
  224. package/dist/commands/tasks/comments/add.js +6 -1
  225. package/dist/commands/tasks/comments/list.js +2 -1
  226. package/dist/commands/tasks/complete.js +26 -2
  227. package/dist/commands/tasks/continue.d.ts +18 -0
  228. package/dist/commands/tasks/continue.js +54 -0
  229. package/dist/commands/tasks/create-tree.d.ts +5 -0
  230. package/dist/commands/tasks/create-tree.js +399 -219
  231. package/dist/commands/tasks/create.d.ts +1 -0
  232. package/dist/commands/tasks/create.js +63 -11
  233. package/dist/commands/tasks/deliverable/add.js +10 -3
  234. package/dist/commands/tasks/deliverable/list.js +2 -1
  235. package/dist/commands/tasks/events/list.js +2 -1
  236. package/dist/commands/tasks/execution-state.d.ts +12 -0
  237. package/dist/commands/tasks/execution-state.js +28 -0
  238. package/dist/commands/tasks/expectations/assess.js +40 -5
  239. package/dist/commands/tasks/guide.d.ts +10 -0
  240. package/dist/commands/tasks/guide.js +20 -0
  241. package/dist/commands/tasks/labels/list.js +2 -1
  242. package/dist/commands/tasks/list.d.ts +19 -0
  243. package/dist/commands/tasks/list.js +97 -4
  244. package/dist/commands/tasks/move.js +10 -2
  245. package/dist/commands/tasks/preflight.d.ts +14 -0
  246. package/dist/commands/tasks/preflight.js +77 -0
  247. package/dist/commands/tasks/resource/list.js +2 -1
  248. package/dist/commands/tasks/result/submit.js +10 -1
  249. package/dist/commands/tasks/review.js +6 -1
  250. package/dist/commands/tasks/revisions.d.ts +2 -0
  251. package/dist/commands/tasks/revisions.js +8 -1
  252. package/dist/commands/tasks/show.js +17 -11
  253. package/dist/commands/tasks/start.d.ts +1 -0
  254. package/dist/commands/tasks/start.js +35 -0
  255. package/dist/commands/tasks/templates/list.js +2 -1
  256. package/dist/commands/tasks/timeline.d.ts +5 -0
  257. package/dist/commands/tasks/timeline.js +9 -1
  258. package/dist/commands/tasks/update.d.ts +1 -0
  259. package/dist/commands/tasks/update.js +25 -2
  260. package/dist/commands/tasks/updates/add.js +6 -1
  261. package/dist/commands/tasks/updates/list.js +2 -1
  262. package/dist/commands/tasks/upsert.d.ts +1 -0
  263. package/dist/commands/tasks/upsert.js +8 -1
  264. package/dist/commands/token/list.js +2 -1
  265. package/dist/commands/tokens/list.js +2 -1
  266. package/dist/commands/tones/list.js +4 -2
  267. package/dist/commands/triggers/list.js +2 -1
  268. package/dist/commands/views/list.js +2 -1
  269. package/dist/commands/webhooks/list.js +2 -1
  270. package/dist/commands/whoami.js +1 -1
  271. package/dist/commands/widgets/list.js +2 -1
  272. package/dist/commands/widgets/save-as-app.d.ts +13 -0
  273. package/dist/commands/widgets/save-as-app.js +65 -0
  274. package/dist/commands/work-views/list.js +2 -1
  275. package/dist/commands/worklog/list.js +2 -1
  276. package/dist/commands/workspaces/list.js +3 -2
  277. package/dist/commands/workspaces/members.d.ts +1 -0
  278. package/dist/commands/workspaces/members.js +5 -2
  279. package/dist/generated/managed-instruction-guides.json +2 -2
  280. package/dist/help.js +7 -0
  281. package/dist/lib/agent-proactive-baseline.d.ts +9 -0
  282. package/dist/lib/agent-proactive-baseline.js +44 -0
  283. package/dist/lib/agentic-stream.d.ts +4 -1
  284. package/dist/lib/agentic-stream.js +29 -4
  285. package/dist/lib/appData.d.ts +75 -0
  286. package/dist/lib/appData.js +274 -0
  287. package/dist/lib/appInstallations.d.ts +117 -0
  288. package/dist/lib/appInstallations.js +960 -0
  289. package/dist/lib/appSettings.d.ts +3 -0
  290. package/dist/lib/appSettings.js +71 -0
  291. package/dist/lib/appWebhooks.d.ts +7 -0
  292. package/dist/lib/appWebhooks.js +59 -0
  293. package/dist/lib/apps-command.d.ts +44 -0
  294. package/dist/lib/apps-command.js +164 -0
  295. package/dist/lib/apps.d.ts +45 -0
  296. package/dist/lib/apps.js +148 -0
  297. package/dist/lib/appsCheck.d.ts +12 -0
  298. package/dist/lib/appsCheck.js +173 -0
  299. package/dist/lib/appsFs.d.ts +58 -0
  300. package/dist/lib/appsFs.js +384 -0
  301. package/dist/lib/auth-failure.d.ts +20 -0
  302. package/dist/lib/auth-failure.js +40 -3
  303. package/dist/lib/cli-installers.d.ts +9 -2
  304. package/dist/lib/command-miss.js +107 -0
  305. package/dist/lib/commitment-loop-status.js +25 -3
  306. package/dist/lib/commitments.d.ts +44 -3
  307. package/dist/lib/commitments.js +107 -9
  308. package/dist/lib/compasses.d.ts +4 -0
  309. package/dist/lib/compasses.js +11 -0
  310. package/dist/lib/daemon-setup.js +7 -7
  311. package/dist/lib/daemonHandoff.js +3 -2
  312. package/dist/lib/dedicated-ssh.d.ts +2 -0
  313. package/dist/lib/dedicated-ssh.js +98 -28
  314. package/dist/lib/json-output.d.ts +33 -0
  315. package/dist/lib/json-output.js +37 -0
  316. package/dist/lib/list-output.d.ts +9 -4
  317. package/dist/lib/list-output.js +36 -9
  318. package/dist/lib/lookbackPlanHelp.d.ts +19 -0
  319. package/dist/lib/lookbackPlanHelp.js +27 -0
  320. package/dist/lib/lookbackPlans.d.ts +22 -0
  321. package/dist/lib/lookbackPlans.js +88 -0
  322. package/dist/lib/machines.d.ts +27 -6
  323. package/dist/lib/machines.js +25 -14
  324. package/dist/lib/member-output.d.ts +20 -0
  325. package/dist/lib/member-output.js +57 -0
  326. package/dist/lib/preflight-copy.d.ts +7 -0
  327. package/dist/lib/preflight-copy.js +31 -0
  328. package/dist/lib/roles.d.ts +2 -2
  329. package/dist/lib/task-admission.d.ts +9 -0
  330. package/dist/lib/task-admission.js +35 -0
  331. package/dist/lib/task-batch.d.ts +4 -0
  332. package/dist/lib/task-batch.js +2 -0
  333. package/dist/lib/task-operations.d.ts +25 -0
  334. package/dist/lib/task-operations.js +123 -0
  335. package/dist/lib/task-preflight.d.ts +35 -0
  336. package/dist/lib/task-preflight.js +121 -0
  337. package/dist/lib/task-resource-references.d.ts +23 -0
  338. package/dist/lib/task-resource-references.js +119 -0
  339. package/dist/lib/task-spec-verification.d.ts +42 -0
  340. package/dist/lib/task-spec-verification.js +101 -0
  341. package/dist/lib/task-work.d.ts +11 -0
  342. package/dist/lib/task-work.js +41 -0
  343. package/dist/lib/task-write-attribution.d.ts +26 -0
  344. package/dist/lib/task-write-attribution.js +47 -0
  345. package/dist/lib/tasks.d.ts +13 -0
  346. package/dist/lib/tasks.js +61 -8
  347. package/dist/lib/triggers.d.ts +7 -0
  348. package/dist/lib/triggers.js +54 -4
  349. package/dist/lib/usage-discovery.d.ts +4 -0
  350. package/dist/lib/usage-discovery.js +14 -4
  351. package/dist/lib/widgetApps.d.ts +10 -0
  352. package/dist/lib/widgetApps.js +47 -0
  353. package/dist/lib/widgetStaticScan.js +25 -1
  354. package/dist/lib/workspaces.d.ts +11 -4
  355. package/dist/lib/workspaces.js +7 -3
  356. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +14 -1
  357. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +47 -2
  358. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.d.ts +49 -1
  359. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +26 -0
  360. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.d.ts +118 -0
  361. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +614 -0
  362. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.d.ts +2 -0
  363. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +15 -2
  364. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refreshClassification.d.ts +5 -0
  365. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refreshClassification.js +3 -1
  366. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionRevocation.d.ts +177 -0
  367. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/sessionRevocation.js +484 -0
  368. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.d.ts +11 -0
  369. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.js +46 -7
  370. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.d.ts +232 -0
  371. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.js +372 -0
  372. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/types.d.ts +17 -1
  373. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/types.js +12 -1
  374. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +14 -1
  375. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +45 -2
  376. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.d.ts +49 -1
  377. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +24 -0
  378. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.d.ts +118 -0
  379. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +608 -0
  380. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.d.ts +2 -0
  381. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +15 -2
  382. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refreshClassification.d.ts +5 -0
  383. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refreshClassification.js +3 -1
  384. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionRevocation.d.ts +177 -0
  385. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/sessionRevocation.js +472 -0
  386. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.d.ts +11 -0
  387. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.js +44 -6
  388. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.d.ts +232 -0
  389. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.js +360 -0
  390. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/types.d.ts +17 -1
  391. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/types.js +12 -1
  392. package/dist/node_modules/@skrr-ai/auth-core/package.json +30 -0
  393. package/dist/node_modules/@skrr-ai/data-provider/index.js +25245 -18730
  394. package/docs/v1/README.md +1 -0
  395. package/docs/v1/lookback-plans.md +88 -0
  396. package/docs/v1/operations.md +52 -0
  397. package/docs/v1/space-search.md +19 -0
  398. package/oclif.manifest.json +4792 -477
  399. package/package.json +27 -3
@@ -0,0 +1,960 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REPORT_REFUSAL_CODES = exports.INSTALLATION_REFUSAL_CODES = exports.ALL_INSTALLATION_REFUSAL_CODES = exports.InstallTargetError = void 0;
4
+ exports.describeAvailability = describeAvailability;
5
+ exports.describeTrust = describeTrust;
6
+ exports.describeTrustShort = describeTrustShort;
7
+ exports.formatInstallationRow = formatInstallationRow;
8
+ exports.describeJobScheduling = describeJobScheduling;
9
+ exports.formatJobStates = formatJobStates;
10
+ exports.describeGrantReasons = describeGrantReasons;
11
+ exports.formatDisclosure = formatDisclosure;
12
+ exports.describeHostUnsuitable = describeHostUnsuitable;
13
+ exports.describeOperatorUnmet = describeOperatorUnmet;
14
+ exports.formatBindings = formatBindings;
15
+ exports.formatHosting = formatHosting;
16
+ exports.describeBindingRefusal = describeBindingRefusal;
17
+ exports.describeDisclosureCheck = describeDisclosureCheck;
18
+ exports.resolveInstallTarget = resolveInstallTarget;
19
+ exports.describeInstallationConflict = describeInstallationConflict;
20
+ exports.formatScopeIssues = formatScopeIssues;
21
+ exports.resolveInstallPrincipal = resolveInstallPrincipal;
22
+ exports.formatUserLayout = formatUserLayout;
23
+ exports.readLayoutRefusal = readLayoutRefusal;
24
+ exports.describeReportRefusal = describeReportRefusal;
25
+ exports.installationRefusalExit = installationRefusalExit;
26
+ /**
27
+ * `skrr apps install | installations | reconsent | upgrade | suspend | resume | uninstall | disclosure`: what
28
+ * the installation commands share. The second half of the domain lib of the Agent App commands; the first,
29
+ * `lib/apps.ts`, is the authoring loop's.
30
+ *
31
+ * It builds no URL. Every call to the API is a `dataService` function (`@skrr-ai/data-provider`), which is
32
+ * what keeps this CLI, the web install dialog and the host window on one set of routes (and what
33
+ * `domain-api-parity.spec.ts` checks). What lives here is what a terminal needs around them:
34
+ *
35
+ * - saying a DISCLOSURE in words. It is the same data the web dialog draws (`parseAppDisclosure`), written as
36
+ * what the app CAN DO and never as a permission key, with the unattended jobs said in the same sentence
37
+ * that says whose authority they run under (owner decision D35 accepted that risk on the condition that
38
+ * the install screen says so, and a terminal is an install screen);
39
+ * - choosing what an `install` points at (an app, a version, the bundle the person was shown);
40
+ * - saying why an installation call was refused, in the contract's closed vocabulary of reasons, with the
41
+ * next step.
42
+ */
43
+ const data_provider_1 = require("@skrr-ai/data-provider");
44
+ // ── what an installation is, in a line ──────────────────────────────────────
45
+ const AVAILABILITY_WORDS = {
46
+ ready: 'ready',
47
+ suspended: 'paused',
48
+ needs_reconsent: 'needs your approval again',
49
+ unavailable: 'cannot be read now',
50
+ };
51
+ /**
52
+ * The words for an availability the contract names. One this CLI does not know (a server newer than the CLI) is said
53
+ * as it came and as NOT recognised, never as "ready" and never as nothing.
54
+ */
55
+ function describeAvailability(availability) {
56
+ if (typeof availability !== 'string') {
57
+ return 'unknown';
58
+ }
59
+ return (AVAILABILITY_WORDS[availability] ??
60
+ `${(0, data_provider_1.plainAppLabel)(availability, 40)} (not recognised: update the CLI)`);
61
+ }
62
+ /**
63
+ * How far an app is trusted, in a sentence. `reviewed` names no person: there is no human review, and an automatic
64
+ * check is not a statement that an app is safe. `workspace` says what is recorded (published to a workspace and
65
+ * marked approved), not who approved it: nothing here knows.
66
+ */
67
+ const TRUST_WORDS = {
68
+ platform: 'built in',
69
+ reviewed: 'public; only automatic checks have looked at it (no person has reviewed it, and the checks do not show it is safe)',
70
+ workspace: 'published to a workspace and marked approved (who approved it is not recorded here)',
71
+ self: 'private: nobody but its maker has looked at it',
72
+ };
73
+ function describeTrust(trust) {
74
+ return typeof trust === 'string' ? (TRUST_WORDS[trust] ?? trust) : 'unknown';
75
+ }
76
+ /** The same four tiers in a few words, for a table: never the raw tier word, which reads as a verdict. */
77
+ const TRUST_SHORT = {
78
+ platform: 'built in',
79
+ reviewed: 'automatic checks only',
80
+ workspace: 'workspace',
81
+ self: 'private',
82
+ };
83
+ function describeTrustShort(trust) {
84
+ return typeof trust === 'string' ? (TRUST_SHORT[trust] ?? trust) : 'unknown';
85
+ }
86
+ /**
87
+ * A table row of the apps installed on a principal. When the platform did not schedule some of the app's jobs (refused, or
88
+ * chose not to run) the row says how many at its end, and when it has not confirmed some (nothing is recorded for the
89
+ * version the app runs now) it says that, as its own count: "the platform said no" and "nobody has said anything" are
90
+ * different facts, and a row that counted only the first read an app whose every job is unconfirmed the same as a healthy
91
+ * one. Neither count is a verdict on the others, and neither says anything reassuring; `show` says which jobs and why. A row
92
+ * with nothing to say is the row it was (a job the person deleted the schedule of is their own choice, and adds nothing).
93
+ */
94
+ function formatInstallationRow(item) {
95
+ const { notScheduled, notConfirmed } = (0, data_provider_1.summarizeAppJobStates)(item.jobState);
96
+ const jobs = (count) => `${count} ${count === 1 ? 'job' : 'jobs'}`;
97
+ return [
98
+ item.id,
99
+ (item.name ?? item.slug ?? item.appId).padEnd(24),
100
+ `v${item.version ?? '?'}`.padEnd(5),
101
+ describeAvailability(item.availability).padEnd(26),
102
+ describeTrustShort(item.trust),
103
+ ...(notScheduled > 0 ? [`${jobs(notScheduled)} not scheduled`] : []),
104
+ ...(notConfirmed > 0 ? [`${jobs(notConfirmed)} not confirmed`] : []),
105
+ ].join(' ');
106
+ }
107
+ // ── the disclosure, in words ────────────────────────────────────────────────
108
+ const CONSENT_MARK = {
109
+ new: ' [new: you have not approved this]',
110
+ granted: '',
111
+ stale: ' [approved for different code: approve again]',
112
+ changed: ' [changed since you approved it]',
113
+ };
114
+ function mark(consent) {
115
+ return CONSENT_MARK[consent] ?? '';
116
+ }
117
+ const ISOLATION_WORDS = {
118
+ none: 'no isolation beyond the machine it runs on',
119
+ gvisor: 'inside a gVisor sandbox',
120
+ microvm: 'inside its own microVM',
121
+ };
122
+ /**
123
+ * Who can change a collection, as the words in the brackets. "The app's own code can change it" and "only your
124
+ * agent can change it" are different promises, so they are different sentences.
125
+ */
126
+ const STORE_WRITER_WORDS = {
127
+ app_and_agent: "the app's own code can read and change it, including what your agent writes there",
128
+ app: "the app's own code can read and change it",
129
+ person_and_agent: "only people and your agent can change it; the app's own code can only read it",
130
+ agent: "only your agent can change it; the app's own code can only read it",
131
+ person: "only people can change it; the app's own code can only read it",
132
+ };
133
+ /** A job's schedule in words, beside the text the author wrote (which is always still shown). */
134
+ function describeSchedule(schedule) {
135
+ const reading = (0, data_provider_1.readAppJobSchedule)(schedule);
136
+ switch (reading.kind) {
137
+ case 'daily':
138
+ return `every day at ${reading.times.join(' and ')}`;
139
+ case 'every':
140
+ return `every ${reading.count === 1 ? reading.unit.replace(/s$/, '') : `${reading.count} ${reading.unit}`}`;
141
+ case 'configured':
142
+ return "on a schedule set in the app's settings";
143
+ default:
144
+ return 'a schedule this CLI cannot read';
145
+ }
146
+ }
147
+ const DISABLE_REASON_WORDS = {
148
+ installation_suspended: 'the app is paused',
149
+ needs_reconsent: 'the app needs your approval again',
150
+ job_not_authorized: "you haven't approved this job as it is now",
151
+ schedule_invalid: "its schedule can't run",
152
+ guide_unavailable: "its guide can't be read",
153
+ circuit_open: 'turned off after repeated failures',
154
+ };
155
+ const PAUSE_AND_RESUME = 'then `skrr apps suspend <installation>` and `skrr apps resume <installation>`';
156
+ /**
157
+ * Why the platform could NOT make an installed job's trigger (the jobs reconciler's refusal, recorded on the installation),
158
+ * one clause and one next step for each member of the contract's closed list. A `Record` over the list does not compile
159
+ * without words for a new reason. The reconciler used to say these only in a server log: an app that was installed and
160
+ * approved could have a job that never ran with nothing here to say why.
161
+ */
162
+ const SCHEDULING_REFUSAL_WORDS = {
163
+ trigger_quota: {
164
+ what: "you've reached your limit on scheduled triggers",
165
+ next: `Turn off or delete a trigger you no longer need (\`skrr triggers list\`), ${PAUSE_AND_RESUME} to try again.`,
166
+ },
167
+ installer_cannot_manage_agent: {
168
+ what: "you can't manage the agent this app is installed on",
169
+ next: `Scheduling a job needs the same access as creating a trigger on that agent. Ask the agent's owner for that access, ${PAUSE_AND_RESUME}.`,
170
+ },
171
+ agent_missing: {
172
+ what: "the agent this app is installed on can't be found",
173
+ next: 'It may have been deleted. Install the app on another agent.',
174
+ },
175
+ schedule_refused: {
176
+ what: 'its schedule was refused',
177
+ next: "The scheduler didn't accept this job's schedule or your time zone. Check your time zone; if it is right, the app's author has to change the schedule in the manifest.",
178
+ },
179
+ prompt_too_long: {
180
+ what: 'its guide is too long for a trigger',
181
+ next: "The app's author has to shorten the guide this job follows and publish a new version.",
182
+ },
183
+ prompt_refused: {
184
+ what: 'its guide was refused',
185
+ next: "The scheduler didn't accept the text of the guide this job follows. The app's author has to change the guide and publish a new version.",
186
+ },
187
+ consent_refused: {
188
+ what: "your approval for this job couldn't be recorded",
189
+ next: 'Approve the app again with `skrr apps reconsent <installation> --yes`. If it keeps happening, tell whoever made the app.',
190
+ },
191
+ input_refused: {
192
+ what: "the scheduler didn't accept this job",
193
+ next: "Something in the job isn't something a trigger can hold, and you can't fix it from here. The app's author has to change the job in the manifest.",
194
+ },
195
+ error: {
196
+ what: "the platform couldn't set it up",
197
+ next: `The reason is not one this CLI has words for. Try again (${PAUSE_AND_RESUME}) and tell whoever made the app if it keeps happening.`,
198
+ },
199
+ };
200
+ /** Why the platform chose NOT to schedule a job. The same reasons as `DISABLE_REASON_WORDS`, each with its next step. */
201
+ const NOT_SCHEDULED_WORDS = {
202
+ installation_suspended: {
203
+ what: 'the app is paused',
204
+ next: "Resume it with `skrr apps resume <installation>`. A pause the platform set can't be lifted by you.",
205
+ },
206
+ needs_reconsent: {
207
+ what: 'the app needs your approval again',
208
+ next: 'Review what changed with `skrr apps disclosure`, then approve with `skrr apps reconsent <installation> --yes`.',
209
+ },
210
+ job_not_authorized: {
211
+ what: "this job isn't approved to run",
212
+ next: "Approve the app again with `skrr apps reconsent <installation> --yes`. If that doesn't help, the agent or the person who approved it may have been removed: install the app again.",
213
+ },
214
+ schedule_invalid: {
215
+ what: "its schedule can't run",
216
+ next: "If the schedule uses a setting of the app, check that setting. Otherwise the app's author has to fix the schedule in the manifest.",
217
+ },
218
+ guide_unavailable: {
219
+ what: "its guide can't be used",
220
+ next: "The guide this job follows is missing, unreadable or too long. The app's author has to fix it and publish a new version.",
221
+ },
222
+ circuit_open: {
223
+ what: 'it was turned off after repeated failures',
224
+ next: "Look at the job's last runs (`skrr triggers list`), then turn it back on once you've decided it should run.",
225
+ },
226
+ };
227
+ const UNKNOWN_NOT_SCHEDULED_WORDS = {
228
+ what: 'the platform gave a reason this CLI does not know',
229
+ next: 'Update the CLI (`skrr update`) and look again.',
230
+ };
231
+ const NOT_RECORDED_WORDS = {
232
+ what: "the platform hasn't recorded whether this job is scheduled",
233
+ next: 'Pausing the app and resuming it checks again (`skrr apps suspend <installation>`, then `skrr apps resume <installation>`).',
234
+ };
235
+ /**
236
+ * A job's scheduling state, in words: `null` when it is scheduled (nothing to say). A state with something to say returns
237
+ * the clause and the next step; `unknown` is NEVER null, because "nobody recorded it" reads as "fine" when it is silent.
238
+ */
239
+ function describeJobScheduling(jobState) {
240
+ if (!jobState || typeof jobState !== 'object') {
241
+ return null;
242
+ }
243
+ switch (jobState.state) {
244
+ case 'scheduled':
245
+ return null;
246
+ case 'refused': {
247
+ const words = (0, data_provider_1.isAppJobRefusalReason)(jobState.reason)
248
+ ? SCHEDULING_REFUSAL_WORDS[jobState.reason]
249
+ : SCHEDULING_REFUSAL_WORDS.error;
250
+ return { state: 'refused', ...words };
251
+ }
252
+ case 'not_runnable': {
253
+ const words = (0, data_provider_1.isAppJobDisableReason)(jobState.reason)
254
+ ? NOT_SCHEDULED_WORDS[jobState.reason]
255
+ : UNKNOWN_NOT_SCHEDULED_WORDS;
256
+ return { state: 'not_runnable', ...words };
257
+ }
258
+ case 'removed_by_person':
259
+ return {
260
+ state: 'removed_by_person',
261
+ what: 'you deleted its schedule; it stays deleted for this version',
262
+ next: null,
263
+ };
264
+ default:
265
+ return { state: 'unknown', ...NOT_RECORDED_WORDS };
266
+ }
267
+ }
268
+ /** The lines `skrr apps installations show` prints for the jobs' states: one per job, the reason and the next step under a job that is not scheduled. */
269
+ function formatJobStates(jobStates, installationId) {
270
+ if (!Array.isArray(jobStates)) {
271
+ // a server that predates the record: say so, since silence would read as "all scheduled"
272
+ return [' (this server does not say whether the jobs are scheduled)'];
273
+ }
274
+ const lines = [];
275
+ for (const job of jobStates) {
276
+ const words = describeJobScheduling(job);
277
+ if (!words) {
278
+ lines.push(` job ${(0, data_provider_1.plainAppLabel)(job.id, 64)}: scheduled`);
279
+ continue;
280
+ }
281
+ lines.push(` job ${(0, data_provider_1.plainAppLabel)(job.id, 64)}: NOT SCHEDULED: ${words.what}`);
282
+ if (words.next) {
283
+ lines.push(` next: ${words.next.replace(/<installation>/g, installationId)}`);
284
+ }
285
+ }
286
+ return lines;
287
+ }
288
+ /**
289
+ * What became of a job's trigger, when the server says (an installed app). `managed` is the ordinary case and says
290
+ * nothing; every other state is said, because a job that does not run and a job that does must not read alike.
291
+ */
292
+ function describeJobState(job) {
293
+ const scheduling = describeJobScheduling(job.jobState);
294
+ // The platform tried to schedule it and was REFUSED: the most useful thing to read, even when an older trigger is
295
+ // still there (it runs the text from before the refusal).
296
+ if (scheduling?.state === 'refused') {
297
+ return ` [NOT SCHEDULED: ${scheduling.what}]`;
298
+ }
299
+ const trigger = job.trigger;
300
+ if (trigger) {
301
+ switch (trigger.state) {
302
+ case 'paused_by_person':
303
+ return ' [you turned this job off]';
304
+ case 'paused_by_platform': {
305
+ const reason = trigger.platformDisabled?.reason;
306
+ const words = reason ? (DISABLE_REASON_WORDS[reason] ?? reason) : 'no reason recorded';
307
+ return ` [turned off by the platform: ${words}]`;
308
+ }
309
+ case 'removed_by_person':
310
+ return ' [you deleted its schedule; it stays deleted for this version]';
311
+ default:
312
+ break;
313
+ }
314
+ }
315
+ // no trigger to speak for the job: what the platform recorded about it, or that it recorded nothing
316
+ if (scheduling && scheduling.state !== 'unknown') {
317
+ return ` [not scheduled: ${scheduling.what}]`;
318
+ }
319
+ if (trigger?.state === 'missing') {
320
+ return scheduling
321
+ ? ` [not scheduled right now; ${scheduling.what}]`
322
+ : ' [not scheduled right now]';
323
+ }
324
+ if (scheduling && !trigger) {
325
+ return ` [${scheduling.what}]`;
326
+ }
327
+ return '';
328
+ }
329
+ /** The next step for a job whose state has one, as the line under it. */
330
+ function jobNextLine(job) {
331
+ const scheduling = describeJobScheduling(job.jobState);
332
+ const stateReason = scheduling && scheduling.state !== 'removed_by_person' ? scheduling : null;
333
+ if (!stateReason?.next) {
334
+ return [];
335
+ }
336
+ // a live trigger vouches for a job nothing is recorded for
337
+ const live = job.trigger?.state === 'managed' || job.trigger?.state === 'detached';
338
+ if (stateReason.state === 'unknown' && live) {
339
+ return [];
340
+ }
341
+ return [` next: ${stateReason.next.replace(/<installation>/g, '<installation id>')}`];
342
+ }
343
+ function itemLines(item) {
344
+ switch (item.kind) {
345
+ case 'store':
346
+ return item.collections.map((collection) => {
347
+ // a server that predates `writers` is drawn from `access` alone
348
+ const summary = collection.writers
349
+ ? (0, data_provider_1.appStoreWriterSummary)(collection.writers.map((writer) => writer.kind))
350
+ : null;
351
+ let words = collection.access === 'read_write' ? 'it can read and change it' : 'it can only read it';
352
+ if (summary) {
353
+ words = STORE_WRITER_WORDS[summary];
354
+ }
355
+ return `keep its own data in "${collection.name}" (${words})${mark(collection.consent)}`;
356
+ });
357
+ case 'query':
358
+ return item.contracts.map((contract) => `read "${contract.name}" from the platform, as whoever is looking (each person sees only what they may see)${mark(contract.consent)}`);
359
+ case 'tools':
360
+ return item.tools.map((tool) => `call the tool "${tool.name}"${tool.connector ? ` (your ${tool.connector} connection)` : ''}${mark(tool.consent)}`);
361
+ case 'http':
362
+ return item.origins.map((origin) => `have ${data_provider_1.BRAND.displayName} contact ${origin.origin} for it (the app's page has no network of its own); this stops working if the app's code changes, until you approve again${mark(origin.consent)}`);
363
+ case 'act':
364
+ return item.effects.map((effect) => `ask to "${effect.effect}"; it only asks, and a person releases each one under their own name${mark(effect.consent)}`);
365
+ case 'webhooks':
366
+ return item.hooks.map((hook) => `let an outside system that holds a secret address add entries to "${hook.collection}" (the hook "${hook.name}"${hook.title ? `, "${hook.title}"` : ''}); entries are only stored there, nothing runs because one arrived${mark(hook.consent)}`);
367
+ case 'service': {
368
+ const declaration = item.declaration;
369
+ const lines = [
370
+ `run a background program (${declaration.protocol}, ${declaration.liveness.replace(/_/g, ' ')}), ${ISOLATION_WORDS[declaration.isolation] ?? declaration.isolation}; this stops working if the app's code changes, until you approve again${mark(item.consent)}`,
371
+ ` command: ${declaration.command.join(' ')}`,
372
+ ];
373
+ if (declaration.secretNames.length > 0) {
374
+ lines.push(` uses secrets named: ${declaration.secretNames.join(', ')} (names only)`);
375
+ }
376
+ // the disclosure has no field for either, and a silence here would read as "none": say it is not told
377
+ lines.push(" what it can reach on the network, and which machine it runs on, are not part of this disclosure (the app's page having no network of its own says nothing about this program)");
378
+ return lines;
379
+ }
380
+ case 'jobs':
381
+ return [
382
+ `run these jobs on a schedule, unattended. ${item.statement} That is accepted when you install it, and each job is listed so you can weigh it:`,
383
+ ...item.jobs.flatMap((job) => [
384
+ ` - ${(0, data_provider_1.plainAppLabel)(job.title)} (${job.schedule}): ${describeSchedule(job.schedule)}${job.guide ? `, following ${job.guide}` : ''}${mark(job.consent)}${describeJobState(job)}`,
385
+ ...jobNextLine(job),
386
+ ]),
387
+ ...(item.notices?.some((notice) => notice.kind === 'trigger_detached')
388
+ ? [
389
+ ' (a job someone edited in Triggers no longer follows this app: an upgrade will not change it)',
390
+ ]
391
+ : []),
392
+ ];
393
+ default:
394
+ return [];
395
+ }
396
+ }
397
+ const REASON_WORDS = {
398
+ no_grant: 'nothing has been approved yet',
399
+ capability_added: 'this version asks for something the earlier one did not',
400
+ capability_expanded: 'this version asks for more than was approved',
401
+ egress_code_changed: `the app changed, and what it may send out of ${data_provider_1.BRAND.displayName} is approved only for the code you saw`,
402
+ jobs_changed: 'a job was added or changed',
403
+ store_writers_expanded: "this version lets something new change the data the app keeps, such as the app's own code",
404
+ };
405
+ /** The words for each reason a grant stopped covering a version; a kind it does not know is said as it came. */
406
+ function describeGrantReasons(kinds) {
407
+ const words = REASON_WORDS;
408
+ return kinds.map((kind) => words[kind] ?? kind);
409
+ }
410
+ /**
411
+ * A disclosure as the lines a person reads before they approve. `null` (a disclosure this CLI cannot read) is
412
+ * said plainly: "cannot show what you would be approving" is never "nothing to approve".
413
+ */
414
+ function formatDisclosure(raw, facts) {
415
+ const disclosure = (0, data_provider_1.parseAppDisclosure)(raw);
416
+ if (!disclosure) {
417
+ return [
418
+ 'This disclosure is not in a form this version of the CLI understands, so it cannot show what you would be approving.',
419
+ 'Update the CLI (`skrr update`) and try again.',
420
+ ];
421
+ }
422
+ const lines = [];
423
+ lines.push(`${disclosure.app.name}${disclosure.bundleHash ? ` (bundle ${disclosure.bundleHash.slice(0, 12)})` : ''}`);
424
+ if (facts) {
425
+ // who is asking to be trusted, beside what it asks
426
+ lines.push(`Version ${facts.version}, published by ${facts.publisher.name ?? 'someone the platform cannot name'}; ${describeTrust(facts.trust)}.`);
427
+ }
428
+ if (disclosure.app.description) {
429
+ lines.push(disclosure.app.description);
430
+ }
431
+ if (disclosure.scope) {
432
+ // WHERE it is installed, and no claim about how far it reaches: the list below says what it can do, and a
433
+ // sentence that said "nothing else" over a list with jobs, tools and outbound requests would contradict it
434
+ if (disclosure.scope.principal.kind === 'user') {
435
+ // an app on a PERSON: say whose it is and what that means in words, and what does not happen for it yet
436
+ lines.push('Installed on you. It is private to your account: what it keeps is not visible to any other person through it (your own sign-ins, and tools you give your account to, can see it as you can), and what it reads from the platform it reads as you.');
437
+ }
438
+ else {
439
+ lines.push(`Installed on ${disclosure.scope.principal.kind} ${disclosure.scope.principal.id}.`);
440
+ }
441
+ }
442
+ if (disclosure.can.length === 0) {
443
+ lines.push('It asks for nothing: it can only draw itself.');
444
+ }
445
+ else {
446
+ lines.push('It can:');
447
+ for (const item of disclosure.can) {
448
+ const [first, ...rest] = itemLines(item);
449
+ if (first !== undefined) {
450
+ lines.push(` - ${first}`);
451
+ lines.push(...rest.map((line) => ` ${line.replace(/^ {4}/, '')}`.replace(/^ {4}(?=- )/, ' ')));
452
+ }
453
+ }
454
+ }
455
+ if (disclosure.consent.status === 'needs_reconsent') {
456
+ lines.push('Why it needs approving again:');
457
+ for (const reason of describeGrantReasons(disclosure.consent.reasons.map((r) => r.kind))) {
458
+ lines.push(` - ${reason}`);
459
+ }
460
+ }
461
+ else if (disclosure.consent.status === 'valid') {
462
+ lines.push('What you approved still covers this version.');
463
+ }
464
+ lines.push(...describeDisclosureCheck(disclosure.check));
465
+ return lines;
466
+ }
467
+ // ── where it runs, and what that costs (p2-11, p2-06) ───────────────────────
468
+ /** US dollars, whole when they are whole. Every figure it is given is the server's arithmetic over a rate. */
469
+ function usd(cents) {
470
+ const dollars = cents / 100;
471
+ return new Intl.NumberFormat('en-US', {
472
+ style: 'currency',
473
+ currency: 'USD',
474
+ minimumFractionDigits: Number.isInteger(dollars) ? 0 : 2,
475
+ maximumFractionDigits: 2,
476
+ }).format(dollars);
477
+ }
478
+ /** Why a computer that said what it can run still cannot run this: what it has, against what the app asks for. */
479
+ const HOST_CAPABILITY_WORDS = {
480
+ os_unsupported: (required, offered) => `it runs ${offered}; the app needs ${required}`,
481
+ arch_unsupported: (required, offered) => `it is a ${offered} computer; the app needs ${required}`,
482
+ runtime_missing: (required, offered) => `the app needs ${required} installed; it has ${offered}`,
483
+ isolation_insufficient: (required, offered) => `the app asks to be isolated at "${required}"; it offers "${offered}"`,
484
+ availability_insufficient: (required, offered) => `the app needs a computer that is ${required}; this one is ${offered}`,
485
+ persistent_fs_missing: () => 'the app keeps files, and it has no storage that survives a restart',
486
+ ingress_relay_missing: () => 'the app gateway cannot reach it yet; it may need an update',
487
+ supervision_missing: () => 'it has no way to keep a program running',
488
+ };
489
+ function describeHostUnsuitable(reason) {
490
+ switch (reason.kind) {
491
+ case 'not_announced':
492
+ return 'it has not said what it can run, so the app cannot be placed on it yet';
493
+ case 'gone':
494
+ return 'it is being removed, or it is gone';
495
+ default:
496
+ return HOST_CAPABILITY_WORDS[reason.code]((0, data_provider_1.plainAppLabel)(reason.required, 80), (0, data_provider_1.plainAppLabel)(reason.offered, 80));
497
+ }
498
+ }
499
+ /** What an app asked of its Agent, as a phrase. The name is the author's word, reduced to printable text. */
500
+ function describeRequirement(requirement) {
501
+ const colon = requirement.indexOf(':');
502
+ const kind = colon === -1 ? '' : requirement.slice(0, colon);
503
+ const name = (0, data_provider_1.plainAppLabel)(colon === -1 ? requirement : requirement.slice(colon + 1), 80);
504
+ const nouns = {
505
+ skill: 'the skill',
506
+ connector: 'the connection',
507
+ tool: 'the tool',
508
+ lineage: 'the Agent line',
509
+ };
510
+ return nouns[kind] ? `${nouns[kind]} "${name}"` : name;
511
+ }
512
+ function describeOperatorUnmet(unmet) {
513
+ const what = describeRequirement(unmet.requirement);
514
+ return unmet.verdict === 'missing'
515
+ ? `it does not have ${what}`
516
+ : `we cannot tell whether it has ${what}`;
517
+ }
518
+ /** What an install was MISSING. The first is the design's sentence: install it on an Agent, or choose one to run it. */
519
+ const BINDING_ISSUE_WORDS = {
520
+ operator_required: 'This app needs an Agent to run it. Install it on one of your Agents instead, or choose an Agent to run it.',
521
+ host_machine_required: 'This app needs a computer to run on. Choose one of yours with --host-machine.',
522
+ };
523
+ /**
524
+ * The choices an install has to settle, as lines. `undefined` is "this app needs no choice" and says nothing; a block this
525
+ * CLI cannot read is said so, and is never "nothing to choose".
526
+ */
527
+ function formatBindings(raw) {
528
+ if (raw === undefined) {
529
+ return [];
530
+ }
531
+ const bindings = (0, data_provider_1.parseAppBindings)(raw);
532
+ if (!bindings) {
533
+ return [
534
+ 'This server sent the choices this app needs in a form this version of the CLI does not understand, so it cannot show them. Update the CLI and try again.',
535
+ ];
536
+ }
537
+ const lines = [];
538
+ if (bindings.needs.operator === 'choose') {
539
+ lines.push(bindings.role
540
+ ? `Choose which of your Agents plays "${(0, data_provider_1.plainAppLabel)(bindings.role, 60)}" for this app:`
541
+ : 'Choose which of your Agents runs this app:');
542
+ const usable = bindings.operators.filter((entry) => entry.verdict.ok);
543
+ if (usable.length === 0) {
544
+ lines.push(' You have no Agent you can use here. Install it on one of your Agents instead.');
545
+ }
546
+ for (const entry of usable) {
547
+ lines.push(` - ${entry.id} ${(0, data_provider_1.plainAppLabel)(entry.name, 120)}`);
548
+ }
549
+ for (const entry of bindings.operators) {
550
+ if (!entry.verdict.ok) {
551
+ lines.push(` x ${entry.id} ${(0, data_provider_1.plainAppLabel)(entry.name, 120)}: ${entry.verdict.unmet
552
+ .map(describeOperatorUnmet)
553
+ .join('; ')}`);
554
+ }
555
+ }
556
+ }
557
+ if (bindings.needs.hostMachine === 'choose') {
558
+ lines.push('This app has a background program. Choose which of your computers runs it (--host-machine):');
559
+ const usable = bindings.machines.filter((entry) => entry.verdict.ok);
560
+ if (bindings.machines.length === 0) {
561
+ lines.push(' You do not have a computer to run it on yet. Get one first.');
562
+ }
563
+ else if (usable.length === 0) {
564
+ lines.push(' None of your computers can run this yet.');
565
+ }
566
+ for (const entry of usable) {
567
+ lines.push(` - ${entry.id} ${(0, data_provider_1.plainAppLabel)(entry.name, 120) || 'Unnamed computer'}`);
568
+ }
569
+ for (const entry of bindings.machines) {
570
+ if (!entry.verdict.ok) {
571
+ lines.push(` x ${entry.id} ${(0, data_provider_1.plainAppLabel)(entry.name, 120) || 'Unnamed computer'}: ${entry.verdict.reasons
572
+ .map(describeHostUnsuitable)
573
+ .join('; ')}`);
574
+ }
575
+ }
576
+ }
577
+ if (bindings.truncated) {
578
+ lines.push(' (This list may be incomplete.)');
579
+ }
580
+ return lines;
581
+ }
582
+ const COST_ADDED_WORDS = {
583
+ nothing: ({ machine }) => `${machine} is set to stay on, so it already runs all month. This app adds no compute charge.`,
584
+ keeps_on: ({ monthlyCents }) => `This app needs the computer on all the time, so it keeps it running: about ${usd(monthlyCents ?? 0)} a month.`,
585
+ usage_example: ({ monthlyCents, usageHoursPerDay, idleTailMinutes }) => `For example, if you use it about ${usageHoursPerDay} hours a day and the computer stays on ${idleTailMinutes} minutes after you stop, that comes to about ${usd(monthlyCents ?? 0)} a month.`,
586
+ by_the_hour: () => 'How much it adds depends on how often and for how long the computer runs for it, so no monthly figure is given.',
587
+ };
588
+ /**
589
+ * What the app's service would cost, as lines. Every figure is the server's arithmetic over the computer's rate; nothing
590
+ * here is an amount written in advance, and a state without a number says why and is never zero. `undefined` is "this app
591
+ * has no service" and says nothing.
592
+ */
593
+ function formatHosting(raw) {
594
+ if (raw === undefined) {
595
+ return [];
596
+ }
597
+ const cost = (0, data_provider_1.parseAppServiceCost)(raw);
598
+ if (!cost) {
599
+ return ['What running it costs: this CLI could not read the estimate, so it shows none.'];
600
+ }
601
+ switch (cost.state) {
602
+ case 'needs_machine':
603
+ return [
604
+ 'What running it costs: this app runs a program on a computer, and you do not have one that can run apps yet. What it costs depends on that computer, so no figure is given.',
605
+ ];
606
+ case 'select_machine':
607
+ return [
608
+ 'What running it costs: choose the computer it will run on (--host-machine) to see what it would bill.',
609
+ ];
610
+ case 'unpriced':
611
+ return [
612
+ `What running it costs: ${(0, data_provider_1.plainAppLabel)(cost.machine.name, 120) || 'that computer'} has no price on record, so what this would cost is not known. Nothing is assumed.`,
613
+ ];
614
+ case 'unknown':
615
+ return [
616
+ 'What running it costs: we could not work out what this would cost. The computer bills by the hour it is running.',
617
+ ];
618
+ default: {
619
+ const machine = (0, data_provider_1.plainAppLabel)(cost.machine.name, 120) || 'The computer';
620
+ const added = cost.added;
621
+ return [
622
+ 'What running it costs:',
623
+ ` ${machine} bills ${usd(cost.rateCentsPerHour)} for each hour it is running.`,
624
+ ...(cost.rateSource === 'admitted'
625
+ ? [
626
+ ` That is the rate it was started at; the current price list does not name one for it.`,
627
+ ]
628
+ : []),
629
+ ` If it never stopped, that would come to about ${usd(cost.ceilingMonthlyCents)} in a ${cost.hoursPerMonth}-hour month.`,
630
+ ` ${COST_ADDED_WORDS[added.basis]({
631
+ machine,
632
+ ...('monthlyCents' in added ? { monthlyCents: added.monthlyCents } : {}),
633
+ ...('usageHoursPerDay' in added
634
+ ? { usageHoursPerDay: added.usageHoursPerDay, idleTailMinutes: added.idleTailMinutes }
635
+ : {}),
636
+ })}`,
637
+ cost.payer
638
+ ? ` These hours are billed to ${cost.payer.kind === 'workspace' ? 'your workspace' : 'you'}, apart from the app's own price.`
639
+ : ' Who these hours are billed to could not be read.',
640
+ " These figures come from today's prices and your computer's settings. They are estimates, not a promise.",
641
+ ];
642
+ }
643
+ }
644
+ }
645
+ /** The words for a `binding_required` refusal: what was missing, and why what was given would not do. */
646
+ function describeBindingRefusal(refusal) {
647
+ const lines = [];
648
+ const issues = Array.isArray(refusal.issues) ? refusal.issues : [];
649
+ const words = BINDING_ISSUE_WORDS;
650
+ for (const issue of issues) {
651
+ if (typeof issue === 'string' && words[issue]) {
652
+ lines.push(words[issue]);
653
+ }
654
+ }
655
+ const unsuitable = (0, data_provider_1.parseAppBindingUnsuitable)(refusal.unsuitable);
656
+ if (unsuitable?.operator === 'not_found') {
657
+ lines.push('That Agent could not be used: it was not found, or you cannot edit it.');
658
+ }
659
+ else if (unsuitable?.operator) {
660
+ lines.push(`That Agent will not do: ${unsuitable.operator.map(describeOperatorUnmet).join('; ')}.`);
661
+ }
662
+ if (unsuitable?.hostMachine === 'not_found') {
663
+ lines.push('That computer could not be used: it was not found, or it is not yours.');
664
+ }
665
+ else if (unsuitable?.hostMachine) {
666
+ lines.push(`That computer will not do: ${unsuitable.hostMachine.map(describeHostUnsuitable).join('; ')}.`);
667
+ }
668
+ return lines.length > 0
669
+ ? lines.join('\n')
670
+ : 'This app needs something the installation did not bind (an operator agent or a host machine).';
671
+ }
672
+ const CHECK_OUTCOME_WORDS = {
673
+ blocked_for_store: 'found something that keeps this version out of the store',
674
+ cannot_analyze: 'could not read part of it, so it could not check that part',
675
+ findings: 'found things to look at',
676
+ nothing_found: 'found nothing it looks for',
677
+ };
678
+ const LIMITS_REMINDER = 'That is not a statement that the app is safe, and no person reviews an app.';
679
+ /**
680
+ * What the automatic check recorded for this version, in lines. It is never a verdict of "safe", and the three states
681
+ * a surface must keep apart are kept apart: a result, no result on record (the version predates the check), and a
682
+ * result stored in a form this CLI cannot read. A server that did not send the section at all is a fourth, said as such.
683
+ * None of the last three is ever drawn as "nothing found".
684
+ */
685
+ function describeDisclosureCheck(check) {
686
+ if (check === undefined) {
687
+ return ['Automatic check: this server did not say what it found. That is not a clean result.'];
688
+ }
689
+ if (!check.recorded) {
690
+ return check.reason === 'unreadable'
691
+ ? [
692
+ 'Automatic check: a result is stored for this version but this CLI cannot read it. That is not a clean result.',
693
+ ]
694
+ : [
695
+ 'Automatic check: none is on record for this version (it was cut before the check was recorded). That is not a clean result.',
696
+ ];
697
+ }
698
+ const { summary } = check;
699
+ const { counts } = summary;
700
+ const lines = [
701
+ `Automatic check: ${CHECK_OUTCOME_WORDS[summary.outcome] ?? summary.outcome}. ${LIMITS_REMINDER}`,
702
+ ];
703
+ if (counts.block + counts.warn + counts.info + counts.unanalyzable > 0) {
704
+ lines.push(` ${counts.block} would keep it out of the store, ${counts.warn} to read, ${counts.info} low-key, ${counts.unanalyzable} could not be read`);
705
+ }
706
+ for (const found of summary.findings.slice(0, 5)) {
707
+ const title = summary.rules[found.rule]?.title ?? found.rule;
708
+ const place = found.path ? ` (${found.line ? `${found.path}:${found.line}` : found.path})` : '';
709
+ lines.push(` - ${(0, data_provider_1.plainAppLabel)(title, 160)}${place}`);
710
+ }
711
+ const more = summary.findings.length - 5 + summary.omitted;
712
+ if (more > 0) {
713
+ lines.push(` - and ${more} more (run \`apps check\` on the app for all of them)`);
714
+ }
715
+ lines.push(` ${summary.limitations.headline}`);
716
+ return lines;
717
+ }
718
+ class InstallTargetError extends Error {
719
+ code;
720
+ constructor(code, message) {
721
+ super(message);
722
+ this.name = 'InstallTargetError';
723
+ this.code = code;
724
+ }
725
+ }
726
+ exports.InstallTargetError = InstallTargetError;
727
+ /**
728
+ * The version an install points at, and the bundle the person is about to be shown. With `--version` that
729
+ * version (and it must belong to the app); without it the app's newest. The server decides whether it is
730
+ * installable (a rejected or delisted version, a beta for a channel that does not see them): this does not
731
+ * guess at that vocabulary, it lets the refusal say it.
732
+ */
733
+ async function resolveInstallTarget(input) {
734
+ if (input.versionId) {
735
+ let detail;
736
+ try {
737
+ detail = await data_provider_1.dataService.getAppVersion(input.versionId);
738
+ }
739
+ catch (error) {
740
+ if (error?.status === 404) {
741
+ throw new InstallTargetError('version_not_found', `There is no version ${input.versionId} that you can use.`);
742
+ }
743
+ throw error;
744
+ }
745
+ if (detail.version.appId !== input.appId) {
746
+ throw new InstallTargetError('wrong_app', `${input.versionId} is a version of another app (${detail.version.appId}), not ${input.appId}.`);
747
+ }
748
+ return {
749
+ appId: input.appId,
750
+ versionId: detail.version.id,
751
+ bundleHash: detail.version.bundleHash,
752
+ version: detail.version.version,
753
+ };
754
+ }
755
+ const { versions } = await data_provider_1.dataService.listAppVersions({ appId: input.appId });
756
+ const newest = [...versions].sort((a, b) => b.version - a.version)[0];
757
+ if (!newest) {
758
+ throw new InstallTargetError('no_versions', `${input.appId} has no version yet. Cut one with \`apps version create\`.`);
759
+ }
760
+ return {
761
+ appId: input.appId,
762
+ versionId: newest.id,
763
+ bundleHash: newest.bundleHash,
764
+ version: newest.version,
765
+ };
766
+ }
767
+ // ── a refusal, in words ─────────────────────────────────────────────────────
768
+ const FORBIDDEN_REASON_WORDS = {
769
+ missing_permission: 'You need edit access to that agent to do this.',
770
+ human_only: 'Only a person can do this, not an agent.',
771
+ not_decided: 'This is not something an agent may do (the platform has not decided to allow it), and it is not something this command can do for you.',
772
+ app_is_not_a_principal: 'An app cannot do this to itself.',
773
+ unknown_actor: 'The platform could not tell who is asking.',
774
+ // the installation was suspended by the platform, not by the person: resuming it is not theirs to do
775
+ suspended_by_moderation: 'The platform suspended this app, not you, and only the platform can lift that. There is nothing to resume from here.',
776
+ };
777
+ /**
778
+ * Every reason an installation call is refused, with the sentence and the next step. A `Record` over the
779
+ * contract's list, so a reason added there does not compile here until it has words.
780
+ */
781
+ const CONFLICT_WORDS = {
782
+ invalid_input: () => 'The request was not understood. Check the ids and try again.',
783
+ principal_kind_not_enabled: () => 'Apps can be installed on an agent or on yourself today; installing on a space is not available yet.',
784
+ principal_not_found: () => 'There is no such agent that you can see (and an app on a person can be put there only by that person). Check the id (and that you have access to it).',
785
+ forbidden: (refusal) => FORBIDDEN_REASON_WORDS[refusal.reason ?? ''] ?? 'You may not do this.',
786
+ app_not_found: () => 'There is no such app that you can use. Check the id, or ask its owner to share it.',
787
+ version_not_found: () => 'There is no such version of that app that you can use.',
788
+ version_not_installable: (_refusal, bin) => `That version cannot be installed (it was withdrawn, replaced, or is a beta your update channel does not see). Name another with --version, or list them with \`${bin} apps versions\`.`,
789
+ manifest_invalid: () => "That version's manifest is not one this platform will run, so it was not installed.",
790
+ consent_mismatch: (_refusal, bin) => `The bundle you were shown is not the one on record for that version. Nothing was installed. Run \`${bin} apps disclosure\` again and approve what it shows.`,
791
+ version_changed: (refusal, bin) => `The installation moved to another version while you were deciding${refusal.current ? ` (now ${refusal.current.versionId})` : ''}. Nothing was changed. Read \`${bin} apps disclosure\` again and approve what it shows.`,
792
+ invalid_update_policy: () => 'That update policy is not one of manual, auto_minor or beta.',
793
+ binding_required: (refusal) => describeBindingRefusal(refusal),
794
+ already_installed: (refusal, bin) => `That app is already installed on this agent${refusal.installationId ? ` (${refusal.installationId})` : ''}. Move it to a newer version with \`${bin} apps upgrade\`.`,
795
+ not_found: () => 'There is no such installation that you can see.',
796
+ changed: (_refusal, bin) => `The installation changed while this was running. Nothing was written. Read it again with \`${bin} apps installations show\` and retry.`,
797
+ not_auto_updatable: () => 'That installation does not update on its own.',
798
+ data_deletion_not_confirmed: (refusal) => `Removing this app also deletes its data (${refusal.docCount ?? 'some'} document${refusal.docCount === 1 ? '' : 's'}), which is yours to confirm. Nothing was removed. Say it, with --delete-data, if you mean it.`,
799
+ installation_incomplete: () => 'This installation points at a version that can no longer be read. It can be removed, not run.',
800
+ principal_scope_unserved: (refusal) => `This app asks for ${describeScopeIssues(refusal.unserved)}, which cannot work for the place it would be installed (an app installed on a person reaches that person's own data, never an agent's or a space's, and has no agent to run it yet).${needsOperator(refusal.unserved)
801
+ ? ' An app that needs an agent to run it can, for now, only be installed on one of your agents.'
802
+ : ''} Nothing was installed.`,
803
+ job_schedule_invalid: (refusal, bin) => {
804
+ const issues = Array.isArray(refusal.issues)
805
+ ? refusal.issues.length
806
+ : 0;
807
+ return `${issues > 0 ? `${issues} of this app's scheduled jobs have` : 'A scheduled job has'} a schedule that runs more often than allowed (at most once a minute) or cannot be read. Nothing was installed. Check it with \`${bin} apps check\`.`;
808
+ },
809
+ };
810
+ /** The sentence for a refusal the server made on an installation call, or null for one that is not. */
811
+ function describeInstallationConflict(refusal, bin) {
812
+ if (!(0, data_provider_1.isAppInstallationConflict)(refusal.error)) {
813
+ return null;
814
+ }
815
+ return CONFLICT_WORDS[refusal.error](refusal, bin);
816
+ }
817
+ /** The machine code of every installation refusal: `APP_<REASON>`. */
818
+ exports.ALL_INSTALLATION_REFUSAL_CODES = Object.fromEntries(Object.keys(CONFLICT_WORDS).map((conflict) => [conflict, `APP_${conflict.toUpperCase()}`]));
819
+ /**
820
+ * `not_found` and `forbidden` are ALSO what the authoring loop says (`APP_AUTHORING_REFUSALS`), about an app
821
+ * and not an installation, and the generic handler words them for every other command. So the authoring
822
+ * commands' map gets only the reasons that are an installation's alone, and the installation commands read the
823
+ * whole of {@link ALL_INSTALLATION_REFUSAL_CODES} themselves (`AppsCommand.failInstallation`).
824
+ */
825
+ const SHARED_WITH_AUTHORING = ['not_found', 'forbidden'];
826
+ exports.INSTALLATION_REFUSAL_CODES = Object.fromEntries(Object.entries(exports.ALL_INSTALLATION_REFUSAL_CODES).filter(([conflict]) => SHARED_WITH_AUTHORING.indexOf(conflict) === -1));
827
+ // ── an app on a person (p2-10) ──────────────────────────────────────────────
828
+ /** What an item a principal cannot serve is called in a sentence, by kind (a `Record`: a new kind does not compile without words). */
829
+ const SCOPE_ISSUE_PHRASE = {
830
+ query: (name) => `the read "${name}"`,
831
+ tools: (name) => `the tool "${name}"`,
832
+ operator: () => 'an agent to run it',
833
+ };
834
+ /** The same, as a line of the disclosure preview. */
835
+ const SCOPE_ISSUE_LINE = {
836
+ query: (name) => `reads ${name}`,
837
+ tools: (name) => `tool ${name}`,
838
+ operator: () => 'needs an agent to run it: for now install it on one of your agents instead',
839
+ };
840
+ /** Does the refusal name the Agent that runs the app (`requires.agent`) among what a person's install cannot serve? */
841
+ function needsOperator(raw) {
842
+ return ((0, data_provider_1.parseAppPrincipalScopeIssues)(raw) ?? []).some((issue) => issue.capability === 'operator');
843
+ }
844
+ /** The items an app declares that its principal cannot serve, as one phrase; "something it declares" when unreadable. */
845
+ function describeScopeIssues(raw) {
846
+ const issues = (0, data_provider_1.parseAppPrincipalScopeIssues)(raw);
847
+ if (issues === null || issues.length === 0) {
848
+ return 'something it declares';
849
+ }
850
+ return issues.map((issue) => SCOPE_ISSUE_PHRASE[issue.capability](issue.name)).join(', ');
851
+ }
852
+ /** The lines the disclosure preview adds when the app cannot be installed on the principal asked about. Empty for none. */
853
+ function formatScopeIssues(raw) {
854
+ if (raw === undefined) {
855
+ return [];
856
+ }
857
+ const issues = (0, data_provider_1.parseAppPrincipalScopeIssues)(raw);
858
+ if (issues === null) {
859
+ return [
860
+ 'This app declares something that cannot work for the place it would be installed, and this version of the CLI cannot say what. It would be refused.',
861
+ ];
862
+ }
863
+ return [
864
+ 'It cannot be installed there, because it declares what an app installed on a person cannot use:',
865
+ ...issues.map((issue) => ` - ${SCOPE_ISSUE_LINE[issue.capability](issue.name)}`),
866
+ ];
867
+ }
868
+ /**
869
+ * Where an install points: one of the person's agents, or the person themself. `me` is the signed-in person's own id,
870
+ * which the server compares with the request's user (a stranger's id is refused as not found), so naming it here is
871
+ * not a claim the server takes on trust.
872
+ */
873
+ async function resolveInstallPrincipal(input) {
874
+ if (input.me) {
875
+ const user = await data_provider_1.dataService.getUser();
876
+ return { kind: 'user', id: String(user.id) };
877
+ }
878
+ return { kind: 'agent', id: String(input.agent) };
879
+ }
880
+ /** A layout read, in lines: the revision to name when writing, then the top-level order and each folder. */
881
+ function formatUserLayout(raw) {
882
+ const read = (0, data_provider_1.parseAppUserLayoutRead)(raw);
883
+ if (read === null) {
884
+ return [
885
+ 'This layout is not in a form this version of the CLI understands, so it is not shown (and will not be written over).',
886
+ ];
887
+ }
888
+ const lines = [
889
+ read.rev === 0
890
+ ? 'Nothing arranged yet (revision 0): your apps are shown in the order they were installed.'
891
+ : `Revision ${read.rev}.`,
892
+ ];
893
+ lines.push(read.layout.order.length === 0 ? 'Order: (none)' : `Order: ${read.layout.order.join(', ')}`);
894
+ for (const folder of read.layout.folders) {
895
+ lines.push(`Folder ${folder.id} "${(0, data_provider_1.plainAppLabel)(folder.name)}": ${folder.items.join(', ') || '(empty)'}`);
896
+ }
897
+ return lines;
898
+ }
899
+ /** Read a layout refusal out of an API error, or null when the error is not one the layout route made. */
900
+ function readLayoutRefusal(error) {
901
+ const e = error;
902
+ if (!e || typeof e.body !== 'string') {
903
+ return null;
904
+ }
905
+ try {
906
+ const body = JSON.parse(e.body);
907
+ if (!body || typeof body !== 'object' || typeof body.error !== 'string') {
908
+ return null;
909
+ }
910
+ return {
911
+ ...(typeof e.status === 'number' ? { status: e.status } : {}),
912
+ error: body.error,
913
+ ...(typeof body.currentRev === 'number' ? { currentRev: body.currentRev } : {}),
914
+ ...(typeof body.issue === 'string' ? { issue: body.issue } : {}),
915
+ };
916
+ }
917
+ catch {
918
+ return null;
919
+ }
920
+ }
921
+ // ── a report that was not taken, in words (p3-04) ───────────────────────────
922
+ /**
923
+ * Every reason a report on an installed app is refused, with the sentence and the next step. A `Record` over
924
+ * the contract's list, so a reason added there does not compile here until it has words. `invalid_input`,
925
+ * `forbidden` and `not_found` are ALSO installation refusals and read the same words there.
926
+ */
927
+ const REPORT_REFUSAL_WORDS = {
928
+ invalid_input: () => 'The request was not understood. Check the installation id and the flags.',
929
+ invalid_reason: () => `That reason is not one the Store takes. Use one of: ${data_provider_1.STORE_REPORT_REASONS.map((entry) => entry.value).join(', ')}.`,
930
+ description_required: () => 'A security report needs --description, so that whoever reads it can reproduce the problem. Nothing was sent.',
931
+ forbidden: (refusal) => FORBIDDEN_REASON_WORDS[refusal.reason ?? ''] ?? 'You may not report this app.',
932
+ not_found: () => 'There is no such installation that you can see.',
933
+ version_not_installed: () => 'You can only report the version this installation runs. Leave --version out, or name that one.',
934
+ already_reported: (_refusal, bin) => `You have already reported this version of the app. A second report on the same version is not taken. Follow the first with \`${bin} store reports\`.`,
935
+ security_report_open: (_refusal, bin) => `You already have a security report open for this app, and it has not been looked at yet. Follow it with \`${bin} store reports\`.`,
936
+ };
937
+ /** The reasons a report is refused that no installation call is refused for. */
938
+ const REPORT_ONLY_REFUSALS = [
939
+ 'invalid_reason',
940
+ 'description_required',
941
+ 'version_not_installed',
942
+ 'already_reported',
943
+ 'security_report_open',
944
+ ];
945
+ /** The machine code of a report refusal that is the report's alone: `APP_REPORT_<REASON>`. */
946
+ exports.REPORT_REFUSAL_CODES = Object.fromEntries(data_provider_1.APP_REPORT_REFUSALS.filter((reason) => REPORT_ONLY_REFUSALS.indexOf(reason) !== -1).map((reason) => [reason, `APP_REPORT_${reason.toUpperCase()}`]));
947
+ /** The sentence for a refusal the server made on a report, or null for one that is not the report's alone. */
948
+ function describeReportRefusal(refusal, bin) {
949
+ const code = refusal.error ?? '';
950
+ if (REPORT_ONLY_REFUSALS.indexOf(code) === -1) {
951
+ return null;
952
+ }
953
+ return REPORT_REFUSAL_WORDS[code](refusal, bin);
954
+ }
955
+ /** The exit of a refusal that says "that is not there for you": the same one an unknown app gets. */
956
+ function installationRefusalExit(conflict) {
957
+ return ['not_found', 'principal_not_found', 'app_not_found', 'version_not_found'].indexOf(conflict) === -1
958
+ ? 1
959
+ : 4;
960
+ }