@skrr-ai/cli 0.1.91 → 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 (272) 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/index.js +3 -2
  45. package/dist/commands/machines/dedicated/power/set.js +1 -1
  46. package/dist/commands/machines/dedicated/power/waiting.d.ts +13 -0
  47. package/dist/commands/machines/dedicated/power/waiting.js +36 -0
  48. package/dist/commands/open.d.ts +24 -0
  49. package/dist/commands/open.js +74 -0
  50. package/dist/commands/projects/archive.d.ts +1 -0
  51. package/dist/commands/projects/archive.js +23 -0
  52. package/dist/commands/projects/delete.d.ts +1 -0
  53. package/dist/commands/projects/delete.js +23 -0
  54. package/dist/commands/projects/list.d.ts +3 -0
  55. package/dist/commands/projects/list.js +12 -2
  56. package/dist/commands/spaces/actions/add.js +4 -3
  57. package/dist/commands/spaces/actions/available.js +3 -2
  58. package/dist/commands/spaces/actions/list.js +5 -4
  59. package/dist/commands/spaces/actions/replace.js +6 -5
  60. package/dist/commands/spaces/archive.js +3 -2
  61. package/dist/commands/spaces/auto-executor/preview.js +4 -3
  62. package/dist/commands/spaces/auto-executor/run.js +4 -3
  63. package/dist/commands/spaces/auto-executor/runs.js +3 -2
  64. package/dist/commands/spaces/auto-executor/update.js +4 -3
  65. package/dist/commands/spaces/bootstrap.js +3 -2
  66. package/dist/commands/spaces/briefs/delete.js +3 -2
  67. package/dist/commands/spaces/briefs/get.js +3 -2
  68. package/dist/commands/spaces/briefs/list.js +3 -2
  69. package/dist/commands/spaces/briefs/set.js +5 -4
  70. package/dist/commands/spaces/capacity.js +5 -4
  71. package/dist/commands/spaces/conversations.js +3 -2
  72. package/dist/commands/spaces/cycles/create.js +3 -2
  73. package/dist/commands/spaces/cycles/graph.js +2 -1
  74. package/dist/commands/spaces/cycles/list.js +3 -2
  75. package/dist/commands/spaces/cycles/settings.js +4 -3
  76. package/dist/commands/spaces/cycles/show.js +3 -2
  77. package/dist/commands/spaces/cycles/update.js +3 -2
  78. package/dist/commands/spaces/delete.js +4 -3
  79. package/dist/commands/spaces/expertise-suggestions.js +4 -3
  80. package/dist/commands/spaces/files/delete.js +3 -2
  81. package/dist/commands/spaces/files/folders/create.js +3 -2
  82. package/dist/commands/spaces/files/folders/delete.js +3 -2
  83. package/dist/commands/spaces/files/folders/list.js +3 -2
  84. package/dist/commands/spaces/files/folders/update.js +3 -2
  85. package/dist/commands/spaces/files/list.js +3 -2
  86. package/dist/commands/spaces/files/move.js +3 -2
  87. package/dist/commands/spaces/files/rename.js +3 -2
  88. package/dist/commands/spaces/files/upload.js +6 -5
  89. package/dist/commands/spaces/github-automations/set.js +3 -2
  90. package/dist/commands/spaces/github-automations/show.js +3 -2
  91. package/dist/commands/spaces/goals.js +2 -1
  92. package/dist/commands/spaces/heartbeats/create.js +4 -3
  93. package/dist/commands/spaces/heartbeats/delete.js +4 -3
  94. package/dist/commands/spaces/heartbeats/list.js +4 -3
  95. package/dist/commands/spaces/heartbeats/status.js +3 -2
  96. package/dist/commands/spaces/heartbeats/update.js +4 -3
  97. package/dist/commands/spaces/insights.js +5 -4
  98. package/dist/commands/spaces/labels/add.js +4 -3
  99. package/dist/commands/spaces/labels/list.js +2 -1
  100. package/dist/commands/spaces/labels/remove.js +4 -3
  101. package/dist/commands/spaces/list.d.ts +3 -0
  102. package/dist/commands/spaces/list.js +11 -2
  103. package/dist/commands/spaces/live/cards/create.js +3 -2
  104. package/dist/commands/spaces/live/cards/list.js +3 -2
  105. package/dist/commands/spaces/live/cards/reorder.js +7 -2
  106. package/dist/commands/spaces/live/scene.js +4 -3
  107. package/dist/commands/spaces/members/add.js +7 -6
  108. package/dist/commands/spaces/members/list.js +4 -3
  109. package/dist/commands/spaces/members/remove.js +7 -6
  110. package/dist/commands/spaces/move.js +3 -2
  111. package/dist/commands/spaces/pin.js +5 -4
  112. package/dist/commands/spaces/preferences/show.js +4 -3
  113. package/dist/commands/spaces/preferences/tabs.js +4 -3
  114. package/dist/commands/spaces/revisions.js +3 -2
  115. package/dist/commands/spaces/room/ensure.js +5 -4
  116. package/dist/commands/spaces/room/messages.js +3 -2
  117. package/dist/commands/spaces/room/show.js +5 -4
  118. package/dist/commands/spaces/skills/add.js +4 -3
  119. package/dist/commands/spaces/skills/list.js +3 -2
  120. package/dist/commands/spaces/skills/pin.js +4 -3
  121. package/dist/commands/spaces/skills/remove.js +4 -3
  122. package/dist/commands/spaces/snapshot.js +3 -2
  123. package/dist/commands/spaces/states/archive.js +3 -2
  124. package/dist/commands/spaces/states/create.js +3 -2
  125. package/dist/commands/spaces/states/list.js +3 -2
  126. package/dist/commands/spaces/states/reorder.js +2 -1
  127. package/dist/commands/spaces/states/update.js +3 -2
  128. package/dist/commands/spaces/summary.js +4 -3
  129. package/dist/commands/spaces/tasks.d.ts +3 -0
  130. package/dist/commands/spaces/tasks.js +14 -3
  131. package/dist/commands/spaces/triggers/delete.js +5 -4
  132. package/dist/commands/spaces/triggers/set.js +4 -3
  133. package/dist/commands/spaces/triggers/show.js +4 -3
  134. package/dist/commands/spaces/unarchive.js +3 -2
  135. package/dist/commands/spaces/update.js +5 -4
  136. package/dist/commands/spaces/views/create.js +3 -2
  137. package/dist/commands/spaces/views/list.js +3 -2
  138. package/dist/commands/spaces/views/reorder.js +6 -3
  139. package/dist/commands/spaces/views/subscribe.js +2 -1
  140. package/dist/commands/spaces/views/subscriptions.js +1 -0
  141. package/dist/commands/spaces/views/unsubscribe.js +2 -1
  142. package/dist/commands/spaces/widgets/add.js +4 -3
  143. package/dist/commands/spaces/widgets/list.js +3 -2
  144. package/dist/commands/spaces/widgets/remove.js +5 -4
  145. package/dist/commands/spaces/work-graph.js +2 -1
  146. package/dist/commands/store/install.d.ts +1 -1
  147. package/dist/commands/store/install.js +24 -8
  148. package/dist/commands/store/show.d.ts +25 -0
  149. package/dist/commands/store/show.js +203 -0
  150. package/dist/commands/store/stats.d.ts +33 -0
  151. package/dist/commands/store/stats.js +258 -0
  152. package/dist/commands/tasks/actions/attach.js +1 -1
  153. package/dist/commands/tasks/actions/detach.js +4 -3
  154. package/dist/commands/tasks/activity.js +3 -2
  155. package/dist/commands/tasks/ancestors.js +2 -1
  156. package/dist/commands/tasks/approvals/create.js +2 -1
  157. package/dist/commands/tasks/approvals/delete.js +3 -2
  158. package/dist/commands/tasks/approvals/list.js +5 -4
  159. package/dist/commands/tasks/approvals/resolve.js +2 -1
  160. package/dist/commands/tasks/archive.js +3 -2
  161. package/dist/commands/tasks/assign.js +4 -3
  162. package/dist/commands/tasks/attachments/delete.js +3 -2
  163. package/dist/commands/tasks/attachments/download.d.ts +1 -0
  164. package/dist/commands/tasks/attachments/download.js +20 -1
  165. package/dist/commands/tasks/attachments/list.js +2 -1
  166. package/dist/commands/tasks/attachments/set-role.js +2 -1
  167. package/dist/commands/tasks/attachments/upload.js +2 -1
  168. package/dist/commands/tasks/bulk-update.d.ts +1 -0
  169. package/dist/commands/tasks/bulk-update.js +106 -15
  170. package/dist/commands/tasks/cancel-cascade.d.ts +1 -0
  171. package/dist/commands/tasks/cancel-cascade.js +13 -3
  172. package/dist/commands/tasks/cascade-status.js +2 -1
  173. package/dist/commands/tasks/chat/send.d.ts +44 -0
  174. package/dist/commands/tasks/chat/send.js +112 -0
  175. package/dist/commands/tasks/checkout.js +3 -2
  176. package/dist/commands/tasks/children.js +2 -1
  177. package/dist/commands/tasks/comments/add.js +7 -6
  178. package/dist/commands/tasks/comments/anchor.js +8 -7
  179. package/dist/commands/tasks/comments/delete.js +3 -2
  180. package/dist/commands/tasks/comments/list.js +2 -1
  181. package/dist/commands/tasks/comments/reopen.js +3 -2
  182. package/dist/commands/tasks/comments/resolve.js +3 -2
  183. package/dist/commands/tasks/create-tree.d.ts +63 -0
  184. package/dist/commands/tasks/create-tree.js +197 -4
  185. package/dist/commands/tasks/delete.js +5 -4
  186. package/dist/commands/tasks/descendants.js +2 -1
  187. package/dist/commands/tasks/dri-plan.js +3 -2
  188. package/dist/commands/tasks/dri-run.js +3 -2
  189. package/dist/commands/tasks/dri-status.js +2 -1
  190. package/dist/commands/tasks/duplicate-pipeline.js +2 -1
  191. package/dist/commands/tasks/execution-summary.js +2 -1
  192. package/dist/commands/tasks/execution-timeline.js +2 -1
  193. package/dist/commands/tasks/fork.js +1 -0
  194. package/dist/commands/tasks/forward.js +4 -3
  195. package/dist/commands/tasks/handover.js +1 -0
  196. package/dist/commands/tasks/interrupt.js +3 -2
  197. package/dist/commands/tasks/labels/attach.js +4 -3
  198. package/dist/commands/tasks/labels/detach.js +4 -3
  199. package/dist/commands/tasks/labels/suggest.js +5 -4
  200. package/dist/commands/tasks/list.d.ts +27 -1
  201. package/dist/commands/tasks/list.js +101 -3
  202. package/dist/commands/tasks/move.js +4 -3
  203. package/dist/commands/tasks/output.js +6 -5
  204. package/dist/commands/tasks/pause-schedule.js +3 -2
  205. package/dist/commands/tasks/promote.js +1 -0
  206. package/dist/commands/tasks/prompt-log.js +2 -1
  207. package/dist/commands/tasks/release.js +5 -4
  208. package/dist/commands/tasks/remind.js +2 -1
  209. package/dist/commands/tasks/replay.js +3 -2
  210. package/dist/commands/tasks/report.js +1 -0
  211. package/dist/commands/tasks/resume-schedule.js +3 -2
  212. package/dist/commands/tasks/retry-schedule.js +3 -2
  213. package/dist/commands/tasks/retry.js +10 -9
  214. package/dist/commands/tasks/revisions.js +2 -1
  215. package/dist/commands/tasks/runs.js +6 -5
  216. package/dist/commands/tasks/schedule.js +3 -2
  217. package/dist/commands/tasks/self-schedule.js +6 -5
  218. package/dist/commands/tasks/skills/pin.js +3 -2
  219. package/dist/commands/tasks/skills/unpin.js +3 -2
  220. package/dist/commands/tasks/snooze.js +6 -5
  221. package/dist/commands/tasks/start-all.js +5 -4
  222. package/dist/commands/tasks/subscribe.js +1 -0
  223. package/dist/commands/tasks/tags/add.js +4 -3
  224. package/dist/commands/tasks/tags/remove.js +4 -3
  225. package/dist/commands/tasks/timeline.js +3 -2
  226. package/dist/commands/tasks/today.d.ts +4 -1
  227. package/dist/commands/tasks/today.js +12 -2
  228. package/dist/commands/tasks/transcript.js +6 -5
  229. package/dist/commands/tasks/unschedule.js +3 -2
  230. package/dist/commands/tasks/unsnooze.js +3 -2
  231. package/dist/commands/tasks/unsubscribe.js +2 -1
  232. package/dist/commands/tasks/update.js +5 -4
  233. package/dist/commands/tasks/wait.js +5 -4
  234. package/dist/lib/agent-distribution.d.ts +37 -0
  235. package/dist/lib/agent-distribution.js +63 -0
  236. package/dist/lib/agent-ref.d.ts +69 -0
  237. package/dist/lib/agent-ref.js +168 -0
  238. package/dist/lib/api-fetch.d.ts +2 -0
  239. package/dist/lib/api-fetch.js +14 -3
  240. package/dist/lib/command-hygiene.d.ts +13 -0
  241. package/dist/lib/command-hygiene.js +62 -2
  242. package/dist/lib/dedicated-power.d.ts +16 -1
  243. package/dist/lib/dedicated-power.js +153 -2
  244. package/dist/lib/dry-run-plans.d.ts +50 -0
  245. package/dist/lib/dry-run-plans.js +85 -0
  246. package/dist/lib/json-output.d.ts +31 -0
  247. package/dist/lib/json-output.js +78 -0
  248. package/dist/lib/list-output.d.ts +75 -0
  249. package/dist/lib/list-output.js +266 -0
  250. package/dist/lib/machine-daemon-log.d.ts +36 -0
  251. package/dist/lib/machine-daemon-log.js +78 -0
  252. package/dist/lib/node-adapter.js +10 -1
  253. package/dist/lib/open-target.d.ts +12 -0
  254. package/dist/lib/open-target.js +108 -0
  255. package/dist/lib/rate-limit-retry.d.ts +45 -0
  256. package/dist/lib/rate-limit-retry.js +88 -0
  257. package/dist/lib/store-listing.d.ts +45 -0
  258. package/dist/lib/store-listing.js +186 -0
  259. package/dist/lib/task-batch.d.ts +67 -0
  260. package/dist/lib/task-batch.js +227 -0
  261. package/dist/lib/terminal-qr.d.ts +55 -0
  262. package/dist/lib/terminal-qr.js +119 -0
  263. package/dist/lib/web-url.d.ts +11 -0
  264. package/dist/lib/web-url.js +24 -0
  265. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +68 -0
  266. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +47 -1
  267. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +68 -0
  268. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +46 -0
  269. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  270. package/dist/node_modules/@skrr-ai/data-provider/index.js +6615 -6112
  271. package/oclif.manifest.json +41499 -32585
  272. package/package.json +2 -1
@@ -0,0 +1,69 @@
1
+ import { type Attribution, type DistributionChannel, type ResolveAgentVanityResponse, type ResolveDistributionCodeResponse } from '@skrr-ai/data-provider';
2
+ /**
3
+ * THE ONE PLACE A STORE AGENT REFERENCE IS RESOLVED.
4
+ *
5
+ * `skrr store install|show|stats`, `skrr agents share|badge` and `skrr open`
6
+ * read the positional through `resolveAgentRef`, never by using the raw string
7
+ * as an id. Accepted, in this order:
8
+ *
9
+ * - an agent id, typed as-is (`agent_abc`) — no attribution: nobody shared it;
10
+ * - any first-party link `parseSkrrLink` recognises as an agent
11
+ * (`https://skrr.ai/a/<id>[/slug]`, `/store/agents/<id>`, `/agent/<id>`,
12
+ * `skrr://agent/<id>`), keeping the link's own `?s=` / `?ch=`;
13
+ * - a first-party link that carries only a share code (`/?s=<code>`), or
14
+ * names something the CLI cannot look up locally but carries a code — the
15
+ * code is resolved through the server (`resolveDistributionCode`);
16
+ * - a vanity address, `@handle/agent-slug` or `…/@handle/agent-slug` — the
17
+ * alias is resolved through the server's public vanity endpoint (a retired
18
+ * handle or slug still resolves; agent-distribution-2026-10-08, "Vanity
19
+ * URLs"). A vanity link that also carries a code is resolved by its code,
20
+ * which names the agent exactly.
21
+ *
22
+ * Link recognition is data-provider's (`inspectSkrrLink`, principle 5): no
23
+ * regex here decides what a URL names.
24
+ *
25
+ * Attribution belongs to the SHARER's channel. A pasted link keeps the `ch` it
26
+ * was minted with; a bare id carries none, and this never invents one (no
27
+ * `ch=cli` for an id someone typed — that would credit a share nobody made).
28
+ */
29
+ export type ResolvedAgentRef = {
30
+ agentId: string;
31
+ /**
32
+ * How it was given: an id, a link naming the agent, a share code the server
33
+ * resolved, or a vanity alias the server resolved.
34
+ */
35
+ source: 'id' | 'link' | 'code' | 'vanity';
36
+ attribution: Attribution;
37
+ };
38
+ export type AgentRefErrorCode = 'AGENT_REF_EMPTY' | 'AGENT_REF_UNSUPPORTED' | 'AGENT_REF_FOREIGN' | 'AGENT_REF_NOT_AN_AGENT' | 'AGENT_REF_VANITY_UNRESOLVED' | 'AGENT_REF_CODE_UNRESOLVED';
39
+ export declare class AgentRefError extends Error {
40
+ readonly code: AgentRefErrorCode;
41
+ constructor(message: string, code: AgentRefErrorCode);
42
+ }
43
+ export type AgentRefOptions = {
44
+ /** The configured deployment; its hosts count as first-party besides the built-in list. */
45
+ baseURL?: string;
46
+ /** How a share code is resolved. Defaults to the anonymous public resolve endpoint. */
47
+ resolveCode?: (code: string) => Promise<ResolveDistributionCodeResponse | null>;
48
+ /** How a vanity alias is resolved. Defaults to the anonymous public vanity endpoint. */
49
+ resolveVanity?: (handle: string, slug: string) => Promise<ResolveAgentVanityResponse | null>;
50
+ };
51
+ /**
52
+ * The built-in first-party hosts plus every origin the configured deployment
53
+ * serves (a dev or self-hosted `baseURL` is first-party for its own user).
54
+ */
55
+ export declare function cliFirstPartyHosts(baseURL?: string): string[];
56
+ export declare function resolveAgentRef(input: string, options?: AgentRefOptions): Promise<ResolvedAgentRef>;
57
+ /**
58
+ * The canonical public address of a resolved agent, keeping the attribution it
59
+ * arrived with — what a command prints when it echoes a link back (an install
60
+ * command, an `open`), so following the echo credits the same share.
61
+ */
62
+ export declare function attributedListingUrl(baseURL: string, ref: Pick<ResolvedAgentRef, 'agentId' | 'attribution'>): string;
63
+ /** The install body fields an attribution maps to; empty for an unattributed ref. */
64
+ export declare function installAttribution(attribution: Attribution): {
65
+ distributionCode?: string;
66
+ channel?: DistributionChannel;
67
+ };
68
+ /** Quote a URL for a POSIX shell: `?` and `&` in an attributed link are metacharacters. */
69
+ export declare function shellQuote(value: string): string;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AgentRefError = void 0;
4
+ exports.cliFirstPartyHosts = cliFirstPartyHosts;
5
+ exports.resolveAgentRef = resolveAgentRef;
6
+ exports.attributedListingUrl = attributedListingUrl;
7
+ exports.installAttribution = installAttribution;
8
+ exports.shellQuote = shellQuote;
9
+ const data_provider_1 = require("@skrr-ai/data-provider");
10
+ const http_error_1 = require("./http-error");
11
+ const web_url_1 = require("./web-url");
12
+ class AgentRefError extends Error {
13
+ code;
14
+ constructor(message, code) {
15
+ super(message);
16
+ this.code = code;
17
+ this.name = 'AgentRefError';
18
+ }
19
+ }
20
+ exports.AgentRefError = AgentRefError;
21
+ /**
22
+ * An agent id is a single opaque token (`agent_…` today). Anything with a
23
+ * slash, a colon, whitespace or a dot is a link, a path or a typo — none of
24
+ * which may be sent to the API as if it were an id, because the server would
25
+ * answer "not found" and the person would conclude the agent does not exist.
26
+ */
27
+ const AGENT_ID_TOKEN = /^[A-Za-z0-9_-]+$/;
28
+ function hostOf(origin) {
29
+ try {
30
+ return new URL(origin).host.toLowerCase();
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ /**
37
+ * The built-in first-party hosts plus every origin the configured deployment
38
+ * serves (a dev or self-hosted `baseURL` is first-party for its own user).
39
+ */
40
+ function cliFirstPartyHosts(baseURL) {
41
+ const hosts = new Set(data_provider_1.FIRST_PARTY_HOSTS.map((host) => host.toLowerCase()));
42
+ if (baseURL) {
43
+ for (const origin of [baseURL, ...(0, web_url_1.firstPartyWebOrigins)(baseURL)]) {
44
+ const host = hostOf(origin);
45
+ if (host) {
46
+ hosts.add(host);
47
+ if (!host.startsWith('www.'))
48
+ hosts.add(`www.${host}`);
49
+ }
50
+ }
51
+ }
52
+ return [...hosts];
53
+ }
54
+ async function defaultResolveCode(code) {
55
+ try {
56
+ return await data_provider_1.dataService.resolveDistributionCode(code);
57
+ }
58
+ catch (err) {
59
+ if ((0, http_error_1.httpStatusOf)(err) === 404)
60
+ return null;
61
+ throw err;
62
+ }
63
+ }
64
+ async function defaultResolveVanity(handle, slug) {
65
+ try {
66
+ return await data_provider_1.dataService.resolveAgentVanity({ handle, slug });
67
+ }
68
+ catch (err) {
69
+ if ((0, http_error_1.httpStatusOf)(err) === 404)
70
+ return null;
71
+ throw err;
72
+ }
73
+ }
74
+ async function resolveByVanity(value, handle, slug, attribution, options) {
75
+ const resolved = await (options.resolveVanity ?? defaultResolveVanity)(handle, slug);
76
+ if (resolved?.entity?.kind !== 'agent' || !resolved.entity.id) {
77
+ throw new AgentRefError(`No public agent answers to "${value}". The publisher may have unpublished it; their ` +
78
+ `page lists what they publish: skrr open ${(0, data_provider_1.entityPath)({ kind: 'publisher', handle })}`, 'AGENT_REF_VANITY_UNRESOLVED');
79
+ }
80
+ // An alias is an address, not a share: it carries no attribution of its own.
81
+ return { agentId: resolved.entity.id, source: 'vanity', attribution };
82
+ }
83
+ function withChannel(attribution, channel) {
84
+ if (attribution.channel)
85
+ return attribution;
86
+ const normalized = (0, data_provider_1.normalizeDistributionChannel)(channel);
87
+ return normalized ? { ...attribution, channel: normalized } : attribution;
88
+ }
89
+ async function resolveByCode(value, attribution, options) {
90
+ const code = attribution.code;
91
+ const resolved = await (options.resolveCode ?? defaultResolveCode)(code);
92
+ if (!resolved?.entity) {
93
+ throw new AgentRefError(`The share code in "${value}" does not point at a public agent: it may have been ` +
94
+ 'unpublished, or the link was copied incompletely.', 'AGENT_REF_CODE_UNRESOLVED');
95
+ }
96
+ if (resolved.entity.kind !== 'agent') {
97
+ throw new AgentRefError(`"${value}" is a link to a ${resolved.entity.kind.replace(/_/g, ' ')}, not an agent.`, 'AGENT_REF_NOT_AN_AGENT');
98
+ }
99
+ return {
100
+ agentId: resolved.entity.id,
101
+ source: 'code',
102
+ // The link's own `ch` wins; the code's minted channel fills a link without one.
103
+ attribution: withChannel(attribution, resolved.channel),
104
+ };
105
+ }
106
+ async function resolveAgentRef(input, options = {}) {
107
+ const value = String(input ?? '').trim();
108
+ if (!value) {
109
+ throw new AgentRefError(`Name the agent: pass its id (agent_…) or a ${data_provider_1.BRAND.displayName} link to it.`, 'AGENT_REF_EMPTY');
110
+ }
111
+ if (AGENT_ID_TOKEN.test(value)) {
112
+ return { agentId: value, source: 'id', attribution: {} };
113
+ }
114
+ const inspected = (0, data_provider_1.inspectSkrrLink)(value, {
115
+ firstPartyHosts: cliFirstPartyHosts(options.baseURL),
116
+ });
117
+ if (!inspected) {
118
+ throw /^[a-z][a-z0-9+.-]*:\/\//i.test(value)
119
+ ? new AgentRefError(`"${value}" is not a ${data_provider_1.BRAND.displayName} link, so it was not followed. Pass an agent ` +
120
+ `id or a link on ${data_provider_1.BRAND.displayName}'s own site.`, 'AGENT_REF_FOREIGN')
121
+ : unsupported(value);
122
+ }
123
+ const { link, attribution } = inspected;
124
+ switch (link.kind) {
125
+ case 'agent':
126
+ case 'store_agent':
127
+ case 'agent_owner':
128
+ return { agentId: link.agentId, source: 'link', attribution };
129
+ case 'agent_vanity':
130
+ // A code on the link names the agent exactly; a bare alias is resolved
131
+ // by the server's vanity store.
132
+ if (attribution.code)
133
+ return resolveByCode(value, attribution, options);
134
+ return resolveByVanity(value, link.handle, link.slug, attribution, options);
135
+ case 'unknown':
136
+ if (attribution.code)
137
+ return resolveByCode(value, attribution, options);
138
+ throw unsupported(value);
139
+ default:
140
+ throw new AgentRefError(`"${value}" is a link to a ${link.kind.replace(/_/g, ' ')}, not an agent.`, 'AGENT_REF_NOT_AN_AGENT');
141
+ }
142
+ }
143
+ function unsupported(value) {
144
+ return new AgentRefError(`"${value}" is not an agent id or a link to an agent. Pass the id (agent_…) or its ` +
145
+ 'listing link (…/a/<id>).', 'AGENT_REF_UNSUPPORTED');
146
+ }
147
+ /**
148
+ * The canonical public address of a resolved agent, keeping the attribution it
149
+ * arrived with — what a command prints when it echoes a link back (an install
150
+ * command, an `open`), so following the echo credits the same share.
151
+ */
152
+ function attributedListingUrl(baseURL, ref) {
153
+ return (0, data_provider_1.buildShareUrl)((0, web_url_1.webOrigin)(baseURL), { kind: 'agent', id: ref.agentId }, {
154
+ code: ref.attribution.code,
155
+ channel: ref.attribution.channel,
156
+ });
157
+ }
158
+ /** The install body fields an attribution maps to; empty for an unattributed ref. */
159
+ function installAttribution(attribution) {
160
+ return {
161
+ ...(attribution.code ? { distributionCode: attribution.code } : {}),
162
+ ...(attribution.channel ? { channel: attribution.channel } : {}),
163
+ };
164
+ }
165
+ /** Quote a URL for a POSIX shell: `?` and `&` in an attributed link are metacharacters. */
166
+ function shellQuote(value) {
167
+ return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
168
+ }
@@ -37,6 +37,8 @@ export declare class ApiFetchError extends Error {
37
37
  * attributed by guesswork — see `node-adapter.ts`.
38
38
  */
39
39
  readonly requestId?: string;
40
+ /** Milliseconds the server asked us to wait (`Retry-After`) on a 429. */
41
+ retryAfterMs?: number;
40
42
  /**
41
43
  * Set on a 401 when this CLI's own refresh was refused AND the local
42
44
  * daemon, asked for a hand-off, refused too (OSK-12474). The daemon's reason
@@ -47,6 +47,7 @@ const daemonBroker_1 = require("./daemonBroker");
47
47
  const dpop_auth_1 = require("./dpop-auth");
48
48
  const workspace_header_1 = require("./workspace-header");
49
49
  const non_json_response_1 = require("./non-json-response");
50
+ const rate_limit_retry_1 = require("./rate-limit-retry");
50
51
  class ApiFetchError extends Error {
51
52
  status;
52
53
  body;
@@ -63,6 +64,8 @@ class ApiFetchError extends Error {
63
64
  * attributed by guesswork — see `node-adapter.ts`.
64
65
  */
65
66
  requestId;
67
+ /** Milliseconds the server asked us to wait (`Retry-After`) on a 429. */
68
+ retryAfterMs;
66
69
  /**
67
70
  * Set on a 401 when this CLI's own refresh was refused AND the local
68
71
  * daemon, asked for a hand-off, refused too (OSK-12474). The daemon's reason
@@ -186,13 +189,19 @@ async function apiFetch(pathOrUrl, opts = {}) {
186
189
  // OSK-12020 — a fresh proof per attempt for a DPoP-bound hand-off token
187
190
  // (the 401 retry below re-enters here and gets its own). No-op otherwise.
188
191
  Object.assign(headers, await (0, dpop_auth_1.dpopHeadersFor)(credential.token, method, url));
189
- return fetch(url, {
192
+ const sent = (0, workspace_header_1.withWorkspaceHeader)(headers);
193
+ // E6: a 429 on a GET or an idempotency-keyed write is retried (bounded,
194
+ // jittered, honouring Retry-After). The last 429's wait is kept for the error.
195
+ const { response, retryAfterMs } = await (0, rate_limit_retry_1.fetchWithRateLimitRetry)(() => fetch(url, {
190
196
  method,
191
- headers: (0, workspace_header_1.withWorkspaceHeader)(headers),
197
+ headers: sent,
192
198
  body,
193
199
  ...(opts.signal ? { signal: opts.signal } : {}),
194
- });
200
+ }), { method, headers: sent, signal: opts.signal });
201
+ lastRetryAfterMs = retryAfterMs;
202
+ return response;
195
203
  };
204
+ let lastRetryAfterMs;
196
205
  let res = await fetchWithCredential(cred);
197
206
  let brokerFailure = null;
198
207
  if (res.status === 401 && delegatedCli) {
@@ -271,6 +280,8 @@ async function apiFetch(pathOrUrl, opts = {}) {
271
280
  const error = new ApiFetchError(`HTTP ${res.status} ${res.statusText} — ${method} ${pathOrUrl}`, res.status, text, code, method, res.headers.get('x-request-id') || undefined);
272
281
  if (brokerFailure)
273
282
  error.brokerFailure = brokerFailure;
283
+ if (res.status === 429 && lastRetryAfterMs !== undefined)
284
+ error.retryAfterMs = lastRetryAfterMs;
274
285
  throw error;
275
286
  }
276
287
  // 204/205 carry no body by definition; an empty body has no content-type
@@ -26,6 +26,8 @@ export type CommandHygieneReport = {
26
26
  domains: number;
27
27
  budgetErrors: number;
28
28
  };
29
+ /** The verb rules the findings below are measured against (P8). */
30
+ namingGrammar: readonly string[];
29
31
  issues: CommandHygieneIssue[];
30
32
  };
31
33
  export declare function auditCommands({ rootDir, manifest, }: {
@@ -37,3 +39,14 @@ export declare function auditCommands({ rootDir, manifest, }: {
37
39
  */
38
40
  manifest?: CommandManifest;
39
41
  }): CommandHygieneReport;
42
+ /**
43
+ * The domains an agent drives most. A missing description or `--json` output
44
+ * here is a build error (P10); elsewhere it stays a warning until that domain's
45
+ * offenders are fixed, so the gate can ratchet outward one domain at a time.
46
+ */
47
+ export declare const ENFORCED_HYGIENE_DOMAINS: readonly ["tasks", "spaces", "projects"];
48
+ /**
49
+ * The verb grammar `commands --audit` checks, stated once so a reader of the
50
+ * report sees the rule and not only the findings it produced.
51
+ */
52
+ export declare const NAMING_GRAMMAR: readonly ["Verbs: list, show, create, update, delete, archive, unarchive, move. A reversible state flip is its own verb, never a flag on its inverse.", "Scope: a list verb takes its parent scope as an optional filter flag; a verb that cannot work without a scope says so in its description.", "Output: every command in tasks, spaces and projects takes --json and has a description (audit errors)."];
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NAMING_GRAMMAR = exports.ENFORCED_HYGIENE_DOMAINS = void 0;
36
37
  exports.auditCommands = auditCommands;
37
38
  const fs = __importStar(require("node:fs"));
38
39
  const path = __importStar(require("node:path"));
@@ -120,6 +121,32 @@ function auditCommands({ rootDir, manifest, }) {
120
121
  });
121
122
  }
122
123
  }
124
+ // Without a generated manifest (a source checkout, most CI jobs) the
125
+ // manifest rules below never run, so the P10 gate for tasks/spaces/projects
126
+ // would pass by not looking. Read the same two facts off the source.
127
+ if (!manifest && isEnforcedDomain(command)) {
128
+ // A spread of a shared flag set (`...paginatedExportFlags(...)`) may carry
129
+ // --json from another file; only the manifest can tell, so do not guess.
130
+ const spreadsSharedFlags = /\.\.\.[\w.]*Flags\b/.test(source);
131
+ if (!hasJson && !spreadsSharedFlags && isMachineRelevantCommand(command)) {
132
+ issues.push({
133
+ code: 'JSON_SUCCESS_OUTPUT_MISSING',
134
+ severity: 'error',
135
+ command,
136
+ file: rel,
137
+ message: 'Machine-relevant command has no --json success-output flag. Keep human-only commands intentional.',
138
+ });
139
+ }
140
+ if (!/static (?:override )?description\s*=/.test(source)) {
141
+ issues.push({
142
+ code: 'COMMAND_DESCRIPTION_MISSING',
143
+ severity: 'error',
144
+ command,
145
+ file: rel,
146
+ message: 'Command is missing a description.',
147
+ });
148
+ }
149
+ }
123
150
  if (hasFromJson && !hasJson) {
124
151
  issues.push({
125
152
  code: 'FROM_JSON_WITHOUT_JSON_OUTPUT',
@@ -153,7 +180,7 @@ function auditCommands({ rootDir, manifest, }) {
153
180
  if (!command?.description?.trim()) {
154
181
  issues.push({
155
182
  code: 'COMMAND_DESCRIPTION_MISSING',
156
- severity: 'warning',
183
+ severity: isEnforcedDomain(id) ? 'error' : 'warning',
157
184
  command: id,
158
185
  message: 'Command is missing a description in the manifest.',
159
186
  });
@@ -161,11 +188,22 @@ function auditCommands({ rootDir, manifest, }) {
161
188
  if (!hasJsonFlag(command?.flags) && isMachineRelevantCommand(id)) {
162
189
  issues.push({
163
190
  code: 'JSON_SUCCESS_OUTPUT_MISSING',
164
- severity: 'warning',
191
+ severity: isEnforcedDomain(id) ? 'error' : 'warning',
165
192
  command: id,
166
193
  message: 'Machine-relevant command has no --json success-output flag. Keep human-only commands intentional.',
167
194
  });
168
195
  }
196
+ // P8: a state flip is a verb (`archive` / `unarchive`), not a flag on its
197
+ // inverse. `spaces unarchive` follows the grammar; `tasks archive
198
+ // --unarchive` and `projects archive --unarchive` do not.
199
+ if (isEnforcedDomain(id) && hasFlag(command?.flags, 'unarchive')) {
200
+ issues.push({
201
+ code: 'VERB_GRAMMAR_INVERSE_AS_FLAG',
202
+ severity: 'warning',
203
+ command: id,
204
+ message: `Naming grammar: a state flip is its own verb (\`${id.replace(/:archive$/, ':unarchive').replace(/:/g, ' ')}\`), not --unarchive on the forward verb. Keep the flag as a deprecated alias when adding the verb.`,
205
+ });
206
+ }
169
207
  }
170
208
  }
171
209
  const errors = issues.filter((issue) => issue.severity === 'error').length;
@@ -190,6 +228,7 @@ function auditCommands({ rootDir, manifest, }) {
190
228
  domains: (0, usage_discovery_1.usageDomains)(manifestForCatalog).length,
191
229
  budgetErrors: usageBudgetIssues.length,
192
230
  },
231
+ namingGrammar: exports.NAMING_GRAMMAR,
193
232
  issues,
194
233
  };
195
234
  }
@@ -213,6 +252,27 @@ function commandIdFromRelativePath(relativePath) {
213
252
  function hasJsonFlag(flags) {
214
253
  return Boolean(flags && typeof flags === 'object' && 'json' in flags);
215
254
  }
255
+ /**
256
+ * The domains an agent drives most. A missing description or `--json` output
257
+ * here is a build error (P10); elsewhere it stays a warning until that domain's
258
+ * offenders are fixed, so the gate can ratchet outward one domain at a time.
259
+ */
260
+ exports.ENFORCED_HYGIENE_DOMAINS = ['tasks', 'spaces', 'projects'];
261
+ function isEnforcedDomain(id) {
262
+ return exports.ENFORCED_HYGIENE_DOMAINS.some((domain) => id === domain || id.startsWith(`${domain}:`));
263
+ }
264
+ function hasFlag(flags, name) {
265
+ return Boolean(flags && typeof flags === 'object' && name in flags);
266
+ }
267
+ /**
268
+ * The verb grammar `commands --audit` checks, stated once so a reader of the
269
+ * report sees the rule and not only the findings it produced.
270
+ */
271
+ exports.NAMING_GRAMMAR = [
272
+ 'Verbs: list, show, create, update, delete, archive, unarchive, move. A reversible state flip is its own verb, never a flag on its inverse.',
273
+ 'Scope: a list verb takes its parent scope as an optional filter flag; a verb that cannot work without a scope says so in its description.',
274
+ 'Output: every command in tasks, spaces and projects takes --json and has a description (audit errors).',
275
+ ];
216
276
  function isMachineRelevantCommand(id) {
217
277
  return !(id === 'login' ||
218
278
  id === 'logout' ||
@@ -1,4 +1,4 @@
1
- import { type DedicatedRuntimePowerSummary, type DedicatedPowerPolicy, type DedicatedRuntimePowerPolicyState, type OnDemandIneligibleError, type SetDedicatedRuntimePowerPolicyResponse } from '@skrr-ai/data-provider';
1
+ import { type DedicatedRuntimePowerSummary, type DedicatedRuntimeWaitingWork, type DedicatedPowerPolicy, type DedicatedRuntimePowerPolicyState, type OnDemandIneligibleError, type SetDedicatedRuntimePowerPolicyResponse } from '@skrr-ai/data-provider';
2
2
  import { type WhenOptions } from './format';
3
3
  import { type DedicatedRuntimeScope } from './dedicated-machines';
4
4
  /**
@@ -33,6 +33,16 @@ export declare function describePolicyWords(policy: DedicatedPowerPolicy, idleAf
33
33
  export declare function describePowerPolicy(power: DedicatedRuntimePowerPolicyState, autoStopMode?: 'off' | 'canary' | 'on'): string;
34
34
  /** `GET /api/machines/dedicated/:leaseId/power` — the read-only power card. */
35
35
  export declare function getDedicatedPowerSummary(leaseId: string, scope?: DedicatedRuntimeScope): Promise<DedicatedRuntimePowerSummary>;
36
+ /** `GET /api/machines/dedicated/:leaseId/power/waiting` — work waiting for this machine. */
37
+ export declare function getDedicatedWaitingWork(leaseId: string, scope?: DedicatedRuntimeScope): Promise<DedicatedRuntimeWaitingWork>;
38
+ /** The lines of `power waiting`. An unreadable source is said, never folded into "nothing waiting". */
39
+ export declare function describeWaitingWork(waiting: DedicatedRuntimeWaitingWork, when?: WhenOptions): string[];
40
+ /** Last wake timing. A wake that never became assignable shows the phases it reached and no latency. */
41
+ export declare function describeLastWakeTiming(wake: DedicatedRuntimePowerSummary['lastWake']): string[];
42
+ /** on_demand availability, so a plan does not need a failed `power set` to find out. */
43
+ export declare function describeOnDemandAvailability(onDemand: DedicatedRuntimePowerSummary['onDemand']): string[];
44
+ /** Pre-warm lines: only a PAUSED pre-warm is in the summary, so silence here is not "pre-warm is on". */
45
+ export declare function describePrewarm(prewarm: DedicatedRuntimePowerSummary['prewarm'], when?: WhenOptions): string[];
36
46
  type PowerDecisionView = NonNullable<DedicatedRuntimePowerSummary['decision']>;
37
47
  /** The stay/stop/wake decision in words: the shared reason copy backs the server's detail. */
38
48
  export declare function describePowerDecisionLines(decision: PowerDecisionView): {
@@ -53,6 +63,11 @@ export declare function describeLastAutoStopLines(last: DedicatedRuntimePowerSum
53
63
  };
54
64
  /** The latest wake decision and who asked, as lines; empty when there is none. */
55
65
  export declare function describeLastWakeDecisionLines(wake: DedicatedRuntimePowerSummary['lastWakeDecision'], when?: WhenOptions): string[];
66
+ /**
67
+ * The announced-but-not-yet-done stop, in the shared words (`describePendingStop`). Empty when the
68
+ * summary carries none, which is also what an older server sends: absent is not "no stop coming".
69
+ */
70
+ export declare function describePendingStopLines(summary: Pick<DedicatedRuntimePowerSummary, 'leaseId' | 'pendingStop'>, when?: WhenOptions): string[];
56
71
  /** The lines of `power show`. */
57
72
  export declare function describePowerSummary(summary: DedicatedRuntimePowerSummary, when?: WhenOptions): string[];
58
73
  /** The lines of `power explain`; the fix is always last. */