@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
@@ -4,9 +4,15 @@ exports.setDedicatedPowerPolicy = setDedicatedPowerPolicy;
4
4
  exports.describePolicyWords = describePolicyWords;
5
5
  exports.describePowerPolicy = describePowerPolicy;
6
6
  exports.getDedicatedPowerSummary = getDedicatedPowerSummary;
7
+ exports.getDedicatedWaitingWork = getDedicatedWaitingWork;
8
+ exports.describeWaitingWork = describeWaitingWork;
9
+ exports.describeLastWakeTiming = describeLastWakeTiming;
10
+ exports.describeOnDemandAvailability = describeOnDemandAvailability;
11
+ exports.describePrewarm = describePrewarm;
7
12
  exports.describePowerDecisionLines = describePowerDecisionLines;
8
13
  exports.describeLastAutoStopLines = describeLastAutoStopLines;
9
14
  exports.describeLastWakeDecisionLines = describeLastWakeDecisionLines;
15
+ exports.describePendingStopLines = describePendingStopLines;
10
16
  exports.describePowerSummary = describePowerSummary;
11
17
  exports.describePowerExplanation = describePowerExplanation;
12
18
  exports.describeBudget = describeBudget;
@@ -45,7 +51,7 @@ async function setDedicatedPowerPolicy(leaseId, request, scope = {}) {
45
51
  return {
46
52
  ok: false,
47
53
  refusal: {
48
- error: String(body.error ?? 'on_demand is not available for this machine yet.'),
54
+ error: String(body.error ?? 'On demand is not available for this machine yet.'),
49
55
  code: 'ON_DEMAND_INELIGIBLE',
50
56
  reason: reason,
51
57
  detail: String(body.detail ?? copy?.detail ?? ''),
@@ -83,11 +89,126 @@ function describePowerPolicy(power, autoStopMode) {
83
89
  function getDedicatedPowerSummary(leaseId, scope = {}) {
84
90
  return (0, api_fetch_1.apiFetch)((0, dedicated_machines_1.withDedicatedScope)(`/api/machines/dedicated/${encodeURIComponent(leaseId)}/power`, scope));
85
91
  }
92
+ /** `GET /api/machines/dedicated/:leaseId/power/waiting` — work waiting for this machine. */
93
+ function getDedicatedWaitingWork(leaseId, scope = {}) {
94
+ return (0, api_fetch_1.apiFetch)((0, dedicated_machines_1.withDedicatedScope)(`/api/machines/dedicated/${encodeURIComponent(leaseId)}/power/waiting`, scope));
95
+ }
96
+ const WAITING_SOURCE_LABELS = {
97
+ dispatch_intent: 'just dispatched',
98
+ parked_fire: 'parked trigger fire',
99
+ parked_run: 'parked run',
100
+ queued_run: 'queued run',
101
+ agent_queued_run: 'queued run (agent)',
102
+ expected_firing: 'expected firing',
103
+ };
104
+ /** The lines of `power waiting`. An unreadable source is said, never folded into "nothing waiting". */
105
+ function describeWaitingWork(waiting, when = {}) {
106
+ const lines = [`Dedicated Runtime ${waiting.leaseId} (${waiting.state})`];
107
+ if (waiting.items.length === 0 && waiting.unreadable.length === 0) {
108
+ lines.push('Waiting work: none');
109
+ }
110
+ else {
111
+ lines.push(waiting.items.length === 0
112
+ ? 'Waiting work: none seen'
113
+ : `Waiting work: ${waiting.items.length} item${waiting.items.length === 1 ? '' : 's'}`);
114
+ for (const item of waiting.items) {
115
+ const label = WAITING_SOURCE_LABELS[item.source] ?? item.source;
116
+ lines.push(` - ${label} ${item.ref}${item.since ? ` · since ${(0, format_1.formatWhen)(item.since, when)}` : ''}`);
117
+ if (item.detail)
118
+ lines.push(` ${item.detail}`);
119
+ }
120
+ }
121
+ if (waiting.truncated.length > 0) {
122
+ lines.push(`More exists than is listed (${waiting.truncated.join(', ')}).`);
123
+ }
124
+ for (const u of waiting.unreadable) {
125
+ lines.push(`Cannot see ${u.source} (${u.reason}) — treat the list as incomplete.`);
126
+ }
127
+ const up = waiting.upcoming;
128
+ if (up) {
129
+ if (up.items.length > 0) {
130
+ lines.push(`Scheduled to fire: ${up.items.length}${up.truncated ? '+' : ''}`);
131
+ for (const f of up.items) {
132
+ lines.push(` - ${f.source} ${f.title ?? f.ref}${f.at ? ` · ${(0, format_1.formatWhen)(f.at, when)}` : ''}`);
133
+ }
134
+ }
135
+ else if (up.unreadable.length === 0) {
136
+ lines.push('Scheduled to fire: none');
137
+ }
138
+ else {
139
+ lines.push('Scheduled to fire: none seen');
140
+ }
141
+ if (up.overdue > 0) {
142
+ lines.push(`${up.overdue} overdue firing${up.overdue === 1 ? '' : 's'} not yet fired.`);
143
+ }
144
+ for (const u of up.unreadable) {
145
+ lines.push(`Cannot see ${u.source} (${u.reason}) — scheduled firings may be missing.`);
146
+ }
147
+ }
148
+ if (waiting.state === 'stopped' && waiting.items.length > 0) {
149
+ lines.push('The machine is stopped. `skrr machines dedicated start <lease> --wait` starts it; work on an on_demand machine wakes it by itself.');
150
+ }
151
+ return lines;
152
+ }
153
+ const PHASE_ORDER = [
154
+ 'start_requested',
155
+ 'provider_start_accepted',
156
+ 'instance_running',
157
+ 'daemon_connected',
158
+ 'first_heartbeat',
159
+ 'assignable',
160
+ ];
161
+ function formatMs(ms) {
162
+ return ms >= 1000 ? `${Math.round(ms / 100) / 10}s` : `${Math.round(ms)}ms`;
163
+ }
164
+ /** Last wake timing. A wake that never became assignable shows the phases it reached and no latency. */
165
+ function describeLastWakeTiming(wake) {
166
+ if (!wake)
167
+ return [];
168
+ const known = Object.keys(wake.phases ?? {});
169
+ const names = [
170
+ ...PHASE_ORDER.filter((p) => known.includes(p)),
171
+ ...known.filter((p) => !PHASE_ORDER.includes(p)),
172
+ ].filter((p) => p !== 'start_requested');
173
+ const phases = names.map((p) => `${p} +${formatMs(wake.phases[p])}`).join(', ');
174
+ const total = wake.latencyMs === null || wake.latencyMs === undefined
175
+ ? 'not ready yet (no latency recorded)'
176
+ : `ready after ${formatMs(wake.latencyMs)}`;
177
+ return [`Wake timing: ${total}${phases ? ` — ${phases}` : ''}`];
178
+ }
179
+ /** on_demand availability, so a plan does not need a failed `power set` to find out. */
180
+ function describeOnDemandAvailability(onDemand) {
181
+ if (!onDemand)
182
+ return [];
183
+ if (onDemand.eligible)
184
+ return ['on_demand: available'];
185
+ return [
186
+ `on_demand: not available (${onDemand.reason})`,
187
+ ` ${onDemand.detail}`,
188
+ ` Fix: ${onDemand.fix}`,
189
+ ];
190
+ }
191
+ /** Pre-warm lines: only a PAUSED pre-warm is in the summary, so silence here is not "pre-warm is on". */
192
+ function describePrewarm(prewarm, when = {}) {
193
+ if (!prewarm?.paused)
194
+ return [];
195
+ const lines = [
196
+ `Pre-warm: paused${prewarm.since ? ` since ${(0, format_1.formatWhen)(prewarm.since, when)}` : ''} (${prewarm.idleStreak} early start${prewarm.idleStreak === 1 ? '' : 's'} in a row went unused)`,
197
+ ];
198
+ if (prewarm.decision?.detail)
199
+ lines.push(` ${prewarm.decision.detail}`);
200
+ if (prewarm.decision?.fix)
201
+ lines.push(` ${prewarm.decision.fix}`);
202
+ return lines;
203
+ }
86
204
  /** The stay/stop/wake decision in words: the shared reason copy backs the server's detail. */
87
205
  function describePowerDecisionLines(decision) {
88
206
  const copy = (0, data_provider_1.describePowerReason)(decision.reason);
89
207
  const VERBS = { stay: 'Staying on', stop: 'Stopped', wake: 'Wake' };
90
- const verb = VERBS[decision.question] ?? decision.question;
208
+ // `stop_scheduled` answers the stop question for a machine that is still running.
209
+ const verb = decision.reason === 'stop_scheduled'
210
+ ? 'Scheduled to stop'
211
+ : (VERBS[decision.question] ?? decision.question);
91
212
  return {
92
213
  // The headline is the human label only; the reason token lives in `--json` and `power explain`.
93
214
  // With no shared copy and no server detail there is no sentence, so the token is the last resort.
@@ -158,6 +279,28 @@ function describeLastWakeDecisionLines(wake, when = {}) {
158
279
  lines.push(` ${wake.fix}`);
159
280
  return lines;
160
281
  }
282
+ /** What the Keep awake offered by the stop notice means in the CLI: two hours. */
283
+ const PENDING_STOP_KEEP_AWAKE_HOURS = 2;
284
+ /**
285
+ * The announced-but-not-yet-done stop, in the shared words (`describePendingStop`). Empty when the
286
+ * summary carries none, which is also what an older server sends: absent is not "no stop coming".
287
+ */
288
+ function describePendingStopLines(summary, when = {}) {
289
+ const pending = summary.pendingStop;
290
+ if (!pending)
291
+ return [];
292
+ const words = (0, data_provider_1.describePendingStop)(pending, {
293
+ nowMs: (when.now ?? new Date()).getTime(),
294
+ when: (0, format_1.formatWhen)(pending.stopsAt, when),
295
+ capWhen: pending.unreachableStopsAt ? (0, format_1.formatWhen)(pending.unreachableStopsAt, when) : null,
296
+ keepAwakeHours: PENDING_STOP_KEEP_AWAKE_HOURS,
297
+ });
298
+ const lines = [`Stop: ${words.headline}`];
299
+ if (words.detail)
300
+ lines.push(` ${words.detail}`);
301
+ lines.push(` ${words.fix} skrr machines dedicated power keep-awake ${summary.leaseId} --for ${PENDING_STOP_KEEP_AWAKE_HOURS}h`);
302
+ return lines;
303
+ }
161
304
  /** The lines of `power show`. */
162
305
  function describePowerSummary(summary, when = {}) {
163
306
  const { power } = summary;
@@ -186,6 +329,7 @@ function describePowerSummary(summary, when = {}) {
186
329
  lines.push('Decision: nothing to explain for this state');
187
330
  }
188
331
  }
332
+ lines.push(...describePendingStopLines(summary, when));
189
333
  lines.push(...describeLastAutoStopLines(summary.lastAutoStop, summary.decision?.detail, when).lines);
190
334
  lines.push(...describeLastWakeDecisionLines(summary.lastWakeDecision, when));
191
335
  if (summary.holders === null) {
@@ -205,6 +349,10 @@ function describePowerSummary(summary, when = {}) {
205
349
  lines.push(`Last wake: ${summary.lastWake
206
350
  ? `${summary.lastWake.at ? (0, format_1.formatWhen)(summary.lastWake.at, when) : 'unknown time'}${summary.lastWake.source ? ` (${summary.lastWake.source})` : ''}`
207
351
  : 'none'}`);
352
+ lines.push(...describeLastWakeTiming(summary.lastWake));
353
+ lines.push(...describePrewarm(summary.prewarm, when));
354
+ if (power.policy !== 'on_demand')
355
+ lines.push(...describeOnDemandAvailability(summary.onDemand));
208
356
  return lines;
209
357
  }
210
358
  /** The lines of `power explain`; the fix is always last. */
@@ -226,9 +374,12 @@ function describePowerExplanation(summary, when = {}) {
226
374
  lines.push(`At: ${(0, format_1.formatWhen)(d.at, when)}`);
227
375
  if (text.detail)
228
376
  lines.push(`Detail: ${text.detail}`);
377
+ lines.push(...describePendingStopLines(summary, when));
229
378
  const stop = describeLastAutoStopLines(summary.lastAutoStop, d.detail, when);
230
379
  lines.push(...stop.lines);
231
380
  lines.push(...wakeLines);
381
+ lines.push(...describeLastWakeTiming(summary.lastWake));
382
+ lines.push(...describePrewarm(summary.prewarm, when));
232
383
  // A false stop's fix replaces nothing: the decision's own fix is still last-but-one.
233
384
  if (text.fix && text.fix !== stop.fix)
234
385
  lines.push(`Fix: ${text.fix}`);
@@ -0,0 +1,50 @@
1
+ type Row = Record<string, unknown>;
2
+ export type ProjectAction = 'archive' | 'unarchive' | 'delete';
3
+ export declare function planProjectChange(action: ProjectAction, project: Row, projectRef: string): {
4
+ object: string;
5
+ source: string;
6
+ ok: boolean;
7
+ action: ProjectAction;
8
+ project: {
9
+ id: unknown;
10
+ ref: {};
11
+ title: unknown;
12
+ archived: boolean;
13
+ };
14
+ changes: {
15
+ deletesProject: boolean;
16
+ detachedTasksEstimate: number | null;
17
+ reversible: boolean;
18
+ archived?: undefined;
19
+ } | {
20
+ archived: boolean;
21
+ reversible: boolean;
22
+ deletesProject?: undefined;
23
+ detachedTasksEstimate?: undefined;
24
+ };
25
+ errors: string[];
26
+ notes: string[];
27
+ };
28
+ export type BulkUpdateInput = {
29
+ id: string;
30
+ patch: Row;
31
+ };
32
+ export declare function planBulkUpdate(updates: BulkUpdateInput[], currentById: Record<string, Row | null | undefined>, failedReads?: Record<string, string>): {
33
+ object: string;
34
+ source: string;
35
+ ok: boolean;
36
+ requested: number;
37
+ wouldChange: number;
38
+ invalid: number;
39
+ results: {
40
+ id: string;
41
+ ok: boolean;
42
+ changes: Record<string, {
43
+ from: unknown;
44
+ to: unknown;
45
+ }>;
46
+ noop: boolean;
47
+ errors: string[];
48
+ }[];
49
+ };
50
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.planProjectChange = planProjectChange;
4
+ exports.planBulkUpdate = planBulkUpdate;
5
+ /**
6
+ * Client-side validated previews for `--dry-run` (audit P5).
7
+ *
8
+ * Each plan is built from READS only (a GET of the current row) and answers three
9
+ * things a caller needs before a destructive call: would it be accepted, what
10
+ * would change, and what is the blast radius. It is a preview, not a promise:
11
+ * the real call re-validates server-side, and a concurrent writer can still
12
+ * change the outcome. Where the server has no validate-only path the plan says
13
+ * `source: 'client_preview'` so nobody mistakes it for one.
14
+ */
15
+ const data_provider_1 = require("@skrr-ai/data-provider");
16
+ function planProjectChange(action, project, projectRef) {
17
+ const archived = Boolean(project.archivedAt);
18
+ const taskCounts = (project.taskCounts ?? {});
19
+ const errors = [];
20
+ const notes = [];
21
+ if (action === 'archive' && archived)
22
+ notes.push('Already archived; archiving again is a no-op.');
23
+ if (action === 'unarchive' && !archived)
24
+ notes.push('Not archived; unarchiving is a no-op.');
25
+ return {
26
+ object: 'project_change_dry_run',
27
+ source: 'client_preview',
28
+ ok: errors.length === 0,
29
+ action,
30
+ project: {
31
+ id: project.id,
32
+ ref: project.identifier ?? projectRef,
33
+ title: project.title,
34
+ archived,
35
+ },
36
+ changes: action === 'delete'
37
+ ? {
38
+ deletesProject: true,
39
+ // Member tasks are detached, never deleted (invariant P3).
40
+ detachedTasksEstimate: taskCounts.total ?? null,
41
+ reversible: false,
42
+ }
43
+ : { archived: action === 'archive', reversible: true },
44
+ errors,
45
+ notes,
46
+ };
47
+ }
48
+ function planBulkUpdate(updates, currentById, failedReads = {}) {
49
+ const rows = updates.map(({ id, patch }) => {
50
+ const errors = [];
51
+ const current = currentById[id];
52
+ if (failedReads[id])
53
+ errors.push(`could not read task: ${failedReads[id]}`);
54
+ else if (!current)
55
+ errors.push('task not found');
56
+ const status = patch.status;
57
+ if (status !== undefined && !data_provider_1.TASK_STATUSES.includes(status)) {
58
+ errors.push(`status must be one of: ${data_provider_1.TASK_STATUSES.join(', ')}`);
59
+ }
60
+ const changes = {};
61
+ for (const [field, to] of Object.entries(patch)) {
62
+ if (to === undefined)
63
+ continue;
64
+ const from = current?.[field];
65
+ if (JSON.stringify(from) !== JSON.stringify(to))
66
+ changes[field] = { from, to };
67
+ }
68
+ return {
69
+ id,
70
+ ok: errors.length === 0,
71
+ changes,
72
+ noop: errors.length === 0 && Object.keys(changes).length === 0,
73
+ errors,
74
+ };
75
+ });
76
+ return {
77
+ object: 'task_bulk_update_dry_run',
78
+ source: 'client_preview',
79
+ ok: rows.every((r) => r.ok),
80
+ requested: rows.length,
81
+ wouldChange: rows.filter((r) => r.ok && !r.noop).length,
82
+ invalid: rows.filter((r) => !r.ok).length,
83
+ results: rows,
84
+ };
85
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Storage-field stripping for `--json` output (audit P9).
3
+ *
4
+ * The API returns Mongo documents, so every row carries `_id` and `__v` beside
5
+ * the real `id`: 47 keys per task row, two of which are storage detail an agent
6
+ * pays tokens for and can mistake for the identifier (OSK-12205 was exactly
7
+ * that: a 24-hex `_id` passed where a task id was wanted).
8
+ *
9
+ * This runs at the CLI SERIALIZER only (`BaseCommand.log`), never in the API or
10
+ * the data layer, so no other consumer's payload changes. `--raw` (or
11
+ * `OVERSKY_CLI_RAW=1`) turns it off for the caller that does want them.
12
+ *
13
+ * Two rules, both conservative:
14
+ * - `__v` is the Mongoose version key and is always dropped.
15
+ * - `_id` is dropped only when the same object has a usable `id`. A row that
16
+ * has ONLY `_id` (some legacy collections) keeps it: removing the sole
17
+ * identifier would turn a cosmetic cleanup into data loss.
18
+ */
19
+ type Json = unknown;
20
+ /**
21
+ * Returns the SAME reference when nothing needed stripping, so a caller can tell
22
+ * "unchanged" apart from "rebuilt" and leave the original text alone.
23
+ */
24
+ export declare function stripStorageFields(value: Json): Json;
25
+ /**
26
+ * Apply {@link stripStorageFields} to one line of CLI output. Anything that is
27
+ * not a JSON object/array (prose, a bare string, malformed text) is returned
28
+ * untouched, as is JSON with nothing to strip, so existing formatting survives.
29
+ */
30
+ export declare function stripStorageFieldsFromText(text: string): string;
31
+ export {};
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * Storage-field stripping for `--json` output (audit P9).
4
+ *
5
+ * The API returns Mongo documents, so every row carries `_id` and `__v` beside
6
+ * the real `id`: 47 keys per task row, two of which are storage detail an agent
7
+ * pays tokens for and can mistake for the identifier (OSK-12205 was exactly
8
+ * that: a 24-hex `_id` passed where a task id was wanted).
9
+ *
10
+ * This runs at the CLI SERIALIZER only (`BaseCommand.log`), never in the API or
11
+ * the data layer, so no other consumer's payload changes. `--raw` (or
12
+ * `OVERSKY_CLI_RAW=1`) turns it off for the caller that does want them.
13
+ *
14
+ * Two rules, both conservative:
15
+ * - `__v` is the Mongoose version key and is always dropped.
16
+ * - `_id` is dropped only when the same object has a usable `id`. A row that
17
+ * has ONLY `_id` (some legacy collections) keeps it: removing the sole
18
+ * identifier would turn a cosmetic cleanup into data loss.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.stripStorageFields = stripStorageFields;
22
+ exports.stripStorageFieldsFromText = stripStorageFieldsFromText;
23
+ function usableId(value) {
24
+ return (typeof value === 'string' && value.length > 0) || typeof value === 'number';
25
+ }
26
+ /**
27
+ * Returns the SAME reference when nothing needed stripping, so a caller can tell
28
+ * "unchanged" apart from "rebuilt" and leave the original text alone.
29
+ */
30
+ function stripStorageFields(value) {
31
+ if (Array.isArray(value)) {
32
+ let changed = false;
33
+ const next = value.map((item) => {
34
+ const stripped = stripStorageFields(item);
35
+ if (stripped !== item)
36
+ changed = true;
37
+ return stripped;
38
+ });
39
+ return changed ? next : value;
40
+ }
41
+ if (value === null || typeof value !== 'object')
42
+ return value;
43
+ const source = value;
44
+ const dropId = '_id' in source && usableId(source.id);
45
+ const dropVersion = '__v' in source;
46
+ let changed = dropId || dropVersion;
47
+ const next = {};
48
+ for (const [key, child] of Object.entries(source)) {
49
+ if ((key === '_id' && dropId) || (key === '__v' && dropVersion))
50
+ continue;
51
+ const stripped = stripStorageFields(child);
52
+ if (stripped !== child)
53
+ changed = true;
54
+ next[key] = stripped;
55
+ }
56
+ return changed ? next : value;
57
+ }
58
+ /**
59
+ * Apply {@link stripStorageFields} to one line of CLI output. Anything that is
60
+ * not a JSON object/array (prose, a bare string, malformed text) is returned
61
+ * untouched, as is JSON with nothing to strip, so existing formatting survives.
62
+ */
63
+ function stripStorageFieldsFromText(text) {
64
+ const head = text.trimStart()[0];
65
+ if (head !== '{' && head !== '[')
66
+ return text;
67
+ let parsed;
68
+ try {
69
+ parsed = JSON.parse(text);
70
+ }
71
+ catch {
72
+ return text;
73
+ }
74
+ const stripped = stripStorageFields(parsed);
75
+ if (stripped === parsed)
76
+ return text;
77
+ return JSON.stringify(stripped, null, text.includes('\n') ? 2 : undefined);
78
+ }
@@ -0,0 +1,75 @@
1
+ export type ListWarning = {
2
+ code: string;
3
+ value?: unknown;
4
+ hint: string;
5
+ };
6
+ export type ListEnvelope = {
7
+ object: 'list';
8
+ data: Array<Record<string, unknown>>;
9
+ has_more: boolean;
10
+ next_cursor: string | null;
11
+ limit_applied?: number;
12
+ warnings?: ListWarning[];
13
+ } & Record<string, unknown>;
14
+ /**
15
+ * The navigation projection per resource: enough to identify a row, decide
16
+ * whether it matters and fetch it with `show`. Allowlists, not drop-lists, so a
17
+ * field the server adds tomorrow does not silently re-inflate every compact row.
18
+ * Documented in docs/cli/SKRR_TASKS.md (List output for agents).
19
+ */
20
+ export declare const COMPACT_FIELDS: {
21
+ readonly task: readonly ["id", "identifier", "ref", "title", "status", "statusType", "priority", "estimate", "assigneeAgentIds", "assigneeUserIds", "parentId", "spaceId", "projectId", "goalId", "dueDate", "scheduledFor", "labelIds", "tags", "externalKey", "version", "executionMode", "nextAction", "createdAt", "updatedAt", "url"];
22
+ readonly space: readonly ["id", "identifier", "title", "status", "parentSpaceId", "leadAgentId", "labelIds", "archivedAt", "createdAt", "updatedAt", "url"];
23
+ readonly project: readonly ["id", "identifier", "title", "spaceId", "externalKey", "taskCounts", "archivedAt", "createdAt", "updatedAt", "url"];
24
+ };
25
+ export type ListResource = keyof typeof COMPACT_FIELDS;
26
+ /** The three flags every projecting list command declares. */
27
+ export declare const listOutputFlags: {
28
+ fields: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
29
+ compact: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
30
+ ndjson: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
31
+ };
32
+ export type ListOutputFlags = {
33
+ fields?: string;
34
+ compact?: boolean;
35
+ ndjson?: boolean;
36
+ };
37
+ /** `--fields a, b ,c` -> ['a','b','c']; empty/blank -> undefined. */
38
+ export declare function parseFields(raw: string | undefined): string[] | undefined;
39
+ export declare function projectRow(row: Record<string, unknown>, fields: readonly string[]): Record<string, unknown>;
40
+ /**
41
+ * Normalize any list response to the shared envelope. `data` is where rows live
42
+ * for every list command; `projects` (an older serialization) is folded into it.
43
+ * A response that is not list-shaped is returned untouched (never invent rows).
44
+ */
45
+ export declare function toListEnvelope(response: unknown): ListEnvelope | undefined;
46
+ export type ShapeListOptions = ListOutputFlags & {
47
+ resource: ListResource;
48
+ /** What the caller asked for with --limit (undefined when the command has none). */
49
+ requestedLimit?: number;
50
+ warnings?: ListWarning[];
51
+ /** A filter the CLI applied that the caller did not ask for (E12). Echoed as `filter_applied`. */
52
+ filterApplied?: Record<string, unknown>;
53
+ };
54
+ /** Pure: envelope + projection + notes. Returns the response untouched if not a list. */
55
+ export declare function shapeListResponse(response: unknown, options: ShapeListOptions): unknown;
56
+ /**
57
+ * E11: the server silently clamps `--limit` (cap) and coerces `0` to its default.
58
+ * Echo what was applied. `applied` is only reported when we can prove it: a full
59
+ * page that still has more rows means the cap is exactly the row count.
60
+ */
61
+ export declare function limitNote(requested: number | undefined, rowCount: number, hasMore: boolean): {
62
+ applied?: number;
63
+ warning?: ListWarning;
64
+ };
65
+ /** The text-mode twin of a warning: one `Note:` line a person can act on. */
66
+ export declare function warningLines(warnings: readonly ListWarning[] | undefined): string[];
67
+ export type ListOutput = {
68
+ stdout: string[];
69
+ stderr: string[];
70
+ };
71
+ /**
72
+ * Render a shaped list for `--json` (pretty envelope) or `--ndjson` (rows one per
73
+ * line, `_meta` on stderr). Pure; the caller writes the lines.
74
+ */
75
+ export declare function renderListOutput(shaped: unknown, ndjson: boolean): ListOutput;