@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,227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describeApiFailure = describeApiFailure;
4
+ exports.isBatchRouteMissing = isBatchRouteMissing;
5
+ exports.chunkItems = chunkItems;
6
+ exports.batchIdempotencyKey = batchIdempotencyKey;
7
+ exports.createNodesViaBatch = createNodesViaBatch;
8
+ exports.patchTasksViaBatch = patchTasksViaBatch;
9
+ /**
10
+ * Domain lib for `POST|PATCH /api/tasks/batch` (docs/architecture/task-batch-api-2026-10-08.md).
11
+ *
12
+ * `tasks create-tree` and `tasks bulk-update` reach the batch routes through
13
+ * `dataService.createTasksBatch|updateTasksBatch` and nothing else. This file owns
14
+ * the parts a command should not restate: chunking at the server cap, a
15
+ * deterministic idempotency key per chunk, tempId translation, and the "this
16
+ * server has no batch route" signal that sends a command back to its serial path.
17
+ */
18
+ const node_crypto_1 = require("node:crypto");
19
+ const data_provider_1 = require("@skrr-ai/data-provider");
20
+ /** Normalize a thrown API error (or a per-item batch error) into one shape. */
21
+ function describeApiFailure(err) {
22
+ const e = err;
23
+ let code = e.code;
24
+ let message = e.message ?? String(err);
25
+ if (e.body) {
26
+ try {
27
+ const parsed = JSON.parse(e.body);
28
+ code = parsed.code ?? code;
29
+ message = parsed.message ?? parsed.error ?? message;
30
+ }
31
+ catch {
32
+ /* non-JSON body */
33
+ }
34
+ }
35
+ const status = e.status;
36
+ return {
37
+ message,
38
+ ...(status ? { status } : {}),
39
+ ...(code ? { code } : {}),
40
+ retryable: status === 408 || status === 425 || status === 429 || (status ?? 0) >= 500,
41
+ };
42
+ }
43
+ /**
44
+ * A server that predates the batch routes answers 404 (no such POST route) or
45
+ * 405. A processed batch is ALWAYS a 200 (or 400/413/429 with a code), so a
46
+ * bare 404/405 on the batch call itself means "route missing", never "task
47
+ * not found".
48
+ */
49
+ function isBatchRouteMissing(err) {
50
+ const status = err?.status;
51
+ return status === 404 || status === 405;
52
+ }
53
+ function chunkItems(items, size = data_provider_1.TASK_BATCH_MAX_ITEMS ?? 100) {
54
+ const out = [];
55
+ for (let i = 0; i < items.length; i += size)
56
+ out.push(items.slice(i, i + size));
57
+ return out;
58
+ }
59
+ /**
60
+ * Same chunk, same key: a retry of an interrupted command replays the stored
61
+ * result instead of creating twice. The key is a fingerprint of the items, so a
62
+ * DIFFERENT chunk can never collide with it (the server answers 422 on a key
63
+ * reused with a different body).
64
+ */
65
+ function batchIdempotencyKey(kind, items) {
66
+ const digest = (0, node_crypto_1.createHash)('sha256').update((0, data_provider_1.stableJson)(items)).digest('hex').slice(0, 40);
67
+ return `cli-${kind}-batch:${digest}`;
68
+ }
69
+ /**
70
+ * Create `nodes` (parents before children) in chunks. `mapping` holds key -> id
71
+ * for nodes that already exist and is extended in place. Stops after the first
72
+ * chunk that reports a failure, as the serial path stopped at its first failure.
73
+ */
74
+ async function createNodesViaBatch(nodes, mapping) {
75
+ const rows = [];
76
+ const failures = [];
77
+ for (const [chunkIndex, chunk] of chunkItems(nodes).entries()) {
78
+ const inChunk = new Map(chunk.map((node, i) => [node.key, `n${i}`]));
79
+ const items = [];
80
+ const sent = [];
81
+ for (const [i, node] of chunk.entries()) {
82
+ const { parentId: _ignored, ...payload } = node.payload;
83
+ const item = { ...payload, tempId: `n${i}` };
84
+ if (node.parentKey) {
85
+ const sameChunk = inChunk.get(node.parentKey);
86
+ if (sameChunk)
87
+ item.parentTempId = sameChunk;
88
+ else if (mapping[node.parentKey])
89
+ item.parentId = mapping[node.parentKey];
90
+ else {
91
+ failures.push({
92
+ key: node.key,
93
+ skipped: true,
94
+ error: {
95
+ message: `Parent "${node.parentKey}" was not created, so "${node.key}" was not attempted`,
96
+ code: 'BATCH_PARENT_NOT_CREATED',
97
+ retryable: false,
98
+ },
99
+ });
100
+ continue;
101
+ }
102
+ }
103
+ else if (node.payload.parentId) {
104
+ item.parentId = node.payload.parentId;
105
+ }
106
+ items.push(item);
107
+ sent.push(node);
108
+ }
109
+ if (items.length === 0)
110
+ break;
111
+ let response;
112
+ try {
113
+ response = await data_provider_1.dataService.createTasksBatch(items, {
114
+ idempotencyKey: batchIdempotencyKey('create', items),
115
+ });
116
+ }
117
+ catch (err) {
118
+ if (chunkIndex === 0 && isBatchRouteMissing(err))
119
+ return { supported: false };
120
+ failures.push({ key: sent[0].key, skipped: false, error: describeApiFailure(err) });
121
+ for (const node of sent.slice(1)) {
122
+ failures.push({
123
+ key: node.key,
124
+ skipped: true,
125
+ error: {
126
+ message: `Not attempted: the batch request containing "${sent[0].key}" failed`,
127
+ code: 'BATCH_NOT_ATTEMPTED',
128
+ retryable: true,
129
+ },
130
+ });
131
+ }
132
+ break;
133
+ }
134
+ let failed = false;
135
+ for (const [i, result] of response.results.entries()) {
136
+ const node = sent[i];
137
+ if (!node)
138
+ continue;
139
+ if (result.ok && result.id) {
140
+ mapping[node.key] = result.id;
141
+ rows.push({
142
+ key: node.key,
143
+ id: result.id,
144
+ ...(result.identifier ? { identifier: result.identifier } : {}),
145
+ status: result.status === 'exists' ? 'exists' : 'created',
146
+ ...(result.externalKey ? { externalKey: result.externalKey } : {}),
147
+ });
148
+ }
149
+ else {
150
+ failed = true;
151
+ failures.push({
152
+ key: node.key,
153
+ skipped: result.status === 'skipped',
154
+ error: result.error
155
+ ? {
156
+ message: result.error.message,
157
+ status: result.error.status,
158
+ code: result.error.code,
159
+ retryable: result.error.retryable,
160
+ }
161
+ : { message: 'Task was not created', retryable: false },
162
+ });
163
+ }
164
+ }
165
+ if (failed)
166
+ break;
167
+ }
168
+ return { supported: true, rows, failures };
169
+ }
170
+ /**
171
+ * Apply `updates` in chunks; `results[i]` answers `updates[i]`. A chunk the
172
+ * server never processed is reported `skipped` for every row rather than lost.
173
+ */
174
+ async function patchTasksViaBatch(updates) {
175
+ const results = [];
176
+ let aborted = null;
177
+ let offset = 0;
178
+ for (const [chunkIndex, chunk] of chunkItems(updates).entries()) {
179
+ if (aborted) {
180
+ for (const [i, update] of chunk.entries()) {
181
+ results.push({
182
+ index: offset + i,
183
+ id: update.id,
184
+ ok: false,
185
+ status: 'skipped',
186
+ error: {
187
+ status: aborted.status ?? 0,
188
+ code: 'BATCH_NOT_ATTEMPTED',
189
+ message: 'Not attempted: an earlier batch request failed',
190
+ retryable: true,
191
+ },
192
+ });
193
+ }
194
+ offset += chunk.length;
195
+ continue;
196
+ }
197
+ try {
198
+ const response = await data_provider_1.dataService.updateTasksBatch(chunk, {
199
+ idempotencyKey: batchIdempotencyKey('patch', chunk),
200
+ });
201
+ for (const [i, result] of response.results.entries()) {
202
+ results.push({ ...result, index: offset + i });
203
+ }
204
+ }
205
+ catch (err) {
206
+ if (chunkIndex === 0 && isBatchRouteMissing(err))
207
+ return { supported: false };
208
+ aborted = describeApiFailure(err);
209
+ for (const [i, update] of chunk.entries()) {
210
+ results.push({
211
+ index: offset + i,
212
+ id: update.id,
213
+ ok: false,
214
+ status: 'failed',
215
+ error: {
216
+ status: aborted.status ?? 0,
217
+ code: aborted.code ?? 'BATCH_REQUEST_FAILED',
218
+ message: aborted.message,
219
+ retryable: aborted.retryable,
220
+ },
221
+ });
222
+ }
223
+ }
224
+ offset += chunk.length;
225
+ }
226
+ return { supported: true, results };
227
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * A QR code a phone can scan off a terminal.
3
+ *
4
+ * The ENCODER is `qrcode-terminal`'s vendored QR model (the same zero-dependency
5
+ * package the daemon already ships for its login QR, pinned in the lockfile).
6
+ * Its own renderer is not used, because it is the part that decides whether a
7
+ * phone can read the result, and it gets two things wrong for that:
8
+ *
9
+ * - a ONE-module border. The QR spec asks for a four-module quiet zone, and a
10
+ * scanner looking at a terminal full of other text needs it most;
11
+ * - it paints light modules as `█` in the terminal's FOREGROUND colour, so on
12
+ * a light-themed terminal the code comes out inverted, which many scanners
13
+ * refuse.
14
+ *
15
+ * This renderer draws half-blocks (two modules per character row, so the code
16
+ * is square in a ~1:2 character cell) in EXPLICIT colours — black on bright
17
+ * white — so it scans the same on dark and light themes, with a full quiet zone.
18
+ *
19
+ * The QR is always a convenience printed beside the URL, never instead of it:
20
+ * `qrRenderDecision` says no for a pipe, `NO_COLOR`, `OVERSKY_NO_QR` / `SKRR_NO_QR`
21
+ * or a terminal too narrow to hold it, and the caller prints the URL alone.
22
+ */
23
+ /** The spec's quiet zone, in modules. */
24
+ export declare const QR_QUIET_ZONE = 4;
25
+ /**
26
+ * The module matrix for `text`, quiet zone included. Level M: a share URL is
27
+ * well under 100 bytes, so the extra damage tolerance costs nothing in size.
28
+ */
29
+ export declare function qrMatrix(text: string, level?: 'L' | 'M' | 'Q' | 'H'): boolean[][];
30
+ /**
31
+ * Render with half blocks: the upper half of each character is the top
32
+ * module (foreground, black), the lower half the bottom module (background,
33
+ * white). Returns the lines, each `matrix width` characters wide.
34
+ */
35
+ export declare function renderQr(text: string): string[];
36
+ /** The QR's width in terminal columns (one column per module). */
37
+ export declare function qrWidth(text: string): number;
38
+ export type QrRenderDecision = {
39
+ render: true;
40
+ } | {
41
+ render: false;
42
+ reason: string;
43
+ };
44
+ /**
45
+ * Whether a QR for `text` can be drawn on `stream`. Default-deny when the
46
+ * stream does not say it is a TTY, so captured output never carries block
47
+ * glyphs or escape codes.
48
+ */
49
+ export declare function qrRenderDecision(text: string, { env, stream, }?: {
50
+ env?: NodeJS.ProcessEnv;
51
+ stream?: {
52
+ isTTY?: boolean;
53
+ columns?: number;
54
+ };
55
+ }): QrRenderDecision;
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ /**
3
+ * A QR code a phone can scan off a terminal.
4
+ *
5
+ * The ENCODER is `qrcode-terminal`'s vendored QR model (the same zero-dependency
6
+ * package the daemon already ships for its login QR, pinned in the lockfile).
7
+ * Its own renderer is not used, because it is the part that decides whether a
8
+ * phone can read the result, and it gets two things wrong for that:
9
+ *
10
+ * - a ONE-module border. The QR spec asks for a four-module quiet zone, and a
11
+ * scanner looking at a terminal full of other text needs it most;
12
+ * - it paints light modules as `█` in the terminal's FOREGROUND colour, so on
13
+ * a light-themed terminal the code comes out inverted, which many scanners
14
+ * refuse.
15
+ *
16
+ * This renderer draws half-blocks (two modules per character row, so the code
17
+ * is square in a ~1:2 character cell) in EXPLICIT colours — black on bright
18
+ * white — so it scans the same on dark and light themes, with a full quiet zone.
19
+ *
20
+ * The QR is always a convenience printed beside the URL, never instead of it:
21
+ * `qrRenderDecision` says no for a pipe, `NO_COLOR`, `OVERSKY_NO_QR` / `SKRR_NO_QR`
22
+ * or a terminal too narrow to hold it, and the caller prints the URL alone.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.QR_QUIET_ZONE = void 0;
26
+ exports.qrMatrix = qrMatrix;
27
+ exports.renderQr = renderQr;
28
+ exports.qrWidth = qrWidth;
29
+ exports.qrRenderDecision = qrRenderDecision;
30
+ // The vendored model has no published types; this is its whole surface here.
31
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
32
+ const QRCodeModel = require('qrcode-terminal/vendor/QRCode');
33
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
34
+ const QRErrorCorrectLevel = require('qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel');
35
+ /** The spec's quiet zone, in modules. */
36
+ exports.QR_QUIET_ZONE = 4;
37
+ /**
38
+ * The module matrix for `text`, quiet zone included. Level M: a share URL is
39
+ * well under 100 bytes, so the extra damage tolerance costs nothing in size.
40
+ */
41
+ function qrMatrix(text, level = 'M') {
42
+ const qr = new QRCodeModel(-1, QRErrorCorrectLevel[level]);
43
+ qr.addData(text);
44
+ qr.make();
45
+ const count = qr.getModuleCount();
46
+ const size = count + exports.QR_QUIET_ZONE * 2;
47
+ const matrix = [];
48
+ for (let row = 0; row < size; row += 1) {
49
+ const line = [];
50
+ for (let col = 0; col < size; col += 1) {
51
+ const r = row - exports.QR_QUIET_ZONE;
52
+ const c = col - exports.QR_QUIET_ZONE;
53
+ line.push(r >= 0 && c >= 0 && r < count && c < count ? qr.isDark(r, c) : false);
54
+ }
55
+ matrix.push(line);
56
+ }
57
+ return matrix;
58
+ }
59
+ /** Indexed by (top dark ? 2 : 0) + (bottom dark ? 1 : 0). */
60
+ const HALF_BLOCK = [' ', '▄', '▀', '█'];
61
+ const DARK_ON_LIGHT = '\x1b[30;107m';
62
+ const RESET = '\x1b[0m';
63
+ /**
64
+ * Render with half blocks: the upper half of each character is the top
65
+ * module (foreground, black), the lower half the bottom module (background,
66
+ * white). Returns the lines, each `matrix width` characters wide.
67
+ */
68
+ function renderQr(text) {
69
+ const matrix = qrMatrix(text);
70
+ const size = matrix.length;
71
+ const lines = [];
72
+ for (let row = 0; row < size; row += 2) {
73
+ let line = '';
74
+ for (let col = 0; col < size; col += 1) {
75
+ const top = matrix[row][col];
76
+ const bottom = row + 1 < size ? matrix[row + 1][col] : false;
77
+ line += HALF_BLOCK[(top ? 2 : 0) + (bottom ? 1 : 0)];
78
+ }
79
+ lines.push(`${DARK_ON_LIGHT}${line}${RESET}`);
80
+ }
81
+ return lines;
82
+ }
83
+ /** The QR's width in terminal columns (one column per module). */
84
+ function qrWidth(text) {
85
+ return qrMatrix(text).length;
86
+ }
87
+ function truthy(value) {
88
+ if (typeof value !== 'string')
89
+ return false;
90
+ const v = value.trim().toLowerCase();
91
+ return v !== '' && v !== '0' && v !== 'false' && v !== 'no';
92
+ }
93
+ /**
94
+ * Whether a QR for `text` can be drawn on `stream`. Default-deny when the
95
+ * stream does not say it is a TTY, so captured output never carries block
96
+ * glyphs or escape codes.
97
+ */
98
+ function qrRenderDecision(text, { env = process.env, stream = process.stdout, } = {}) {
99
+ // https://no-color.org: present and non-empty disables colour. The QR IS
100
+ // colour (it is drawn in explicit black and white), so it goes too.
101
+ if (typeof env.NO_COLOR === 'string' && env.NO_COLOR !== '') {
102
+ return { render: false, reason: 'NO_COLOR is set' };
103
+ }
104
+ if (truthy(env.SKRR_NO_QR) || truthy(env.OVERSKY_NO_QR)) {
105
+ return { render: false, reason: 'QR codes are turned off (SKRR_NO_QR)' };
106
+ }
107
+ if (stream.isTTY !== true) {
108
+ return { render: false, reason: 'output is not a terminal' };
109
+ }
110
+ const columns = typeof stream.columns === 'number' ? stream.columns : 0;
111
+ const width = qrWidth(text);
112
+ if (columns > 0 && columns < width) {
113
+ return {
114
+ render: false,
115
+ reason: `the terminal is ${columns} columns wide and the code needs ${width}`,
116
+ };
117
+ }
118
+ return { render: true };
119
+ }
@@ -45,6 +45,9 @@ export type WebUrlRef = {
45
45
  } | {
46
46
  kind: 'agent';
47
47
  agentId: string;
48
+ } | {
49
+ kind: 'storeListing';
50
+ agentId: string;
48
51
  } | {
49
52
  kind: 'compass';
50
53
  agentId: string;
@@ -96,6 +99,14 @@ export type WebUrlRef = {
96
99
  export declare function webPath(ref: WebUrlRef): string | null;
97
100
  /** Absolute web URL (`<webOrigin><path>`), or `null` when the ref lacks its id. */
98
101
  export declare function webUrl(baseURL: string, ref: WebUrlRef): string | null;
102
+ /** The origin that serves the SPA for a configured baseURL (see `toWebOrigin`). */
103
+ export declare function webOrigin(baseURL: string): string;
104
+ /**
105
+ * Every origin that serves the skrr web app: the configured deployment's, each
106
+ * environment's from the one domain contract, and prod's retained previous
107
+ * origin. A URL on any other host is not a skrr page.
108
+ */
109
+ export declare function firstPartyWebOrigins(baseURL: string): string[];
99
110
  /** A persisted personalized Task View always opens as a focused modal on /tasks. */
100
111
  export declare function taskViewUrl(baseURL: string, viewId: string): string;
101
112
  type EntityRecord = Record<string, unknown>;
@@ -19,6 +19,8 @@
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
20
  exports.webPath = webPath;
21
21
  exports.webUrl = webUrl;
22
+ exports.webOrigin = webOrigin;
23
+ exports.firstPartyWebOrigins = firstPartyWebOrigins;
22
24
  exports.taskViewUrl = taskViewUrl;
23
25
  exports.taskUrlFrom = taskUrlFrom;
24
26
  exports.spaceUrlFrom = spaceUrlFrom;
@@ -42,6 +44,7 @@ exports.withNorthstarUrl = withNorthstarUrl;
42
44
  exports.withAgentUrl = withAgentUrl;
43
45
  exports.withDataUrls = withDataUrls;
44
46
  exports.workflowUrlFrom = workflowUrlFrom;
47
+ const data_provider_1 = require("@skrr-ai/data-provider");
45
48
  const publicEndpoints_generated_1 = require("./publicEndpoints.generated");
46
49
  /**
47
50
  * Site-relative canonical path for an entity, or `null` when the required id is
@@ -93,6 +96,10 @@ function webPath(ref) {
93
96
  const agentId = encodeId(ref.agentId);
94
97
  return agentId ? `/agent/${agentId}` : null;
95
98
  }
99
+ case 'storeListing': {
100
+ // The path comes from data-provider's one builder, never spelled here.
101
+ return ref.agentId ? (0, data_provider_1.publicAgentListingPath)(ref.agentId) : null;
102
+ }
96
103
  case 'compass': {
97
104
  const agentId = encodeId(ref.agentId);
98
105
  const compassId = encodeId(ref.compassId);
@@ -178,6 +185,23 @@ const WEB_ORIGIN_FROM_API = {
178
185
  // deliberately kept (LEGACY_PROD_BASE_URL), so its api. host must map too.
179
186
  'https://api.oversky.ai': 'https://oversky.ai',
180
187
  };
188
+ /** The origin that serves the SPA for a configured baseURL (see `toWebOrigin`). */
189
+ function webOrigin(baseURL) {
190
+ return toWebOrigin(baseURL);
191
+ }
192
+ /**
193
+ * Every origin that serves the skrr web app: the configured deployment's, each
194
+ * environment's from the one domain contract, and prod's retained previous
195
+ * origin. A URL on any other host is not a skrr page.
196
+ */
197
+ function firstPartyWebOrigins(baseURL) {
198
+ const origins = new Set([
199
+ toWebOrigin(baseURL).toLowerCase(),
200
+ ...Object.values(publicEndpoints_generated_1.OVERSKY_ENVIRONMENT_ENDPOINTS).map((e) => e.appUrl.toLowerCase()),
201
+ ...Object.values(WEB_ORIGIN_FROM_API).map((origin) => origin.toLowerCase()),
202
+ ]);
203
+ return [...origins].filter(Boolean);
204
+ }
181
205
  function toWebOrigin(baseURL) {
182
206
  const trimmed = trimTrailingSlash(baseURL);
183
207
  return WEB_ORIGIN_FROM_API[trimmed.toLowerCase()] ?? trimmed;
@@ -151,6 +151,14 @@ export declare const DAEMON_COMPUTER_EVENTS: {
151
151
  * `computer_declared_services_v1`.
152
152
  */
153
153
  readonly services: "daemon:computer:services";
154
+ /**
155
+ * Read the tail of the daemon's OWN process log (a bounded, redacted copy of
156
+ * what its logger wrote since it started), for the owner who asks why their
157
+ * machine reconnected. Carries a `requestId` and the principal the API
158
+ * authorized (`observe`); the daemon checks the principal against the grant
159
+ * set it holds. Needs `computer_daemon_log_v1`.
160
+ */
161
+ readonly daemonLog: "daemon:computer:log";
154
162
  /** The answer to any request that carried a `requestId`. */
155
163
  readonly ack: "daemon:computer:ack";
156
164
  readonly manifest: "daemon:computer:manifest";
@@ -295,6 +303,15 @@ export declare const COMPUTER_CAPABILITIES: {
295
303
  * browser; nothing is proxied to it. Announced by the relay that serves it.
296
304
  */
297
305
  readonly declaredServices: "computer_declared_services_v1";
306
+ /**
307
+ * The daemon serves the tail of its own process log
308
+ * (`daemon:computer:log`): an in-memory ring of lines its logger
309
+ * wrote, redacted before they enter the ring, read at the `watch` tier. It
310
+ * is NOT syslog or the journal and never reads either. Announced by the relay
311
+ * that serves it; a personal machine's daemon announces it too and refuses
312
+ * the read `consent_missing` until `skrr computer allow`.
313
+ */
314
+ readonly daemonLog: "computer_daemon_log_v1";
298
315
  /**
299
316
  * The page follows the controlling window (§6.2 "a stable viewport", §7.1,
300
317
  * OSK-13808): a browser `viewport` input, sent only by the attachment that
@@ -1080,3 +1097,54 @@ export declare function computerPowerPhaseForLeaseState(state: unknown): Compute
1080
1097
  export declare function computerShowsDesktop(phase: ComputerPowerPhase): boolean;
1081
1098
  /** Power actions are offered for a Dedicated Runtime only; a personal machine has none (§18). */
1082
1099
  export declare function computerOffersPowerActions(machineKind: ComputerMachineKind): boolean;
1100
+ /**
1101
+ * Why the daemon's log is a wire feature at all: the tenant uid on a Dedicated
1102
+ * Runtime guest cannot read syslog or the journal, so an owner could not see
1103
+ * why their machine's daemon reconnected or failed. The daemon keeps the last
1104
+ * lines its OWN logger wrote in memory and serves them; it opens no file and no
1105
+ * system log for this.
1106
+ */
1107
+ export declare const COMPUTER_DAEMON_LOG_LEVELS: readonly ["trace", "debug", "info", "warn", "error"];
1108
+ export type ComputerDaemonLogLevel = (typeof COMPUTER_DAEMON_LOG_LEVELS)[number];
1109
+ /** Every bound is the daemon's to enforce and the API's to validate against. */
1110
+ export declare const COMPUTER_DAEMON_LOG_LIMITS: {
1111
+ /** Lines the daemon keeps in memory; older ones fall off the front. */
1112
+ readonly ringLines: 2000;
1113
+ /** A line longer than this is cut and marked, never kept whole. */
1114
+ readonly lineChars: 1000;
1115
+ /** Lines returned when the caller names none. */
1116
+ readonly defaultLines: 100;
1117
+ /** The most lines one answer carries. */
1118
+ readonly maxLines: 500;
1119
+ /** The most bytes (UTF-8) one answer's text carries; far under the 1 MiB SSE frame. */
1120
+ readonly maxBytes: number;
1121
+ /** The longest look-back a `sinceMs` may ask for (24 h; the ring is shorter anyway). */
1122
+ readonly maxSinceMs: number;
1123
+ /** Requests the daemon answers per `rateWindowMs`; one more is `rate_limited`. */
1124
+ readonly rateMax: 30;
1125
+ readonly rateWindowMs: number;
1126
+ };
1127
+ /** One line of the daemon's log as it leaves the daemon: redacted, time and level split out. */
1128
+ export interface ComputerDaemonLogLine {
1129
+ /** Epoch milliseconds the daemon wrote it. */
1130
+ at: number;
1131
+ level: ComputerDaemonLogLevel;
1132
+ text: string;
1133
+ }
1134
+ /**
1135
+ * The answer to `daemon:computer:log`. `lines` are oldest first, at most
1136
+ * the asked number of the NEWEST that match. `truncated` is true when more
1137
+ * matched than were returned (by count or bytes); `ringFull` is true when the
1138
+ * ring has already dropped older lines, so "no line before this" does not mean
1139
+ * "the daemon logged nothing earlier". `startedAt` is the daemon process start:
1140
+ * a reconnect that restarted the daemon is visible as a new one.
1141
+ */
1142
+ export interface ComputerDaemonLogResult {
1143
+ lines: ComputerDaemonLogLine[];
1144
+ startedAt: number;
1145
+ now: number;
1146
+ truncated: boolean;
1147
+ ringFull: boolean;
1148
+ /** Lines the redaction rewrote anywhere in the ring (a count, never content). */
1149
+ redactedLines: number;
1150
+ }
@@ -27,7 +27,7 @@
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
28
  exports.COMPUTER_BROWSER_DIALOG_KINDS = exports.COMPUTER_INPUT_TEXT_MAX_LENGTH = exports.COMPUTER_BROWSER_INPUT_PLATFORMS = exports.COMPUTER_BROWSER_VIEWPORT_LIMITS = exports.COMPUTER_BROWSER_INPUT_TYPES = exports.COMPUTER_TERMINAL_CAVEATS = exports.COMPUTER_TERMINAL_HISTORY_CAUSES = exports.COMPUTER_TERMINAL_LIFETIMES = exports.COMPUTER_TERMINAL_INPUT_TYPES = exports.COMPUTER_TERMINAL_SIGNALS = exports.COMPUTER_DIAGNOSTICS_MAX_STREAMS = exports.COMPUTER_DIAGNOSTICS_INTERVAL_MS = exports.COMPUTER_DIAGNOSTIC_COUNTERS = exports.COMPUTER_FRAME_ACK_TIMEOUT_MS = exports.COMPUTER_FRAME_MAX_BYTES = exports.COMPUTER_BROWSER_VIEWPORT = exports.COMPUTER_SURFACE_END_REASONS = exports.COMPUTER_SURFACE_STATES = exports.COMPUTER_SURFACE_KINDS = exports.COMPUTER_CONTROL_ACTIVITY_CHANGES = exports.COMPUTER_CONTROL_CHANGE_REASONS = exports.COMPUTER_SURFACE_UNPIN_REASONS = exports.COMPUTER_SURFACE_PIN_ACTIONS = exports.COMPUTER_SHARE_MODES = exports.COMPUTER_SHARE_ACTIONS = exports.COMPUTER_CONTROL_ACTIONS = exports.COMPUTER_AGENT_WRITE_WAIT_MS = exports.COMPUTER_RECONNECT_GRACE_MS = exports.COMPUTER_RECLAIM_WARNING_MS = exports.COMPUTER_CONTROL_IDLE_MS = exports.COMPUTER_HANDBACK_NOTE_MAX_LENGTH = exports.COMPUTER_GRANT_TIERS = exports.COMPUTER_OPERATIONS = exports.COMPUTER_ACCESS_LEVELS = exports.COMPUTER_ACTOR_ENGINE_MAX_LENGTH = exports.COMPUTER_PLATFORM_ROUTE_SESSION_PREFIXES = exports.COMPUTER_ACTIVITY_ACTOR_KINDS = exports.COMPUTER_ACTOR_KINDS = exports.COMPUTER_REFUSAL_CODES = exports.COMPUTER_CAPABILITY_VALUES = exports.COMPUTER_CAPABILITIES = exports.COMPUTER_MANIFEST_REORDER_WAIT_MS = exports.COMPUTER_RESYNC_TIMEOUT_MS = exports.COMPUTER_API_ANSWERED_EVENT_KEYS = exports.COMPUTER_SERVER_EVENT_KEYS = exports.DAEMON_COMPUTER_REPORT_EVENT_KEYS = exports.DAEMON_COMPUTER_EVENT_NAMES = exports.COMPUTER_EVENT_NAMES = exports.DAEMON_COMPUTER_EVENTS = exports.COMPUTER_EVENTS = void 0;
29
29
  exports.COMPUTER_DECLARED_SERVICES_MAX = exports.COMPUTER_DECLARED_SERVICE_PROTOCOLS = exports.COMPUTER_SERVICES_TOOL_ERROR_PREFIX = exports.COMPUTER_SERVICES_TOOL_NAME = exports.COMPUTER_DECLARED_SERVICE_ACTIONS = exports.COMPUTER_COMMAND_OUTPUT_STREAMS = exports.COMPUTER_COMMAND_START_REFUSALS = exports.COMPUTER_COMMAND_UNKNOWN_END_SIGNAL = exports.COMPUTER_COMMAND_NOT_STARTED_SIGNAL = exports.COMPUTER_COMMAND_OUTCOMES = exports.COMPUTER_LIFECYCLE_EVENTS = exports.COMPUTER_COMMAND_PHASES = exports.COMPUTER_ACTIVITY_WITHHELD_PLACEHOLDER = exports.COMPUTER_ACTIVITY_OUTPUT_MAX_LENGTH = exports.COMPUTER_ACTIVITY_SUMMARY_MAX_LENGTH = exports.COMPUTER_ACTIVITY_KINDS = exports.COMPUTER_FILE_CONTENTS_TAG_PATTERN = exports.COMPUTER_FILE_CONTENTS_TAG_MAX_ENTRIES = exports.COMPUTER_FILE_CHANGES = exports.COMPUTER_FILES_CHANGED_MAX_CHANGES = exports.COMPUTER_FILES_WATCH_DEGRADED_REASONS = exports.COMPUTER_FILE_WITHHELD_REASONS = exports.COMPUTER_FILE_TYPES = exports.COMPUTER_FILE_GIT_STATUS_BUDGET_MS = exports.COMPUTER_FILE_SEARCH_MAX_QUERY_LENGTH = exports.COMPUTER_FILE_SEARCH_MAX_BUDGET_MS = exports.COMPUTER_FILE_SEARCH_DEFAULT_BUDGET_MS = exports.COMPUTER_FILE_SEARCH_MAX_LIMIT = exports.COMPUTER_FILE_SEARCH_DEFAULT_LIMIT = exports.COMPUTER_FILE_GIT_MARKS = exports.COMPUTER_FILE_SEARCH_STATES = exports.COMPUTER_FILE_SEARCH_OPERATIONS = exports.COMPUTER_FILE_OPERATIONS = exports.COMPUTER_BROWSER_URL_MAX_LENGTH = exports.COMPUTER_BROWSER_TAB_ACTIONS = exports.COMPUTER_BROWSER_HISTORY_ACTIONS = exports.COMPUTER_BROWSER_COPY_MAX_LENGTH = exports.COMPUTER_TERMINAL_CWD_MAX_LENGTH = exports.COMPUTER_BROWSER_FILE_CHOOSER_PATH_MAX_LENGTH = exports.COMPUTER_BROWSER_FILE_CHOOSER_ACCEPT_MAX_LENGTH = exports.COMPUTER_BROWSER_FILE_CHOOSER_MAX_FILES = exports.COMPUTER_BROWSER_FILE_CHOOSER_OUTCOMES = exports.COMPUTER_BROWSER_FILE_CHOOSER_MODES = exports.COMPUTER_BROWSER_DOWNLOADS_MAX = exports.COMPUTER_BROWSER_DOWNLOAD_STATES = exports.COMPUTER_BROWSER_DIALOG_CREDENTIAL_MAX_LENGTH = exports.COMPUTER_BROWSER_DIALOG_PROMPT_MAX_LENGTH = exports.COMPUTER_BROWSER_DIALOG_MESSAGE_MAX_LENGTH = exports.COMPUTER_BROWSER_DIALOG_ANSWERERS = exports.COMPUTER_BROWSER_DIALOG_OUTCOMES = void 0;
30
- exports.COMPUTER_LEASE_STATE_POWER_PHASE = exports.COMPUTER_START_REFUSALS = exports.COMPUTER_PERSONAL_SIGN_IN_REASONS = exports.COMPUTER_PERSONAL_POWER_PHASES = exports.COMPUTER_POWER_PHASES = exports.COMPUTER_MACHINE_KINDS = exports.COMPUTER_DECLARED_SERVICE_PROBLEMS = exports.COMPUTER_DECLARED_SERVICE_NAME_PATTERN = exports.COMPUTER_DECLARED_SERVICE_HOST = exports.COMPUTER_DECLARED_SERVICE_PATH_MAX_LENGTH = exports.COMPUTER_DECLARED_SERVICE_NAME_MAX_LENGTH = void 0;
30
+ exports.COMPUTER_DAEMON_LOG_LIMITS = exports.COMPUTER_DAEMON_LOG_LEVELS = exports.COMPUTER_LEASE_STATE_POWER_PHASE = exports.COMPUTER_START_REFUSALS = exports.COMPUTER_PERSONAL_SIGN_IN_REASONS = exports.COMPUTER_PERSONAL_POWER_PHASES = exports.COMPUTER_POWER_PHASES = exports.COMPUTER_MACHINE_KINDS = exports.COMPUTER_DECLARED_SERVICE_PROBLEMS = exports.COMPUTER_DECLARED_SERVICE_NAME_PATTERN = exports.COMPUTER_DECLARED_SERVICE_HOST = exports.COMPUTER_DECLARED_SERVICE_PATH_MAX_LENGTH = exports.COMPUTER_DECLARED_SERVICE_NAME_MAX_LENGTH = void 0;
31
31
  exports.normalizeComputerRefusalCode = normalizeComputerRefusalCode;
32
32
  exports.isComputerPlatformRouteSession = isComputerPlatformRouteSession;
33
33
  exports.computerTierOperations = computerTierOperations;
@@ -176,6 +176,14 @@ exports.DAEMON_COMPUTER_EVENTS = {
176
176
  * `computer_declared_services_v1`.
177
177
  */
178
178
  services: 'daemon:computer:services',
179
+ /**
180
+ * Read the tail of the daemon's OWN process log (a bounded, redacted copy of
181
+ * what its logger wrote since it started), for the owner who asks why their
182
+ * machine reconnected. Carries a `requestId` and the principal the API
183
+ * authorized (`observe`); the daemon checks the principal against the grant
184
+ * set it holds. Needs `computer_daemon_log_v1`.
185
+ */
186
+ daemonLog: 'daemon:computer:log',
179
187
  // daemon → API
180
188
  /** The answer to any request that carried a `requestId`. */
181
189
  ack: 'daemon:computer:ack',
@@ -336,6 +344,15 @@ exports.COMPUTER_CAPABILITIES = {
336
344
  * browser; nothing is proxied to it. Announced by the relay that serves it.
337
345
  */
338
346
  declaredServices: 'computer_declared_services_v1',
347
+ /**
348
+ * The daemon serves the tail of its own process log
349
+ * (`daemon:computer:log`): an in-memory ring of lines its logger
350
+ * wrote, redacted before they enter the ring, read at the `watch` tier. It
351
+ * is NOT syslog or the journal and never reads either. Announced by the relay
352
+ * that serves it; a personal machine's daemon announces it too and refuses
353
+ * the read `consent_missing` until `skrr computer allow`.
354
+ */
355
+ daemonLog: 'computer_daemon_log_v1',
339
356
  /**
340
357
  * The page follows the controlling window (§6.2 "a stable viewport", §7.1,
341
358
  * OSK-13808): a browser `viewport` input, sent only by the attachment that
@@ -1218,3 +1235,32 @@ function computerShowsDesktop(phase) {
1218
1235
  function computerOffersPowerActions(machineKind) {
1219
1236
  return machineKind === 'dedicated';
1220
1237
  }
1238
+ // ---------------------------------------------------------------------------
1239
+ // The daemon's own log (`computer_daemon_log_v1`)
1240
+ // ---------------------------------------------------------------------------
1241
+ /**
1242
+ * Why the daemon's log is a wire feature at all: the tenant uid on a Dedicated
1243
+ * Runtime guest cannot read syslog or the journal, so an owner could not see
1244
+ * why their machine's daemon reconnected or failed. The daemon keeps the last
1245
+ * lines its OWN logger wrote in memory and serves them; it opens no file and no
1246
+ * system log for this.
1247
+ */
1248
+ exports.COMPUTER_DAEMON_LOG_LEVELS = ['trace', 'debug', 'info', 'warn', 'error'];
1249
+ /** Every bound is the daemon's to enforce and the API's to validate against. */
1250
+ exports.COMPUTER_DAEMON_LOG_LIMITS = {
1251
+ /** Lines the daemon keeps in memory; older ones fall off the front. */
1252
+ ringLines: 2000,
1253
+ /** A line longer than this is cut and marked, never kept whole. */
1254
+ lineChars: 1000,
1255
+ /** Lines returned when the caller names none. */
1256
+ defaultLines: 100,
1257
+ /** The most lines one answer carries. */
1258
+ maxLines: 500,
1259
+ /** The most bytes (UTF-8) one answer's text carries; far under the 1 MiB SSE frame. */
1260
+ maxBytes: 192 * 1024,
1261
+ /** The longest look-back a `sinceMs` may ask for (24 h; the ring is shorter anyway). */
1262
+ maxSinceMs: 24 * 60 * 60 * 1000,
1263
+ /** Requests the daemon answers per `rateWindowMs`; one more is `rate_limited`. */
1264
+ rateMax: 30,
1265
+ rateWindowMs: 60 * 1000,
1266
+ };