@skrr-ai/cli 0.1.92 → 0.1.93

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 (267) hide show
  1. package/dist/base-command.d.ts +44 -0
  2. package/dist/base-command.js +96 -0
  3. package/dist/commands/agents/badge.d.ts +41 -0
  4. package/dist/commands/agents/badge.js +158 -0
  5. package/dist/commands/agents/create.d.ts +24 -0
  6. package/dist/commands/agents/create.js +212 -0
  7. package/dist/commands/agents/embed.d.ts +20 -0
  8. package/dist/commands/agents/embed.js +61 -0
  9. package/dist/commands/agents/share.d.ts +27 -0
  10. package/dist/commands/agents/share.js +100 -0
  11. package/dist/commands/agents/vanity.d.ts +21 -0
  12. package/dist/commands/agents/vanity.js +77 -0
  13. package/dist/commands/agents/visibility.d.ts +21 -1
  14. package/dist/commands/agents/visibility.js +112 -0
  15. package/dist/commands/commands.d.ts +1 -0
  16. package/dist/commands/commands.js +22 -9
  17. package/dist/commands/earnings/attributions.d.ts +17 -0
  18. package/dist/commands/earnings/attributions.js +82 -0
  19. package/dist/commands/earnings/index.js +2 -1
  20. package/dist/commands/generate-recovery-code.js +4 -3
  21. package/dist/commands/github/allow-tools.d.ts +1 -0
  22. package/dist/commands/github/app/install.d.ts +1 -0
  23. package/dist/commands/github/app/status.d.ts +1 -0
  24. package/dist/commands/github/connect.d.ts +1 -0
  25. package/dist/commands/github/connections.d.ts +1 -0
  26. package/dist/commands/github/disconnect.d.ts +1 -0
  27. package/dist/commands/github/finalize.d.ts +1 -0
  28. package/dist/commands/github/reconnect.d.ts +1 -0
  29. package/dist/commands/github/run.d.ts +1 -0
  30. package/dist/commands/github/tools.d.ts +1 -0
  31. package/dist/commands/integrations/connections/connect.d.ts +1 -0
  32. package/dist/commands/integrations/connections/disconnect.d.ts +1 -0
  33. package/dist/commands/integrations/connections/finalize.d.ts +1 -0
  34. package/dist/commands/integrations/connections/list.d.ts +1 -0
  35. package/dist/commands/integrations/connections/reconnect.d.ts +1 -0
  36. package/dist/commands/integrations/execute.d.ts +1 -0
  37. package/dist/commands/integrations/search.d.ts +1 -0
  38. package/dist/commands/integrations/toolkits.d.ts +1 -0
  39. package/dist/commands/integrations/tools/allow.d.ts +1 -0
  40. package/dist/commands/integrations/tools/list.d.ts +1 -0
  41. package/dist/commands/login.js +12 -0
  42. package/dist/commands/machines/dedicated/logs.d.ts +19 -0
  43. package/dist/commands/machines/dedicated/logs.js +103 -0
  44. package/dist/commands/machines/dedicated/power/set.js +1 -1
  45. package/dist/commands/open.d.ts +24 -0
  46. package/dist/commands/open.js +74 -0
  47. package/dist/commands/projects/archive.d.ts +1 -0
  48. package/dist/commands/projects/archive.js +23 -0
  49. package/dist/commands/projects/delete.d.ts +1 -0
  50. package/dist/commands/projects/delete.js +23 -0
  51. package/dist/commands/projects/list.d.ts +3 -0
  52. package/dist/commands/projects/list.js +12 -2
  53. package/dist/commands/spaces/actions/add.js +4 -3
  54. package/dist/commands/spaces/actions/available.js +3 -2
  55. package/dist/commands/spaces/actions/list.js +5 -4
  56. package/dist/commands/spaces/actions/replace.js +6 -5
  57. package/dist/commands/spaces/archive.js +3 -2
  58. package/dist/commands/spaces/auto-executor/preview.js +4 -3
  59. package/dist/commands/spaces/auto-executor/run.js +4 -3
  60. package/dist/commands/spaces/auto-executor/runs.js +3 -2
  61. package/dist/commands/spaces/auto-executor/update.js +4 -3
  62. package/dist/commands/spaces/bootstrap.js +3 -2
  63. package/dist/commands/spaces/briefs/delete.js +3 -2
  64. package/dist/commands/spaces/briefs/get.js +3 -2
  65. package/dist/commands/spaces/briefs/list.js +3 -2
  66. package/dist/commands/spaces/briefs/set.js +5 -4
  67. package/dist/commands/spaces/capacity.js +5 -4
  68. package/dist/commands/spaces/conversations.js +3 -2
  69. package/dist/commands/spaces/cycles/create.js +3 -2
  70. package/dist/commands/spaces/cycles/graph.js +2 -1
  71. package/dist/commands/spaces/cycles/list.js +3 -2
  72. package/dist/commands/spaces/cycles/settings.js +4 -3
  73. package/dist/commands/spaces/cycles/show.js +3 -2
  74. package/dist/commands/spaces/cycles/update.js +3 -2
  75. package/dist/commands/spaces/delete.js +4 -3
  76. package/dist/commands/spaces/expertise-suggestions.js +4 -3
  77. package/dist/commands/spaces/files/delete.js +3 -2
  78. package/dist/commands/spaces/files/folders/create.js +3 -2
  79. package/dist/commands/spaces/files/folders/delete.js +3 -2
  80. package/dist/commands/spaces/files/folders/list.js +3 -2
  81. package/dist/commands/spaces/files/folders/update.js +3 -2
  82. package/dist/commands/spaces/files/list.js +3 -2
  83. package/dist/commands/spaces/files/move.js +3 -2
  84. package/dist/commands/spaces/files/rename.js +3 -2
  85. package/dist/commands/spaces/files/upload.js +6 -5
  86. package/dist/commands/spaces/github-automations/set.js +3 -2
  87. package/dist/commands/spaces/github-automations/show.js +3 -2
  88. package/dist/commands/spaces/goals.js +2 -1
  89. package/dist/commands/spaces/heartbeats/create.js +4 -3
  90. package/dist/commands/spaces/heartbeats/delete.js +4 -3
  91. package/dist/commands/spaces/heartbeats/list.js +4 -3
  92. package/dist/commands/spaces/heartbeats/status.js +3 -2
  93. package/dist/commands/spaces/heartbeats/update.js +4 -3
  94. package/dist/commands/spaces/insights.js +5 -4
  95. package/dist/commands/spaces/labels/add.js +4 -3
  96. package/dist/commands/spaces/labels/list.js +2 -1
  97. package/dist/commands/spaces/labels/remove.js +4 -3
  98. package/dist/commands/spaces/list.d.ts +3 -0
  99. package/dist/commands/spaces/list.js +11 -2
  100. package/dist/commands/spaces/live/cards/create.js +3 -2
  101. package/dist/commands/spaces/live/cards/list.js +3 -2
  102. package/dist/commands/spaces/live/cards/reorder.js +7 -2
  103. package/dist/commands/spaces/live/scene.js +4 -3
  104. package/dist/commands/spaces/members/add.js +7 -6
  105. package/dist/commands/spaces/members/list.js +4 -3
  106. package/dist/commands/spaces/members/remove.js +7 -6
  107. package/dist/commands/spaces/move.js +3 -2
  108. package/dist/commands/spaces/pin.js +5 -4
  109. package/dist/commands/spaces/preferences/show.js +4 -3
  110. package/dist/commands/spaces/preferences/tabs.js +4 -3
  111. package/dist/commands/spaces/revisions.js +3 -2
  112. package/dist/commands/spaces/room/ensure.js +5 -4
  113. package/dist/commands/spaces/room/messages.js +3 -2
  114. package/dist/commands/spaces/room/show.js +5 -4
  115. package/dist/commands/spaces/skills/add.js +4 -3
  116. package/dist/commands/spaces/skills/list.js +3 -2
  117. package/dist/commands/spaces/skills/pin.js +4 -3
  118. package/dist/commands/spaces/skills/remove.js +4 -3
  119. package/dist/commands/spaces/snapshot.js +3 -2
  120. package/dist/commands/spaces/states/archive.js +3 -2
  121. package/dist/commands/spaces/states/create.js +3 -2
  122. package/dist/commands/spaces/states/list.js +3 -2
  123. package/dist/commands/spaces/states/reorder.js +2 -1
  124. package/dist/commands/spaces/states/update.js +3 -2
  125. package/dist/commands/spaces/summary.js +4 -3
  126. package/dist/commands/spaces/tasks.d.ts +3 -0
  127. package/dist/commands/spaces/tasks.js +14 -3
  128. package/dist/commands/spaces/triggers/delete.js +5 -4
  129. package/dist/commands/spaces/triggers/set.js +4 -3
  130. package/dist/commands/spaces/triggers/show.js +4 -3
  131. package/dist/commands/spaces/unarchive.js +3 -2
  132. package/dist/commands/spaces/update.js +5 -4
  133. package/dist/commands/spaces/views/create.js +3 -2
  134. package/dist/commands/spaces/views/list.js +3 -2
  135. package/dist/commands/spaces/views/reorder.js +6 -3
  136. package/dist/commands/spaces/views/subscribe.js +2 -1
  137. package/dist/commands/spaces/views/subscriptions.js +1 -0
  138. package/dist/commands/spaces/views/unsubscribe.js +2 -1
  139. package/dist/commands/spaces/widgets/add.js +4 -3
  140. package/dist/commands/spaces/widgets/list.js +3 -2
  141. package/dist/commands/spaces/widgets/remove.js +5 -4
  142. package/dist/commands/spaces/work-graph.js +2 -1
  143. package/dist/commands/store/install.d.ts +1 -1
  144. package/dist/commands/store/install.js +24 -8
  145. package/dist/commands/store/show.d.ts +25 -0
  146. package/dist/commands/store/show.js +203 -0
  147. package/dist/commands/store/stats.d.ts +33 -0
  148. package/dist/commands/store/stats.js +258 -0
  149. package/dist/commands/tasks/actions/attach.js +1 -1
  150. package/dist/commands/tasks/actions/detach.js +4 -3
  151. package/dist/commands/tasks/activity.js +3 -2
  152. package/dist/commands/tasks/ancestors.js +2 -1
  153. package/dist/commands/tasks/approvals/create.js +2 -1
  154. package/dist/commands/tasks/approvals/delete.js +3 -2
  155. package/dist/commands/tasks/approvals/list.js +5 -4
  156. package/dist/commands/tasks/approvals/resolve.js +2 -1
  157. package/dist/commands/tasks/archive.js +3 -2
  158. package/dist/commands/tasks/assign.js +4 -3
  159. package/dist/commands/tasks/attachments/delete.js +3 -2
  160. package/dist/commands/tasks/attachments/download.d.ts +1 -0
  161. package/dist/commands/tasks/attachments/download.js +20 -1
  162. package/dist/commands/tasks/attachments/list.js +2 -1
  163. package/dist/commands/tasks/attachments/set-role.js +2 -1
  164. package/dist/commands/tasks/attachments/upload.js +2 -1
  165. package/dist/commands/tasks/bulk-update.d.ts +1 -0
  166. package/dist/commands/tasks/bulk-update.js +106 -15
  167. package/dist/commands/tasks/cancel-cascade.d.ts +1 -0
  168. package/dist/commands/tasks/cancel-cascade.js +13 -3
  169. package/dist/commands/tasks/cascade-status.js +2 -1
  170. package/dist/commands/tasks/checkout.js +3 -2
  171. package/dist/commands/tasks/children.js +2 -1
  172. package/dist/commands/tasks/comments/add.js +7 -6
  173. package/dist/commands/tasks/comments/anchor.js +8 -7
  174. package/dist/commands/tasks/comments/delete.js +3 -2
  175. package/dist/commands/tasks/comments/list.js +2 -1
  176. package/dist/commands/tasks/comments/reopen.js +3 -2
  177. package/dist/commands/tasks/comments/resolve.js +3 -2
  178. package/dist/commands/tasks/create-tree.d.ts +63 -0
  179. package/dist/commands/tasks/create-tree.js +197 -4
  180. package/dist/commands/tasks/delete.js +5 -4
  181. package/dist/commands/tasks/descendants.js +2 -1
  182. package/dist/commands/tasks/dri-plan.js +3 -2
  183. package/dist/commands/tasks/dri-run.js +3 -2
  184. package/dist/commands/tasks/dri-status.js +2 -1
  185. package/dist/commands/tasks/duplicate-pipeline.js +2 -1
  186. package/dist/commands/tasks/execution-summary.js +2 -1
  187. package/dist/commands/tasks/execution-timeline.js +2 -1
  188. package/dist/commands/tasks/fork.js +1 -0
  189. package/dist/commands/tasks/forward.js +4 -3
  190. package/dist/commands/tasks/handover.js +1 -0
  191. package/dist/commands/tasks/interrupt.js +3 -2
  192. package/dist/commands/tasks/labels/attach.js +4 -3
  193. package/dist/commands/tasks/labels/detach.js +4 -3
  194. package/dist/commands/tasks/labels/suggest.js +5 -4
  195. package/dist/commands/tasks/list.d.ts +27 -1
  196. package/dist/commands/tasks/list.js +101 -3
  197. package/dist/commands/tasks/move.js +4 -3
  198. package/dist/commands/tasks/output.js +6 -5
  199. package/dist/commands/tasks/pause-schedule.js +3 -2
  200. package/dist/commands/tasks/promote.js +1 -0
  201. package/dist/commands/tasks/prompt-log.js +2 -1
  202. package/dist/commands/tasks/release.js +5 -4
  203. package/dist/commands/tasks/remind.js +2 -1
  204. package/dist/commands/tasks/replay.js +3 -2
  205. package/dist/commands/tasks/report.js +1 -0
  206. package/dist/commands/tasks/resume-schedule.js +3 -2
  207. package/dist/commands/tasks/retry-schedule.js +3 -2
  208. package/dist/commands/tasks/retry.js +10 -9
  209. package/dist/commands/tasks/revisions.js +2 -1
  210. package/dist/commands/tasks/runs.js +6 -5
  211. package/dist/commands/tasks/schedule.js +3 -2
  212. package/dist/commands/tasks/self-schedule.js +6 -5
  213. package/dist/commands/tasks/skills/pin.js +3 -2
  214. package/dist/commands/tasks/skills/unpin.js +3 -2
  215. package/dist/commands/tasks/snooze.js +6 -5
  216. package/dist/commands/tasks/start-all.js +5 -4
  217. package/dist/commands/tasks/subscribe.js +1 -0
  218. package/dist/commands/tasks/tags/add.js +4 -3
  219. package/dist/commands/tasks/tags/remove.js +4 -3
  220. package/dist/commands/tasks/timeline.js +3 -2
  221. package/dist/commands/tasks/today.d.ts +4 -1
  222. package/dist/commands/tasks/today.js +12 -2
  223. package/dist/commands/tasks/transcript.js +6 -5
  224. package/dist/commands/tasks/unschedule.js +3 -2
  225. package/dist/commands/tasks/unsnooze.js +3 -2
  226. package/dist/commands/tasks/unsubscribe.js +2 -1
  227. package/dist/commands/tasks/update.js +5 -4
  228. package/dist/commands/tasks/wait.js +5 -4
  229. package/dist/lib/agent-distribution.d.ts +37 -0
  230. package/dist/lib/agent-distribution.js +63 -0
  231. package/dist/lib/agent-ref.d.ts +69 -0
  232. package/dist/lib/agent-ref.js +168 -0
  233. package/dist/lib/api-fetch.d.ts +2 -0
  234. package/dist/lib/api-fetch.js +14 -3
  235. package/dist/lib/command-hygiene.d.ts +13 -0
  236. package/dist/lib/command-hygiene.js +62 -2
  237. package/dist/lib/dedicated-power.d.ts +5 -0
  238. package/dist/lib/dedicated-power.js +30 -2
  239. package/dist/lib/dry-run-plans.d.ts +50 -0
  240. package/dist/lib/dry-run-plans.js +85 -0
  241. package/dist/lib/json-output.d.ts +31 -0
  242. package/dist/lib/json-output.js +78 -0
  243. package/dist/lib/list-output.d.ts +75 -0
  244. package/dist/lib/list-output.js +266 -0
  245. package/dist/lib/machine-daemon-log.d.ts +36 -0
  246. package/dist/lib/machine-daemon-log.js +78 -0
  247. package/dist/lib/node-adapter.js +10 -1
  248. package/dist/lib/open-target.d.ts +12 -0
  249. package/dist/lib/open-target.js +108 -0
  250. package/dist/lib/rate-limit-retry.d.ts +45 -0
  251. package/dist/lib/rate-limit-retry.js +88 -0
  252. package/dist/lib/store-listing.d.ts +45 -0
  253. package/dist/lib/store-listing.js +186 -0
  254. package/dist/lib/task-batch.d.ts +67 -0
  255. package/dist/lib/task-batch.js +227 -0
  256. package/dist/lib/terminal-qr.d.ts +55 -0
  257. package/dist/lib/terminal-qr.js +119 -0
  258. package/dist/lib/web-url.d.ts +11 -0
  259. package/dist/lib/web-url.js +24 -0
  260. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +68 -0
  261. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +47 -1
  262. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +68 -0
  263. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +46 -0
  264. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  265. package/dist/node_modules/@skrr-ai/data-provider/index.js +6612 -6113
  266. package/oclif.manifest.json +46778 -38019
  267. package/package.json +2 -1
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenTargetError = exports.OPEN_REF_KINDS = void 0;
4
+ exports.resolveOpenTarget = resolveOpenTarget;
5
+ const data_provider_1 = require("@skrr-ai/data-provider");
6
+ const agent_ref_1 = require("./agent-ref");
7
+ const web_url_1 = require("./web-url");
8
+ /**
9
+ * What `skrr open <target>` accepts, resolved to one absolute web URL.
10
+ *
11
+ * - a skrr web URL (`https://skrr.ai/a/agent_abc`) — opened as given, after
12
+ * checking it is first-party;
13
+ * - a site path (`/spaces/sp_1/tasks`) — on the configured deployment;
14
+ * - a typed reference (`space:sp_1`, `listing:agent_abc`) — through the
15
+ * CLI's one route table, `web-url.ts`, so no route is spelled here;
16
+ * - an agent reference `resolveAgentRef` understands that is not already a
17
+ * web URL (`skrr://agent/<id>`, `agent_abc`) — opened at its public
18
+ * listing, keeping any attribution it carried.
19
+ *
20
+ * A foreign host is refused rather than opened. `skrr open` is also run by
21
+ * coding agents, and a command that opens whatever URL it is handed would turn
22
+ * "open this skrr link" into "open any link" for anything that can put text in
23
+ * front of one. WHETHER a URL is first-party is data-provider's
24
+ * `inspectSkrrLink` (the shared link parser) over the CLI's host list, never a
25
+ * host comparison of our own.
26
+ */
27
+ /** Kind words a typed reference may use, mapped to the route table's refs. */
28
+ const REF_KINDS = {
29
+ space: (id) => ({ kind: 'space', spaceId: id }),
30
+ task: (id) => ({ kind: 'task', taskId: id }),
31
+ goal: (id) => ({ kind: 'goal', goalId: id }),
32
+ commitment: (id) => ({ kind: 'commitment', commitmentId: id }),
33
+ northstar: (id) => ({ kind: 'northstar', northstarId: id }),
34
+ // The owner's workspace for an agent you hold. To open a published agent's
35
+ // public page — the address you hand to someone else — use `listing:`.
36
+ agent: (id) => ({ kind: 'agent', agentId: id }),
37
+ listing: (id) => ({ kind: 'storeListing', agentId: id }),
38
+ conversation: (id) => ({ kind: 'conversation', conversationId: id }),
39
+ group: (id) => ({ kind: 'groupChat', groupChatId: id }),
40
+ machine: (id) => ({ kind: 'machine', machineId: id }),
41
+ harness: (id) => ({ kind: 'harness', harnessId: id }),
42
+ template: (id) => ({ kind: 'spaceTemplate', templateId: id }),
43
+ };
44
+ exports.OPEN_REF_KINDS = Object.freeze(Object.keys(REF_KINDS));
45
+ class OpenTargetError extends Error {
46
+ code;
47
+ constructor(message, code) {
48
+ super(message);
49
+ this.code = code;
50
+ this.name = 'OpenTargetError';
51
+ }
52
+ }
53
+ exports.OpenTargetError = OpenTargetError;
54
+ /** An agent reference that is not a web URL: an app-scheme link, `@handle/…`, or an `agent_` id. */
55
+ function looksLikeAgentRef(value) {
56
+ return (/^[a-z][a-z0-9+.-]*:\/\//i.test(value) ||
57
+ value.startsWith('@') ||
58
+ /^agent_[A-Za-z0-9_-]+$/.test(value));
59
+ }
60
+ async function resolveOpenTarget(input, baseURL) {
61
+ const value = String(input ?? '').trim();
62
+ if (!value) {
63
+ throw new OpenTargetError(`Name what to open: a ${data_provider_1.BRAND.displayName} URL, a /path, or <kind>:<id>.`, 'OPEN_TARGET_EMPTY');
64
+ }
65
+ if (/^https?:\/\//i.test(value)) {
66
+ let parsed;
67
+ try {
68
+ parsed = new URL(value);
69
+ }
70
+ catch {
71
+ throw new OpenTargetError(`"${value}" is not a valid URL.`, 'OPEN_TARGET_UNKNOWN');
72
+ }
73
+ if (!(0, data_provider_1.inspectSkrrLink)(value, { firstPartyHosts: (0, agent_ref_1.cliFirstPartyHosts)(baseURL) })) {
74
+ throw new OpenTargetError(`${parsed.host} is not a ${data_provider_1.BRAND.displayName} web address, so it was not opened.`, 'OPEN_TARGET_FOREIGN');
75
+ }
76
+ return { url: parsed.toString(), form: 'url' };
77
+ }
78
+ if (value.startsWith('/')) {
79
+ // `//host/...` is a protocol-relative URL to ANOTHER host, not a path.
80
+ if (value.startsWith('//')) {
81
+ throw new OpenTargetError(`"${value}" is not a site path.`, 'OPEN_TARGET_UNKNOWN');
82
+ }
83
+ return { url: new URL(value, `${(0, web_url_1.webOrigin)(baseURL)}/`).toString(), form: 'path' };
84
+ }
85
+ const ref = /^([a-z]+):(.+)$/i.exec(value);
86
+ const build = ref ? REF_KINDS[ref[1].toLowerCase()] : undefined;
87
+ if (ref && build) {
88
+ const url = (0, web_url_1.webUrl)(baseURL, build(ref[2].trim()));
89
+ if (url)
90
+ return { url, form: 'ref' };
91
+ }
92
+ if (looksLikeAgentRef(value)) {
93
+ try {
94
+ const agent = await (0, agent_ref_1.resolveAgentRef)(value, { baseURL });
95
+ return { url: (0, agent_ref_1.attributedListingUrl)(baseURL, agent), form: 'agent' };
96
+ }
97
+ catch (err) {
98
+ if (!(err instanceof agent_ref_1.AgentRefError))
99
+ throw err;
100
+ // A foreign scheme or an unresolvable vanity link says so in its own words.
101
+ if (err.code !== 'AGENT_REF_UNSUPPORTED') {
102
+ throw new OpenTargetError(err.message, err.code === 'AGENT_REF_FOREIGN' ? 'OPEN_TARGET_FOREIGN' : 'OPEN_TARGET_UNKNOWN');
103
+ }
104
+ }
105
+ }
106
+ throw new OpenTargetError(`"${value}" is not something \`skrr open\` understands. Pass a ${data_provider_1.BRAND.displayName} URL, a site path ` +
107
+ `(/spaces/<id>), or <kind>:<id> where kind is one of: ${exports.OPEN_REF_KINDS.join(', ')}.`, 'OPEN_TARGET_UNKNOWN');
108
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Bounded retry on HTTP 429 (agent-surface audit E6).
3
+ *
4
+ * The API limits writes per USER (task create is 200/min), so N agents under one
5
+ * account share one bucket, and the server already says when to come back
6
+ * (`Retry-After`, `standardHeaders: true`). Until now both transports treated a
7
+ * 429 as terminal, so a burst of keyed creates failed on the first refusal.
8
+ *
9
+ * Retried only when replay is provably safe: a GET, or a write that carries an
10
+ * `X-Idempotency-Key` (every `request.ts` / adapter write does). A 429 means the
11
+ * request was refused before it ran, so the key is belt and braces.
12
+ *
13
+ * Bounded twice: at most `maxRetries` extra attempts and a per-wait ceiling, so
14
+ * a stuck limiter costs a script seconds, not minutes. `SKRR_RATE_LIMIT_RETRIES=0`
15
+ * turns it off.
16
+ */
17
+ export declare const DEFAULT_MAX_RATE_LIMIT_RETRIES = 2;
18
+ export declare const MAX_RATE_LIMIT_WAIT_MS = 10000;
19
+ /** `Retry-After` is delta-seconds or an HTTP-date; both become milliseconds. */
20
+ export declare function parseRetryAfterMs(value: string | null | undefined, now?: number): number | undefined;
21
+ /**
22
+ * Wait before retry number `attempt` (0-based): the server's `Retry-After` when
23
+ * given, else exponential from 500 ms, plus 0-25% jitter so a fleet released
24
+ * together does not come back together. Clamped to the ceiling.
25
+ */
26
+ export declare function rateLimitWaitMs(attempt: number, retryAfterMs: number | undefined, random?: () => number): number;
27
+ export declare function maxRateLimitRetries(env?: NodeJS.ProcessEnv): number;
28
+ export declare function isRateLimitRetrySafe(method: string, headers: Record<string, string> | undefined): boolean;
29
+ export interface RateLimitRetryOptions {
30
+ method: string;
31
+ headers?: Record<string, string>;
32
+ signal?: AbortSignal;
33
+ sleep?: (ms: number) => Promise<void>;
34
+ random?: () => number;
35
+ maxRetries?: number;
36
+ }
37
+ /**
38
+ * Run `attemptFetch` and, on a 429 for a replay-safe request, wait and run it
39
+ * again. Returns the last response, with `retryAfterMs` of the final 429 (so the
40
+ * caller can surface it) when retries ran out.
41
+ */
42
+ export declare function fetchWithRateLimitRetry(attemptFetch: () => Promise<Response>, options: RateLimitRetryOptions): Promise<{
43
+ response: Response;
44
+ retryAfterMs?: number;
45
+ }>;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * Bounded retry on HTTP 429 (agent-surface audit E6).
4
+ *
5
+ * The API limits writes per USER (task create is 200/min), so N agents under one
6
+ * account share one bucket, and the server already says when to come back
7
+ * (`Retry-After`, `standardHeaders: true`). Until now both transports treated a
8
+ * 429 as terminal, so a burst of keyed creates failed on the first refusal.
9
+ *
10
+ * Retried only when replay is provably safe: a GET, or a write that carries an
11
+ * `X-Idempotency-Key` (every `request.ts` / adapter write does). A 429 means the
12
+ * request was refused before it ran, so the key is belt and braces.
13
+ *
14
+ * Bounded twice: at most `maxRetries` extra attempts and a per-wait ceiling, so
15
+ * a stuck limiter costs a script seconds, not minutes. `SKRR_RATE_LIMIT_RETRIES=0`
16
+ * turns it off.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.MAX_RATE_LIMIT_WAIT_MS = exports.DEFAULT_MAX_RATE_LIMIT_RETRIES = void 0;
20
+ exports.parseRetryAfterMs = parseRetryAfterMs;
21
+ exports.rateLimitWaitMs = rateLimitWaitMs;
22
+ exports.maxRateLimitRetries = maxRateLimitRetries;
23
+ exports.isRateLimitRetrySafe = isRateLimitRetrySafe;
24
+ exports.fetchWithRateLimitRetry = fetchWithRateLimitRetry;
25
+ exports.DEFAULT_MAX_RATE_LIMIT_RETRIES = 2;
26
+ exports.MAX_RATE_LIMIT_WAIT_MS = 10_000;
27
+ const MIN_WAIT_MS = 250;
28
+ /** `Retry-After` is delta-seconds or an HTTP-date; both become milliseconds. */
29
+ function parseRetryAfterMs(value, now = Date.now()) {
30
+ if (!value)
31
+ return undefined;
32
+ const trimmed = value.trim();
33
+ if (/^\d+(\.\d+)?$/.test(trimmed))
34
+ return Math.round(Number(trimmed) * 1000);
35
+ const at = Date.parse(trimmed);
36
+ if (Number.isNaN(at))
37
+ return undefined;
38
+ return Math.max(0, at - now);
39
+ }
40
+ /**
41
+ * Wait before retry number `attempt` (0-based): the server's `Retry-After` when
42
+ * given, else exponential from 500 ms, plus 0-25% jitter so a fleet released
43
+ * together does not come back together. Clamped to the ceiling.
44
+ */
45
+ function rateLimitWaitMs(attempt, retryAfterMs, random = Math.random) {
46
+ const base = retryAfterMs ?? 500 * 2 ** attempt;
47
+ const jittered = base * (1 + 0.25 * random());
48
+ return Math.min(exports.MAX_RATE_LIMIT_WAIT_MS, Math.max(MIN_WAIT_MS, Math.round(jittered)));
49
+ }
50
+ function maxRateLimitRetries(env = process.env) {
51
+ const raw = env.SKRR_RATE_LIMIT_RETRIES;
52
+ if (raw === undefined || raw === '')
53
+ return exports.DEFAULT_MAX_RATE_LIMIT_RETRIES;
54
+ const n = Number(raw);
55
+ return Number.isInteger(n) && n >= 0 ? Math.min(n, 5) : exports.DEFAULT_MAX_RATE_LIMIT_RETRIES;
56
+ }
57
+ function hasKey(headers) {
58
+ return Object.keys(headers ?? {}).some((k) => k.toLowerCase() === 'x-idempotency-key');
59
+ }
60
+ function isRateLimitRetrySafe(method, headers) {
61
+ return method.toUpperCase() === 'GET' || hasKey(headers);
62
+ }
63
+ function retryAfterOf(response) {
64
+ return response.status === 429
65
+ ? parseRetryAfterMs(response.headers.get('retry-after'))
66
+ : undefined;
67
+ }
68
+ /**
69
+ * Run `attemptFetch` and, on a 429 for a replay-safe request, wait and run it
70
+ * again. Returns the last response, with `retryAfterMs` of the final 429 (so the
71
+ * caller can surface it) when retries ran out.
72
+ */
73
+ async function fetchWithRateLimitRetry(attemptFetch, options) {
74
+ const sleep = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
75
+ const max = options.maxRetries ?? maxRateLimitRetries();
76
+ let response = await attemptFetch();
77
+ let retryAfterMs = retryAfterOf(response);
78
+ if (!isRateLimitRetrySafe(options.method, options.headers))
79
+ return { response, retryAfterMs };
80
+ for (let attempt = 0; attempt < max && response.status === 429; attempt++) {
81
+ if (options.signal?.aborted)
82
+ break;
83
+ await sleep(rateLimitWaitMs(attempt, retryAfterMs, options.random));
84
+ response = await attemptFetch();
85
+ retryAfterMs = retryAfterOf(response);
86
+ }
87
+ return { response, retryAfterMs };
88
+ }
@@ -0,0 +1,45 @@
1
+ import { type ReleaseCapabilityManifestView, type StoreAgentInstallFunnelSummary, type StoreAgentReleaseAdoptionSummary, type StoreAgentReleaseOutcomes } from '@skrr-ai/data-provider';
2
+ /**
3
+ * Terminal wording for a Store listing (`skrr store show`) and its publisher
4
+ * readouts (`skrr store stats`). Pure functions, so the commands only fetch
5
+ * and print and every sentence here is pinned by a unit test.
6
+ *
7
+ * Two rules carried over from the web surfaces, because a terminal is not a
8
+ * licence to say less:
9
+ *
10
+ * - The capability manifest is a DISCLOSURE. Nothing narrows a run to it
11
+ * (see `client/src/components/Store/capabilityDisclosure.ts`), so no line
12
+ * here says an agent is limited, restricted or "can only" do something.
13
+ * `Unrestricted` is the one state word, and it names the BAD case.
14
+ * - A k-anonymous readout below its floor has NO figures. It is printed as
15
+ * "withheld" with the floor it missed, never as 0 — a zero is a claim that
16
+ * nobody did the thing, and the server did not make that claim.
17
+ */
18
+ /** A listing's price in token credits (1,000,000 = $1), as the Store states it. */
19
+ export declare function formatListingPrice(price: number | null | undefined): string;
20
+ /** `4.6 ★ (12 ratings)`, or `No ratings yet` — never `0.0` for an unrated listing. */
21
+ export declare function formatListingRating(rating: number | null | undefined, count: number | null | undefined): string;
22
+ /**
23
+ * What the listed release is configured to use, as `label: value` pairs.
24
+ *
25
+ * `unavailable` stays its own answer — "we could not tell" — and is never
26
+ * rendered as an empty manifest, which would read as "uses nothing".
27
+ */
28
+ export declare function capabilityDisclosureRows(view: ReleaseCapabilityManifestView | null | undefined): Array<[string, string]>;
29
+ /** One sentence that keeps the disclosure from being read as a sandbox. */
30
+ export declare const CAPABILITY_DISCLOSURE_FOOTNOTE = "Recorded by the platform when the release was created. A disclosure of its configuration \u2014 not a limit on what a run may do.";
31
+ /** Align `label: value` pairs under a section, indented two spaces. */
32
+ export declare function labelledLines(rows: ReadonlyArray<readonly [string, string]>): string[];
33
+ /** `withheld: fewer than 5 buyers in this window` — the floor, never a zero. */
34
+ export declare function withheldLine(minimumCohort: number, unit: string): string;
35
+ export declare function formatRate(value: number | null | undefined): string;
36
+ export declare function funnelWindowLine(summary: StoreAgentInstallFunnelSummary): string;
37
+ export declare function adoptionWindowLine(summary: StoreAgentReleaseAdoptionSummary): string;
38
+ export declare function outcomesWindowLine(outcomes: StoreAgentReleaseOutcomes): string;
39
+ /**
40
+ * Small cells that were withheld from an otherwise reported readout. Said
41
+ * once, with the floor, so a short table is not mistaken for a complete one.
42
+ */
43
+ export declare function suppressedCellsLine(cells: Record<string, number>, minimumCohort: number, unit: string): string | null;
44
+ /** An exclusion count; `null` is "some, from too few buyers to say how many". */
45
+ export declare function exclusionValue(value: number | null | undefined): string;
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CAPABILITY_DISCLOSURE_FOOTNOTE = void 0;
4
+ exports.formatListingPrice = formatListingPrice;
5
+ exports.formatListingRating = formatListingRating;
6
+ exports.capabilityDisclosureRows = capabilityDisclosureRows;
7
+ exports.labelledLines = labelledLines;
8
+ exports.withheldLine = withheldLine;
9
+ exports.formatRate = formatRate;
10
+ exports.funnelWindowLine = funnelWindowLine;
11
+ exports.adoptionWindowLine = adoptionWindowLine;
12
+ exports.outcomesWindowLine = outcomesWindowLine;
13
+ exports.suppressedCellsLine = suppressedCellsLine;
14
+ exports.exclusionValue = exclusionValue;
15
+ const data_provider_1 = require("@skrr-ai/data-provider");
16
+ /**
17
+ * Terminal wording for a Store listing (`skrr store show`) and its publisher
18
+ * readouts (`skrr store stats`). Pure functions, so the commands only fetch
19
+ * and print and every sentence here is pinned by a unit test.
20
+ *
21
+ * Two rules carried over from the web surfaces, because a terminal is not a
22
+ * licence to say less:
23
+ *
24
+ * - The capability manifest is a DISCLOSURE. Nothing narrows a run to it
25
+ * (see `client/src/components/Store/capabilityDisclosure.ts`), so no line
26
+ * here says an agent is limited, restricted or "can only" do something.
27
+ * `Unrestricted` is the one state word, and it names the BAD case.
28
+ * - A k-anonymous readout below its floor has NO figures. It is printed as
29
+ * "withheld" with the floor it missed, never as 0 — a zero is a claim that
30
+ * nobody did the thing, and the server did not make that claim.
31
+ */
32
+ /** A listing's price in token credits (1,000,000 = $1), as the Store states it. */
33
+ function formatListingPrice(price) {
34
+ return (0, data_provider_1.formatStoreAcquisitionPrice)(price);
35
+ }
36
+ /** `4.6 ★ (12 ratings)`, or `No ratings yet` — never `0.0` for an unrated listing. */
37
+ function formatListingRating(rating, count) {
38
+ const ratings = Number(count) || 0;
39
+ if (ratings <= 0)
40
+ return 'No ratings yet';
41
+ return `${(Number(rating) || 0).toFixed(1)} / 5 (${ratings} rating${ratings === 1 ? '' : 's'})`;
42
+ }
43
+ const UNAVAILABLE_REASON = {
44
+ not_recorded: 'no capability record was stored for this release',
45
+ digest_mismatch: 'the stored record describes a different configuration, so it is not shown',
46
+ no_release: 'the listing has no approved public release',
47
+ };
48
+ const SHARED_DATA = {
49
+ none: 'None — you start from a blank agent',
50
+ bootstrap: "The publisher's bootstrap files are offered with the agent",
51
+ memory: "The publisher's shared memories are offered with the agent",
52
+ full: "The publisher's bootstrap files and shared memories are offered with the agent",
53
+ };
54
+ function listOrNone(items, none = 'None named') {
55
+ return items.length > 0 ? items.join(', ') : none;
56
+ }
57
+ /** A permission dimension: a wildcard entry means it is not narrowed at all. */
58
+ function permissionValue(items) {
59
+ if (items.some(data_provider_1.isUnrestrictedCapabilityEntry)) {
60
+ const named = items.filter((entry) => !(0, data_provider_1.isUnrestrictedCapabilityEntry)(entry));
61
+ return named.length > 0 ? `Unrestricted (also names: ${named.join(', ')})` : 'Unrestricted';
62
+ }
63
+ return listOrNone(items);
64
+ }
65
+ /**
66
+ * What the listed release is configured to use, as `label: value` pairs.
67
+ *
68
+ * `unavailable` stays its own answer — "we could not tell" — and is never
69
+ * rendered as an empty manifest, which would read as "uses nothing".
70
+ */
71
+ function capabilityDisclosureRows(view) {
72
+ if (!view) {
73
+ return [['Disclosure', 'Not available — this server did not send one']];
74
+ }
75
+ if (view.status !== 'available') {
76
+ return [['Disclosure', `Not available — ${UNAVAILABLE_REASON[view.reason] ?? view.reason}`]];
77
+ }
78
+ const m = view.manifest;
79
+ const rows = [];
80
+ rows.push([
81
+ 'Platform capabilities',
82
+ m.platformCapabilities.mode === 'unrestricted'
83
+ ? 'Unrestricted — chosen per request'
84
+ : m.platformCapabilities.mode === 'not_loaded'
85
+ ? 'Not loaded by its tool policy'
86
+ : listOrNone(m.platformCapabilities.capabilities),
87
+ ]);
88
+ rows.push([
89
+ 'Built-in tools',
90
+ m.builtinTools.mode === 'platform_default'
91
+ ? 'Platform default set (includes a shell and web access)'
92
+ : m.builtinTools.mode === 'none'
93
+ ? 'None'
94
+ : listOrNone(m.builtinTools.tools),
95
+ ]);
96
+ rows.push(['Tools', permissionValue(m.permissionManifest.tools)]);
97
+ rows.push(['Connectors', permissionValue(m.permissionManifest.connectors)]);
98
+ rows.push(['Network', permissionValue(m.permissionManifest.networkDomains)]);
99
+ rows.push(['Data', permissionValue(m.permissionManifest.dataScopes)]);
100
+ rows.push(['Secrets', permissionValue(m.permissionManifest.secretNames)]);
101
+ const delegation = m.delegation;
102
+ let delegationValue;
103
+ switch (delegation.mode) {
104
+ case 'none':
105
+ delegationValue = 'None';
106
+ break;
107
+ case 'all':
108
+ delegationValue = 'Unrestricted — any agent in its network';
109
+ break;
110
+ case 'not_loaded':
111
+ delegationValue = 'Not loaded by its tool policy';
112
+ break;
113
+ default:
114
+ delegationValue = listOrNone(delegation.agentIds);
115
+ }
116
+ if (delegation.includesPublicAgents && delegation.mode !== 'none') {
117
+ delegationValue += ' (includes public agents)';
118
+ }
119
+ rows.push(['Delegates to', delegationValue]);
120
+ const model = [m.model.provider, m.model.model].filter(Boolean).join(' / ');
121
+ rows.push(['Model', model || 'Not stated']);
122
+ const autonomy = [];
123
+ if (m.proactive.enabled) {
124
+ const watches = [...m.proactive.sources, ...m.proactive.watchers];
125
+ autonomy.push(watches.length > 0
126
+ ? `Acts on its own schedule after install (watches: ${watches.join(', ')})`
127
+ : 'Acts on its own schedule after install');
128
+ }
129
+ if (m.firstContact)
130
+ autonomy.push('Starts a conversation shortly after install');
131
+ rows.push(['Acts on its own', autonomy.length > 0 ? autonomy.join('; ') : 'No']);
132
+ rows.push(['Shared data', SHARED_DATA[m.sharedData] ?? m.sharedData]);
133
+ return rows;
134
+ }
135
+ /** One sentence that keeps the disclosure from being read as a sandbox. */
136
+ exports.CAPABILITY_DISCLOSURE_FOOTNOTE = 'Recorded by the platform when the release was created. A disclosure of its configuration — not a limit on what a run may do.';
137
+ /** Align `label: value` pairs under a section, indented two spaces. */
138
+ function labelledLines(rows) {
139
+ const width = Math.max(0, ...rows.map(([label]) => label.length)) + 1;
140
+ return rows.map(([label, value]) => ` ${`${label}:`.padEnd(width + 1)}${value}`);
141
+ }
142
+ // ─── Publisher readouts (`skrr store stats`) ────────────────────────────────
143
+ /** `withheld: fewer than 5 buyers in this window` — the floor, never a zero. */
144
+ function withheldLine(minimumCohort, unit) {
145
+ return `withheld: fewer than ${minimumCohort} ${unit} in this window, so no figures are shown`;
146
+ }
147
+ function formatRate(value) {
148
+ if (value === null || value === undefined || !Number.isFinite(Number(value)))
149
+ return '-';
150
+ return `${Math.round(Number(value) * 100)}%`;
151
+ }
152
+ function day(value) {
153
+ return value ? String(value).slice(0, 10) : '?';
154
+ }
155
+ function funnelWindowLine(summary) {
156
+ return `${summary.days}-day window, ${day(summary.since)} to ${day(summary.until)} (UTC, complete days)`;
157
+ }
158
+ function adoptionWindowLine(summary) {
159
+ return `copies acquired before ${day(summary.until)} (UTC)`;
160
+ }
161
+ function outcomesWindowLine(outcomes) {
162
+ return `${outcomes.windowDays}-day window, ${day(outcomes.since)} to ${day(outcomes.until)} (UTC)`;
163
+ }
164
+ /**
165
+ * Small cells that were withheld from an otherwise reported readout. Said
166
+ * once, with the floor, so a short table is not mistaken for a complete one.
167
+ */
168
+ function suppressedCellsLine(cells, minimumCohort, unit) {
169
+ const parts = Object.entries(cells)
170
+ .filter(([, count]) => Number(count) > 0)
171
+ .map(([name, count]) => `${count} ${humanize(name)}`);
172
+ if (parts.length === 0)
173
+ return null;
174
+ return `Withheld rows (fewer than ${minimumCohort} ${unit} each): ${parts.join(', ')}.`;
175
+ }
176
+ function humanize(key) {
177
+ return key.replace(/([a-z])([A-Z])/g, '$1 $2').toLowerCase();
178
+ }
179
+ /** An exclusion count; `null` is "some, from too few buyers to say how many". */
180
+ function exclusionValue(value) {
181
+ if (value === null)
182
+ return 'some (too few buyers to count)';
183
+ if (value === undefined)
184
+ return '-';
185
+ return String(value);
186
+ }
@@ -0,0 +1,67 @@
1
+ import { type TaskBatchItemResult, type TaskBatchPatchItem } from '@skrr-ai/data-provider';
2
+ export type ApiFailure = {
3
+ message: string;
4
+ status?: number;
5
+ code?: string;
6
+ retryable: boolean;
7
+ };
8
+ /** Normalize a thrown API error (or a per-item batch error) into one shape. */
9
+ export declare function describeApiFailure(err: unknown): ApiFailure;
10
+ /**
11
+ * A server that predates the batch routes answers 404 (no such POST route) or
12
+ * 405. A processed batch is ALWAYS a 200 (or 400/413/429 with a code), so a
13
+ * bare 404/405 on the batch call itself means "route missing", never "task
14
+ * not found".
15
+ */
16
+ export declare function isBatchRouteMissing(err: unknown): boolean;
17
+ export declare function chunkItems<T>(items: T[], size?: number): T[][];
18
+ /**
19
+ * Same chunk, same key: a retry of an interrupted command replays the stored
20
+ * result instead of creating twice. The key is a fingerprint of the items, so a
21
+ * DIFFERENT chunk can never collide with it (the server answers 422 on a key
22
+ * reused with a different body).
23
+ */
24
+ export declare function batchIdempotencyKey(kind: 'create' | 'patch', items: unknown[]): string;
25
+ export type BatchCreateNode = {
26
+ key: string;
27
+ parentKey?: string;
28
+ payload: Record<string, unknown>;
29
+ };
30
+ export type BatchCreatedRow = {
31
+ key: string;
32
+ id: string;
33
+ identifier?: string;
34
+ /** `created` now, or `exists` when an earlier attempt already made it. */
35
+ status: 'created' | 'exists';
36
+ externalKey?: string;
37
+ };
38
+ export type BatchCreateFailure = {
39
+ key: string;
40
+ /** Not attempted because its parent was not created (or an earlier chunk failed). */
41
+ skipped: boolean;
42
+ error: ApiFailure;
43
+ };
44
+ export type BatchCreateOutcome = {
45
+ supported: false;
46
+ } | {
47
+ supported: true;
48
+ rows: BatchCreatedRow[];
49
+ failures: BatchCreateFailure[];
50
+ };
51
+ /**
52
+ * Create `nodes` (parents before children) in chunks. `mapping` holds key -> id
53
+ * for nodes that already exist and is extended in place. Stops after the first
54
+ * chunk that reports a failure, as the serial path stopped at its first failure.
55
+ */
56
+ export declare function createNodesViaBatch(nodes: BatchCreateNode[], mapping: Record<string, string>): Promise<BatchCreateOutcome>;
57
+ export type BatchPatchOutcome = {
58
+ supported: false;
59
+ } | {
60
+ supported: true;
61
+ results: TaskBatchItemResult[];
62
+ };
63
+ /**
64
+ * Apply `updates` in chunks; `results[i]` answers `updates[i]`. A chunk the
65
+ * server never processed is reported `skipped` for every row rather than lost.
66
+ */
67
+ export declare function patchTasksViaBatch(updates: TaskBatchPatchItem[]): Promise<BatchPatchOutcome>;