@skrr-ai/cli 0.1.119 → 0.1.120

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 (276) hide show
  1. package/dist/base-command.d.ts +31 -0
  2. package/dist/base-command.js +106 -4
  3. package/dist/commands/commands.js +11 -0
  4. package/dist/commands/commitments/action-proposal.d.ts +13 -0
  5. package/dist/commands/commitments/action-proposal.js +39 -0
  6. package/dist/commands/commitments/action-proposals/decide.js +8 -1
  7. package/dist/commands/commitments/action-proposals/execute.js +11 -1
  8. package/dist/commands/commitments/create.js +2 -2
  9. package/dist/commands/commitments/doctor.d.ts +8 -0
  10. package/dist/commands/commitments/doctor.js +22 -0
  11. package/dist/commands/commitments/execute-remediation.js +12 -1
  12. package/dist/commands/commitments/observations.js +2 -2
  13. package/dist/commands/commitments/pack/bind.d.ts +18 -1
  14. package/dist/commands/commitments/pack/bind.js +66 -8
  15. package/dist/commands/commitments/pack/plan.d.ts +4 -1
  16. package/dist/commands/commitments/pack/plan.js +30 -2
  17. package/dist/commands/commitments/update.js +8 -2
  18. package/dist/commands/completion/index.js +1 -1
  19. package/dist/commands/completion/values.js +1 -1
  20. package/dist/commands/computer-use/audio.d.ts +1 -0
  21. package/dist/commands/computer-use/audio.js +1 -0
  22. package/dist/commands/computer-use/browser.d.ts +1 -0
  23. package/dist/commands/computer-use/browser.js +1 -0
  24. package/dist/commands/computer-use/disable.d.ts +1 -0
  25. package/dist/commands/computer-use/disable.js +1 -0
  26. package/dist/commands/computer-use/enable.d.ts +1 -0
  27. package/dist/commands/computer-use/enable.js +1 -0
  28. package/dist/commands/computer-use/index.d.ts +1 -0
  29. package/dist/commands/computer-use/index.js +1 -0
  30. package/dist/commands/computer-use/install.d.ts +1 -0
  31. package/dist/commands/computer-use/install.js +1 -0
  32. package/dist/commands/computer-use/recover.d.ts +1 -0
  33. package/dist/commands/computer-use/recover.js +1 -0
  34. package/dist/commands/computer-use/status.d.ts +1 -0
  35. package/dist/commands/computer-use/status.js +1 -0
  36. package/dist/commands/computer-use/stop.d.ts +1 -0
  37. package/dist/commands/computer-use/stop.js +1 -0
  38. package/dist/commands/context.js +16 -11
  39. package/dist/commands/convos/recovery.js +1 -1
  40. package/dist/commands/daemon/diagnostics.d.ts +9 -0
  41. package/dist/commands/daemon/diagnostics.js +53 -0
  42. package/dist/commands/daemon/index.js +2 -0
  43. package/dist/commands/daemon/maintenance/attest.d.ts +15 -0
  44. package/dist/commands/daemon/maintenance/attest.js +52 -0
  45. package/dist/commands/daemon/maintenance/hold.d.ts +17 -0
  46. package/dist/commands/daemon/maintenance/hold.js +70 -0
  47. package/dist/commands/daemon/maintenance/index.d.ts +12 -0
  48. package/dist/commands/daemon/maintenance/index.js +30 -0
  49. package/dist/commands/daemon/maintenance/resume.d.ts +13 -0
  50. package/dist/commands/daemon/maintenance/resume.js +36 -0
  51. package/dist/commands/daemon/maintenance/status.d.ts +13 -0
  52. package/dist/commands/daemon/maintenance/status.js +36 -0
  53. package/dist/commands/doctor.d.ts +4 -1
  54. package/dist/commands/doctor.js +50 -6
  55. package/dist/commands/followups/plans/cancel-batch.js +6 -3
  56. package/dist/commands/followups/plans/capacity.js +7 -3
  57. package/dist/commands/followups/plans/observability.js +11 -3
  58. package/dist/commands/followups/plans/preferences/set.js +26 -8
  59. package/dist/commands/followups/plans/preferences.js +1 -1
  60. package/dist/commands/followups/plans/show.js +1 -1
  61. package/dist/commands/goals/key-results/assess.d.ts +36 -0
  62. package/dist/commands/goals/key-results/assess.js +110 -0
  63. package/dist/commands/goals/key-results/history.d.ts +30 -0
  64. package/dist/commands/goals/key-results/history.js +104 -0
  65. package/dist/commands/goals/key-results/list.d.ts +5 -4
  66. package/dist/commands/goals/key-results/list.js +12 -6
  67. package/dist/commands/goals/key-results/show.d.ts +4 -2
  68. package/dist/commands/goals/key-results/show.js +25 -4
  69. package/dist/commands/goals/key-results/update.d.ts +4 -0
  70. package/dist/commands/goals/key-results/update.js +18 -24
  71. package/dist/commands/goals/plan-now.js +12 -1
  72. package/dist/commands/goals/planner-compare.d.ts +30 -0
  73. package/dist/commands/goals/planner-compare.js +136 -0
  74. package/dist/commands/machines/dedicated/service/exec.d.ts +3 -0
  75. package/dist/commands/machines/dedicated/service/exec.js +70 -11
  76. package/dist/commands/machines/hosted/destroy.d.ts +1 -0
  77. package/dist/commands/machines/hosted/destroy.js +11 -1
  78. package/dist/commands/machines/hosted/exec.d.ts +1 -0
  79. package/dist/commands/machines/hosted/exec.js +12 -1
  80. package/dist/commands/machines/hosted/index.js +1 -0
  81. package/dist/commands/machines/hosted/operation.d.ts +14 -0
  82. package/dist/commands/machines/hosted/operation.js +51 -0
  83. package/dist/commands/machines/hosted/pull.js +1 -1
  84. package/dist/commands/machines/hosted/start.js +6 -2
  85. package/dist/commands/spaces/auto-executor/compare.d.ts +18 -0
  86. package/dist/commands/spaces/auto-executor/compare.js +139 -0
  87. package/dist/commands/spaces/auto-executor/runs.d.ts +3 -0
  88. package/dist/commands/spaces/auto-executor/runs.js +13 -1
  89. package/dist/commands/spaces/charter/create-from-description.d.ts +21 -0
  90. package/dist/commands/spaces/charter/create-from-description.js +77 -0
  91. package/dist/commands/spaces/charter/show.d.ts +22 -0
  92. package/dist/commands/spaces/charter/show.js +61 -0
  93. package/dist/commands/spaces/heartbeats/list.d.ts +1 -16
  94. package/dist/commands/spaces/heartbeats/list.js +13 -0
  95. package/dist/commands/spaces/install-template.js +3 -0
  96. package/dist/commands/spaces/loops/migrate.d.ts +32 -0
  97. package/dist/commands/spaces/loops/migrate.js +103 -0
  98. package/dist/commands/spaces/loops/release.d.ts +14 -0
  99. package/dist/commands/spaces/loops/release.js +59 -0
  100. package/dist/commands/spaces/notebook.d.ts +25 -0
  101. package/dist/commands/spaces/notebook.js +75 -0
  102. package/dist/commands/spaces/proposals/discard.d.ts +17 -0
  103. package/dist/commands/spaces/proposals/discard.js +17 -0
  104. package/dist/commands/spaces/proposals/keep.d.ts +17 -0
  105. package/dist/commands/spaces/proposals/keep.js +17 -0
  106. package/dist/commands/spaces/proposals/list.d.ts +24 -0
  107. package/dist/commands/spaces/proposals/list.js +89 -0
  108. package/dist/commands/spaces/skills/propose.d.ts +29 -0
  109. package/dist/commands/spaces/skills/propose.js +82 -0
  110. package/dist/commands/spaces/templates/fork.js +3 -0
  111. package/dist/commands/spaces/triggers/show.js +6 -0
  112. package/dist/commands/spaces/workflows/retry.d.ts +1 -0
  113. package/dist/commands/spaces/workflows/retry.js +8 -1
  114. package/dist/commands/spaces/workflows/triggers/create.js +3 -2
  115. package/dist/commands/spaces/workflows/triggers/fire.js +4 -0
  116. package/dist/commands/spaces/workflows/triggers/update.js +2 -1
  117. package/dist/commands/spaces/write-policy/set.d.ts +22 -0
  118. package/dist/commands/spaces/write-policy/set.js +82 -0
  119. package/dist/commands/spaces/write-policy/show.d.ts +19 -0
  120. package/dist/commands/spaces/write-policy/show.js +49 -0
  121. package/dist/commands/store/artifacts/receipt.d.ts +14 -0
  122. package/dist/commands/store/artifacts/receipt.js +34 -0
  123. package/dist/commands/store/artifacts/release.d.ts +2 -0
  124. package/dist/commands/store/artifacts/release.js +11 -0
  125. package/dist/commands/store/governance/publish-release.d.ts +2 -0
  126. package/dist/commands/store/governance/publish-release.js +30 -1
  127. package/dist/commands/store/governance/release-receipt.d.ts +12 -0
  128. package/dist/commands/store/governance/release-receipt.js +32 -0
  129. package/dist/commands/tasks/approvals/list.d.ts +11 -5
  130. package/dist/commands/tasks/approvals/list.js +13 -6
  131. package/dist/commands/tasks/attachments/facts.d.ts +12 -0
  132. package/dist/commands/tasks/attachments/facts.js +29 -0
  133. package/dist/commands/tasks/attachments/upload.d.ts +1 -0
  134. package/dist/commands/tasks/attachments/upload.js +16 -0
  135. package/dist/commands/tasks/bulk-update.js +35 -1
  136. package/dist/commands/tasks/context.d.ts +15 -0
  137. package/dist/commands/tasks/context.js +69 -0
  138. package/dist/commands/tasks/copy.d.ts +18 -0
  139. package/dist/commands/tasks/copy.js +85 -0
  140. package/dist/commands/tasks/create-tree.js +97 -23
  141. package/dist/commands/tasks/create.js +9 -1
  142. package/dist/commands/tasks/deliverable/add.js +20 -10
  143. package/dist/commands/tasks/move.js +8 -1
  144. package/dist/commands/tasks/operations/show.d.ts +16 -0
  145. package/dist/commands/tasks/operations/show.js +98 -0
  146. package/dist/commands/tasks/operations/wait.d.ts +22 -0
  147. package/dist/commands/tasks/operations/wait.js +114 -0
  148. package/dist/commands/tasks/preflight.d.ts +1 -0
  149. package/dist/commands/tasks/preflight.js +11 -1
  150. package/dist/commands/tasks/rearm-recurrence.js +4 -0
  151. package/dist/commands/tasks/result/show.js +22 -0
  152. package/dist/commands/tasks/result/submit.d.ts +1 -0
  153. package/dist/commands/tasks/result/submit.js +3 -0
  154. package/dist/commands/tasks/retry-receipt.d.ts +15 -0
  155. package/dist/commands/tasks/retry-receipt.js +89 -0
  156. package/dist/commands/tasks/retry-review.d.ts +16 -0
  157. package/dist/commands/tasks/retry-review.js +66 -0
  158. package/dist/commands/tasks/retry.d.ts +4 -8
  159. package/dist/commands/tasks/retry.js +34 -68
  160. package/dist/commands/tasks/runs.d.ts +21 -0
  161. package/dist/commands/tasks/runs.js +95 -0
  162. package/dist/commands/tasks/show.d.ts +2 -0
  163. package/dist/commands/tasks/show.js +15 -1
  164. package/dist/commands/tasks/start-receipt.d.ts +15 -0
  165. package/dist/commands/tasks/start-receipt.js +95 -0
  166. package/dist/commands/tasks/start.d.ts +4 -0
  167. package/dist/commands/tasks/start.js +49 -3
  168. package/dist/commands/tasks/update.js +3 -0
  169. package/dist/commands/tasks/upsert.js +17 -3
  170. package/dist/commands/tasks/watch.d.ts +3 -0
  171. package/dist/commands/tasks/watch.js +85 -20
  172. package/dist/commands/wiki/history.d.ts +33 -0
  173. package/dist/commands/wiki/history.js +134 -0
  174. package/dist/commands/wiki/ls.d.ts +2 -0
  175. package/dist/commands/wiki/ls.js +8 -0
  176. package/dist/commands/wiki/update.d.ts +3 -1
  177. package/dist/commands/wiki/update.js +24 -2
  178. package/dist/commands/wiki/write.d.ts +22 -0
  179. package/dist/commands/wiki/write.js +144 -6
  180. package/dist/generated/agent-guides.json +81 -81
  181. package/dist/generated/managed-instruction-guides.json +1 -1
  182. package/dist/lib/agent-guides.d.ts +9 -0
  183. package/dist/lib/agent-guides.js +23 -1
  184. package/dist/lib/agentic-stream.d.ts +5 -0
  185. package/dist/lib/agentic-stream.js +122 -3
  186. package/dist/lib/auth-diagnostics.d.ts +39 -0
  187. package/dist/lib/auth-diagnostics.js +71 -0
  188. package/dist/lib/cli-client-identity.d.ts +6 -0
  189. package/dist/lib/cli-client-identity.js +16 -0
  190. package/dist/lib/cli-installation-diagnostics.d.ts +52 -0
  191. package/dist/lib/cli-installation-diagnostics.js +254 -0
  192. package/dist/lib/command-hygiene.d.ts +45 -0
  193. package/dist/lib/command-hygiene.js +413 -0
  194. package/dist/lib/commitments.d.ts +64 -3
  195. package/dist/lib/commitments.js +34 -6
  196. package/dist/lib/completion-index.d.ts +16 -4
  197. package/dist/lib/completion-index.js +50 -14
  198. package/dist/lib/config.js +7 -1
  199. package/dist/lib/daemon-maintenance-command.d.ts +22 -0
  200. package/dist/lib/daemon-maintenance-command.js +39 -0
  201. package/dist/lib/daemon-maintenance.d.ts +275 -0
  202. package/dist/lib/daemon-maintenance.js +1035 -0
  203. package/dist/lib/dedicated-service.d.ts +3 -2
  204. package/dist/lib/dedicated-service.js +11 -3
  205. package/dist/lib/governed-store.d.ts +8 -0
  206. package/dist/lib/governed-store.js +5 -0
  207. package/dist/lib/hosted-machines.d.ts +33 -2
  208. package/dist/lib/hosted-machines.js +19 -1
  209. package/dist/lib/json-output.d.ts +1 -1
  210. package/dist/lib/machines.d.ts +9 -1
  211. package/dist/lib/machines.js +15 -1
  212. package/dist/lib/node-adapter.js +13 -0
  213. package/dist/lib/record-output.d.ts +22 -0
  214. package/dist/lib/record-output.js +78 -0
  215. package/dist/lib/roles.d.ts +3 -3
  216. package/dist/lib/scoped-memory-command.d.ts +18 -0
  217. package/dist/lib/scoped-memory-command.js +53 -2
  218. package/dist/lib/space-charter.d.ts +49 -0
  219. package/dist/lib/space-charter.js +78 -0
  220. package/dist/lib/space-loop-migration.d.ts +18 -0
  221. package/dist/lib/space-loop-migration.js +128 -0
  222. package/dist/lib/space-notebook.d.ts +22 -0
  223. package/dist/lib/space-notebook.js +140 -0
  224. package/dist/lib/space-proposal-decision-command.d.ts +36 -0
  225. package/dist/lib/space-proposal-decision-command.js +108 -0
  226. package/dist/lib/space-proposals.d.ts +44 -0
  227. package/dist/lib/space-proposals.js +186 -0
  228. package/dist/lib/space-templates.d.ts +8 -0
  229. package/dist/lib/space-templates.js +17 -0
  230. package/dist/lib/space-write-policy.d.ts +24 -0
  231. package/dist/lib/space-write-policy.js +103 -0
  232. package/dist/lib/task-agent-context-capabilities.d.ts +10 -0
  233. package/dist/lib/task-agent-context-capabilities.js +22 -0
  234. package/dist/lib/task-agent-context-compatibility.d.ts +9 -0
  235. package/dist/lib/task-agent-context-compatibility.js +30 -0
  236. package/dist/lib/task-asset-upload.d.ts +22 -0
  237. package/dist/lib/task-asset-upload.js +257 -29
  238. package/dist/lib/task-batch.d.ts +15 -1
  239. package/dist/lib/task-batch.js +35 -2
  240. package/dist/lib/task-operation-watch.d.ts +66 -0
  241. package/dist/lib/task-operation-watch.js +159 -0
  242. package/dist/lib/task-resolver.d.ts +1 -1
  243. package/dist/lib/task-resolver.js +4 -3
  244. package/dist/lib/task-work.d.ts +1 -1
  245. package/dist/lib/task-work.js +35 -1
  246. package/dist/lib/task-write-attribution.d.ts +14 -0
  247. package/dist/lib/task-write-attribution.js +35 -2
  248. package/dist/lib/triggers.d.ts +11 -0
  249. package/dist/lib/triggers.js +7 -0
  250. package/dist/lib/wiki-update.d.ts +1 -0
  251. package/dist/lib/wiki-update.js +10 -1
  252. package/dist/lib/wiki.js +4 -1
  253. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +9 -1
  254. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +31 -15
  255. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +1 -0
  256. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +13 -7
  257. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/guidedUpdate.d.ts +370 -0
  258. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/guidedUpdate.js +315 -0
  259. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/maintenanceReportWire.d.ts +178 -0
  260. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/maintenanceReportWire.js +262 -0
  261. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.d.ts +51 -0
  262. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.js +106 -0
  263. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +9 -1
  264. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +32 -5
  265. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +1 -0
  266. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +33 -14
  267. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/guidedUpdate.d.ts +370 -0
  268. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/guidedUpdate.js +404 -0
  269. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/maintenanceReportWire.d.ts +178 -0
  270. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/maintenanceReportWire.js +342 -0
  271. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.d.ts +51 -0
  272. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.js +138 -0
  273. package/dist/node_modules/@skrr-ai/auth-core/package.json +20 -0
  274. package/dist/node_modules/@skrr-ai/data-provider/index.js +27085 -20250
  275. package/oclif.manifest.json +10566 -7247
  276. package/package.json +20 -2
@@ -13,9 +13,21 @@ export type CompletionIndex = {
13
13
  };
14
14
  export type CompletionKind = 'project' | 'space' | 'status' | 'task';
15
15
  export type CompletionIndexLoader = () => Promise<CompletionIndex>;
16
- export declare function completionIndexPath(cacheDir: string): string;
16
+ export type CompletionCacheScope = {
17
+ namespace: string;
18
+ credentialDigest: string;
19
+ };
20
+ /** Bind references to the command's resolved context, never a stored login. */
21
+ export declare function createCompletionCacheScope(context: {
22
+ configRoot: string;
23
+ profile: string;
24
+ baseURL: string;
25
+ workspaceId?: string;
26
+ token?: string | null;
27
+ }): CompletionCacheScope | null;
28
+ export declare function completionIndexPath(cacheDir: string, scope: CompletionCacheScope): string;
17
29
  /** Read corruption as a cache miss: a completion request should never fail a shell line. */
18
- export declare function readCompletionIndex(cacheDir: string): Promise<CompletionIndex | null>;
30
+ export declare function readCompletionIndex(cacheDir: string, scope: CompletionCacheScope | null): Promise<CompletionIndex | null>;
19
31
  /**
20
32
  * Build from the three lightweight list endpoints. The cache deliberately
21
33
  * stores identifiers/ref values, not titles or descriptions, both because a
@@ -27,5 +39,5 @@ export declare function loadCompletionIndex(): Promise<CompletionIndex>;
27
39
  * Refresh is best-effort by contract. A healthy cached index remains usable
28
40
  * during an outage; a first-use outage simply produces no dynamic candidates.
29
41
  */
30
- export declare function refreshCompletionIndex(cacheDir: string, loader?: CompletionIndexLoader): Promise<CompletionIndex | null>;
31
- export declare function completionCandidates(cacheDir: string, kind: CompletionKind, query?: string, loader?: CompletionIndexLoader): Promise<string[]>;
42
+ export declare function refreshCompletionIndex(cacheDir: string, scope: CompletionCacheScope | null, loader?: CompletionIndexLoader): Promise<CompletionIndex | null>;
43
+ export declare function completionCandidates(cacheDir: string, scope: CompletionCacheScope | null, kind: CompletionKind, query?: string, loader?: CompletionIndexLoader): Promise<string[]>;
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createCompletionCacheScope = createCompletionCacheScope;
36
37
  exports.completionIndexPath = completionIndexPath;
37
38
  exports.readCompletionIndex = readCompletionIndex;
38
39
  exports.loadCompletionIndex = loadCompletionIndex;
@@ -40,8 +41,32 @@ exports.refreshCompletionIndex = refreshCompletionIndex;
40
41
  exports.completionCandidates = completionCandidates;
41
42
  const fs = __importStar(require("node:fs/promises"));
42
43
  const path = __importStar(require("node:path"));
43
- const INDEX_FILE = 'index.json';
44
+ const node_crypto_1 = require("node:crypto");
44
45
  const INDEX_VERSION = 1;
46
+ const CACHE_VERSION = 2;
47
+ /** Bind references to the command's resolved context, never a stored login. */
48
+ function createCompletionCacheScope(context) {
49
+ if (!context.token)
50
+ return null;
51
+ try {
52
+ const hash = (value) => (0, node_crypto_1.createHash)('sha256').update(value).digest('hex');
53
+ // The adapter appends API paths to the full request base. Preserve deployment
54
+ // prefixes, queries and fragments; normalize its trailing-slash handling.
55
+ const requestBase = new URL(context.baseURL.replace(/\/+$/, '')).href;
56
+ return {
57
+ namespace: hash(JSON.stringify([
58
+ path.resolve(context.configRoot), context.profile,
59
+ requestBase, context.workspaceId || '',
60
+ ])),
61
+ // A different actor or rotated credential invalidates the existing file.
62
+ // Keep the filename stable so refreshes do not accumulate token-keyed files.
63
+ credentialDigest: hash(`completion-cache-v2\0${context.token}`),
64
+ };
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
45
70
  /**
46
71
  * Delay loading transport modules until a refresh is actually needed. The
47
72
  * shell's common cached path stays tiny, and cache-only unit tests do not need
@@ -65,8 +90,8 @@ function values(rows, ...keys) {
65
90
  function unique(entries) {
66
91
  return [...new Set(entries.map((entry) => entry.trim()).filter(Boolean))].sort((a, b) => a.localeCompare(b));
67
92
  }
68
- function completionIndexPath(cacheDir) {
69
- return path.join(cacheDir, 'completion', INDEX_FILE);
93
+ function completionIndexPath(cacheDir, scope) {
94
+ return path.join(cacheDir, 'completion', 'v2', `${scope.namespace}.json`);
70
95
  }
71
96
  function isCompletionIndex(value) {
72
97
  const index = value;
@@ -76,10 +101,14 @@ function isCompletionIndex(value) {
76
101
  ['projects', 'spaces', 'statuses', 'tasks'].every((key) => Array.isArray(index[key])));
77
102
  }
78
103
  /** Read corruption as a cache miss: a completion request should never fail a shell line. */
79
- async function readCompletionIndex(cacheDir) {
104
+ async function readCompletionIndex(cacheDir, scope) {
105
+ if (!scope)
106
+ return null;
80
107
  try {
81
- const parsed = JSON.parse(await fs.readFile(completionIndexPath(cacheDir), 'utf8'));
82
- return isCompletionIndex(parsed) ? parsed : null;
108
+ const parsed = JSON.parse(await fs.readFile(completionIndexPath(cacheDir, scope), 'utf8'));
109
+ return parsed?.version === CACHE_VERSION && parsed.namespace === scope.namespace &&
110
+ parsed.credentialDigest === scope.credentialDigest && isCompletionIndex(parsed.index)
111
+ ? parsed.index : null;
83
112
  }
84
113
  catch {
85
114
  return null;
@@ -123,13 +152,14 @@ async function loadCompletionIndex() {
123
152
  tasks: unique(values(tasks, 'identifier')),
124
153
  };
125
154
  }
126
- async function writeCompletionIndex(cacheDir, index) {
127
- const file = completionIndexPath(cacheDir);
155
+ async function writeCompletionIndex(cacheDir, scope, index) {
156
+ const file = completionIndexPath(cacheDir, scope);
128
157
  const directory = path.dirname(file);
129
158
  await fs.mkdir(directory, { recursive: true, mode: 0o700 });
130
159
  const temporary = `${file}.${process.pid}.${Date.now()}.tmp`;
131
160
  try {
132
- await fs.writeFile(temporary, `${JSON.stringify(index)}\n`, { encoding: 'utf8', mode: 0o600 });
161
+ const record = { version: CACHE_VERSION, ...scope, index };
162
+ await fs.writeFile(temporary, `${JSON.stringify(record)}\n`, { encoding: 'utf8', mode: 0o600 });
133
163
  await fs.rename(temporary, file);
134
164
  }
135
165
  finally {
@@ -140,20 +170,26 @@ async function writeCompletionIndex(cacheDir, index) {
140
170
  * Refresh is best-effort by contract. A healthy cached index remains usable
141
171
  * during an outage; a first-use outage simply produces no dynamic candidates.
142
172
  */
143
- async function refreshCompletionIndex(cacheDir, loader = loadCompletionIndex) {
173
+ async function refreshCompletionIndex(cacheDir, scope, loader = loadCompletionIndex) {
174
+ // Static command/flag completion still works before login. Workspace lists
175
+ // need an explicit current credential, including for doctor and --bare.
176
+ if (!scope)
177
+ return null;
144
178
  try {
145
179
  const index = await loader();
146
- await writeCompletionIndex(cacheDir, index);
180
+ await writeCompletionIndex(cacheDir, scope, index);
147
181
  return index;
148
182
  }
149
183
  catch {
150
184
  return null;
151
185
  }
152
186
  }
153
- async function completionCandidates(cacheDir, kind, query = '', loader = loadCompletionIndex) {
154
- let index = await readCompletionIndex(cacheDir);
187
+ async function completionCandidates(cacheDir, scope, kind, query = '', loader = loadCompletionIndex) {
188
+ if (!scope)
189
+ return [];
190
+ let index = await readCompletionIndex(cacheDir, scope);
155
191
  if (!index)
156
- index = await refreshCompletionIndex(cacheDir, loader);
192
+ index = await refreshCompletionIndex(cacheDir, scope, loader);
157
193
  if (!index)
158
194
  return [];
159
195
  const needle = query.trim().toLocaleLowerCase();
@@ -56,6 +56,7 @@ const os = __importStar(require("node:os"));
56
56
  const path = __importStar(require("node:path"));
57
57
  const keychain_1 = require("./keychain");
58
58
  const auth_core_1 = require("@skrr-ai/auth-core");
59
+ const auth_diagnostics_1 = require("./auth-diagnostics");
59
60
  const cli_id_1 = require("./cli-id");
60
61
  const device_id_1 = require("./device-id");
61
62
  const publicEndpoints_generated_1 = require("./publicEndpoints.generated");
@@ -205,8 +206,13 @@ function envOverlayValue(key) {
205
206
  const renamed = process.env[renamedName]?.trim();
206
207
  if (legacy && renamed && legacy !== renamed && !warnedEnvPrefixConflict) {
207
208
  warnedEnvPrefixConflict = true;
209
+ const display = (value) => {
210
+ if (key === 'token' || key === 'refreshToken')
211
+ return '[redacted]';
212
+ return (0, auth_diagnostics_1.safeServerOrigin)(value) ?? '[invalid URL]';
213
+ };
208
214
  process.stderr.write(`warning: ${legacyName} and ${renamedName} are both set and disagree. ` +
209
- `Using ${legacyName}=${legacy}.\n`);
215
+ `Using ${legacyName}=${display(legacy)}.\n`);
210
216
  }
211
217
  return legacy && legacy.length > 0 ? legacy : renamed && renamed.length > 0 ? renamed : undefined;
212
218
  }
@@ -0,0 +1,22 @@
1
+ import { BaseCommand } from '../base-command';
2
+ import { type MaintenanceRun } from './daemon-maintenance';
3
+ /**
4
+ * The part of `skrr daemon maintenance *` every command shares: how a finished run
5
+ * is printed, and how the command exits.
6
+ *
7
+ * With `--json` exactly one document goes to stdout, through `printJsonResult` so it
8
+ * carries `ok` first like every other command's result, and nothing else does:
9
+ * progress is always stderr. Without it a person gets the lines the run produced,
10
+ * results on stdout and refusals on stderr. The exit code is the run's, and it is
11
+ * the one thing a script gates on: 0 ready (or done), 1 refused, 2 still pending at
12
+ * the timeout, 3 unknown.
13
+ */
14
+ export declare abstract class DaemonMaintenanceCommand extends BaseCommand {
15
+ /**
16
+ * A progress line. stderr, always, so `--json` stdout stays one document. A method,
17
+ * not an arrow property: a test builds a command with `Object.create(prototype)`,
18
+ * which never runs a constructor, and a property would be missing there.
19
+ */
20
+ protected progressLine(line: string): void;
21
+ protected conclude(run: MaintenanceRun, json: boolean | undefined): void;
22
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DaemonMaintenanceCommand = void 0;
4
+ const base_command_1 = require("../base-command");
5
+ /**
6
+ * The part of `skrr daemon maintenance *` every command shares: how a finished run
7
+ * is printed, and how the command exits.
8
+ *
9
+ * With `--json` exactly one document goes to stdout, through `printJsonResult` so it
10
+ * carries `ok` first like every other command's result, and nothing else does:
11
+ * progress is always stderr. Without it a person gets the lines the run produced,
12
+ * results on stdout and refusals on stderr. The exit code is the run's, and it is
13
+ * the one thing a script gates on: 0 ready (or done), 1 refused, 2 still pending at
14
+ * the timeout, 3 unknown.
15
+ */
16
+ class DaemonMaintenanceCommand extends base_command_1.BaseCommand {
17
+ /**
18
+ * A progress line. stderr, always, so `--json` stdout stays one document. A method,
19
+ * not an arrow property: a test builds a command with `Object.create(prototype)`,
20
+ * which never runs a constructor, and a property would be missing there.
21
+ */
22
+ progressLine(line) {
23
+ process.stderr.write(`${line}\n`);
24
+ }
25
+ conclude(run, json) {
26
+ if (json) {
27
+ this.printJsonResult(run.document, { ok: run.exit === 0 });
28
+ }
29
+ else {
30
+ for (const line of run.stdout)
31
+ this.log(line);
32
+ for (const line of run.stderr)
33
+ process.stderr.write(`${line}\n`);
34
+ }
35
+ if (run.exit !== 0)
36
+ this.exit(run.exit);
37
+ }
38
+ }
39
+ exports.DaemonMaintenanceCommand = DaemonMaintenanceCommand;
@@ -0,0 +1,275 @@
1
+ import { DAEMON_MAINTENANCE_EXIT_CODES, type DaemonMaintenanceAttestationRequest, type DaemonMaintenanceChangeRequest, type DaemonMaintenanceDaemonRef, type DaemonMaintenanceOutcome, type DaemonMaintenanceSummary, type DaemonMaintenanceView } from '@skrr-ai/data-provider';
2
+ import { type Machine } from './machines';
3
+ /**
4
+ * daemon-maintenance.ts — the owner's pause on one of their own machines, from the
5
+ * terminal (`skrr daemon maintenance status | hold | resume | attest`; OSK-19107,
6
+ * Space OSK-S-524, plan §3.6, journey J12).
7
+ *
8
+ * ## What this file does NOT do
9
+ *
10
+ * It declares no phase, cause, refusal, control or word. All of them are owned by
11
+ * `@skrr-ai/data-provider` (`daemonMaintenance.ts`) and imported: the SERVER decides
12
+ * which phase a machine is in (`deriveMaintenanceJourney`), this file renders what
13
+ * the server answered. A synonym spelled here is the drift that module exists to stop.
14
+ *
15
+ * It never builds an `/api/...` URL. Every call is a `dataService` function
16
+ * (`listDaemonMaintenance` and its three siblings), which is how
17
+ * `domain-api-parity.spec.ts` sees this domain.
18
+ *
19
+ * ## The contract a script can rely on
20
+ *
21
+ * With `--json` every command writes EXACTLY ONE JSON object to stdout and nothing
22
+ * else (progress goes to stderr), with `schema: 1` and a `command` and an `outcome`.
23
+ * The exit code follows `scripts/release-status.js` and is in the document as
24
+ * `exit`: `DAEMON_MAINTENANCE_EXIT_CODES` — 0 ready, 1 refused, 2 still pending at
25
+ * the timeout, 3 unknown.
26
+ *
27
+ * - Only `hold --wait ready` and a command that could not read the state end in 2 or 3.
28
+ * `status`, a `hold` that did not wait, `resume` and `attest` end in 0 when they did
29
+ * what was asked, and in 1 when the server (or this CLI, before asking) refused.
30
+ * - **A timeout NEVER releases the hold**, and the document and the text both say so
31
+ * (`holdInForce: true`). A script cannot mistake "timed out" for "ready", and a
32
+ * person is told the one command that lets go.
33
+ * - A state this CLI could not read (the network, a 5xx, a 429) is `unknown`, exit 3:
34
+ * "I could not tell" is an answer, and it is never rendered as `ready` or as zero.
35
+ *
36
+ * ## Naming a machine, and why it never picks
37
+ *
38
+ * `<machine>` is a machine id, a name, or a runtimeKey. A hold addresses ONE
39
+ * `runtimeKey` (one daemon, so one profile), and one machine can span several, so a
40
+ * machine that is two daemons is ambiguous by construction. Resolution therefore
41
+ * REFUSES with the candidates when a reference matches zero or more than one, and
42
+ * the only inference it makes is the unambiguous one: no reference given and exactly
43
+ * one daemon that qualifies.
44
+ */
45
+ /** The version of the documents `--json` prints. Bump it when a field's meaning changes. */
46
+ export declare const DAEMON_MAINTENANCE_CLI_SCHEMA: 1;
47
+ /** How often `--wait` reads the state, and how long it waits when no timeout is given. */
48
+ export declare const MAINTENANCE_POLL_INTERVAL_MS = 5000;
49
+ export declare const MAINTENANCE_DEFAULT_TIMEOUT_MS: number;
50
+ export declare const MAINTENANCE_MAX_TIMEOUT_MS: number;
51
+ /** A machine from `GET /api/machines`, with the two additive maintenance fields. */
52
+ export type MaintenanceMachineRow = Machine & {
53
+ daemons?: DaemonMaintenanceDaemonRef[];
54
+ maintenance?: DaemonMaintenanceSummary;
55
+ };
56
+ /** One daemon a hold can address. */
57
+ export interface MaintenanceCandidate {
58
+ runtimeKey: string;
59
+ machineId?: string;
60
+ name?: string;
61
+ profile?: string | null;
62
+ daemonId?: string;
63
+ held?: boolean;
64
+ }
65
+ /** A refusal as a value: the code is the vocabulary's (or a transport word), the message is a sentence. */
66
+ export interface MaintenanceRefusal {
67
+ code: string;
68
+ message: string;
69
+ status?: number;
70
+ currentGeneration?: number;
71
+ /** Machine candidates from this CLI's own resolution, or machine uuids from a server `ambiguous`. */
72
+ candidates?: Array<MaintenanceCandidate | string>;
73
+ retryAfterMs?: number;
74
+ }
75
+ export type MaintenanceFailure = MaintenanceRefusal & {
76
+ /** `refused`: an answer (do not retry unchanged). `unknown`: no answer (the state is NOT known). */
77
+ kind: 'refused' | 'unknown';
78
+ };
79
+ export type MaintenanceResult<T> = {
80
+ ok: true;
81
+ value: T;
82
+ } | {
83
+ ok: false;
84
+ error: MaintenanceFailure;
85
+ };
86
+ /**
87
+ * Every call this CLI makes. A plain mutable object so a test replaces one member
88
+ * without touching a module: the real members are `dataService` functions and the
89
+ * machine list, nothing else.
90
+ */
91
+ export declare const maintenanceApi: {
92
+ listMachines: () => Promise<MaintenanceMachineRow[]>;
93
+ list: () => Promise<{
94
+ holds: DaemonMaintenanceView[];
95
+ }>;
96
+ get: (runtimeKey: string) => Promise<DaemonMaintenanceView>;
97
+ change: (runtimeKey: string, body: DaemonMaintenanceChangeRequest) => Promise<DaemonMaintenanceView>;
98
+ attest: (runtimeKey: string, body: DaemonMaintenanceAttestationRequest) => Promise<DaemonMaintenanceView>;
99
+ };
100
+ export type MaintenanceApi = typeof maintenanceApi;
101
+ /** The clock and the sleep `--wait` uses, replaceable so a timeout takes no time to test. */
102
+ export declare const maintenanceClock: {
103
+ now: () => number;
104
+ sleep: (ms: number) => Promise<void>;
105
+ };
106
+ /**
107
+ * What a failed call means. Two kinds, and the difference is the whole design:
108
+ *
109
+ * - `refused`: the server ANSWERED no (a 4xx other than 429). The answer carries a
110
+ * code the vocabulary knows, or a transport word (`invalid_request`,
111
+ * `unauthorized`), and a sentence. Repeating the request unchanged repeats it.
112
+ * - `unknown`: there was NO answer (the network, a 5xx, a 429). Nothing is known
113
+ * about the machine's state from it, so it is never reported as a refusal or as
114
+ * "not held".
115
+ */
116
+ export declare function failureFromError(err: unknown): MaintenanceFailure;
117
+ /** Run one call and turn what it throws into a value. */
118
+ export declare function attempt<T>(call: () => Promise<T>): Promise<MaintenanceResult<T>>;
119
+ /** A runtimeKey needs no lookup: the server decides whether it is one of ours. */
120
+ export declare function looksLikeRuntimeKey(ref: string): boolean;
121
+ export type TargetScope = 'any' | 'held';
122
+ export type Resolution = {
123
+ ok: true;
124
+ target: MaintenanceCandidate;
125
+ } | {
126
+ ok: false;
127
+ refusal: MaintenanceRefusal;
128
+ };
129
+ /**
130
+ * Which daemon a reference names. Pure: the lists are passed in.
131
+ *
132
+ * A reference is matched in three tiers and the FIRST tier with any match decides:
133
+ * an exact id or runtimeKey, then an exact name (any case), then a unique id prefix of
134
+ * at least four characters. Within the tier the answer is the set of matching
135
+ * DAEMONS, and a set of anything but one is a refusal that lists them.
136
+ *
137
+ * `scope: 'held'` (resume, attest) considers only daemons with a live hold: naming a
138
+ * machine that is not held is `not_held`, not a pick of some other machine.
139
+ *
140
+ * With no reference, the one candidate that qualifies is used and anything else is a
141
+ * refusal listing them: `hold` with no argument on an account with a single
142
+ * machine is not a guess, and on an account with two it never picks.
143
+ */
144
+ export declare function resolveMaintenanceTarget(input: {
145
+ ref?: string;
146
+ machines?: MaintenanceMachineRow[];
147
+ holds?: DaemonMaintenanceView[];
148
+ scope: TargetScope;
149
+ }): Resolution;
150
+ export interface WaitResult {
151
+ /**
152
+ * `ready`: the server says ready. `timeout`: it did not, in time, and the hold is
153
+ * STILL IN FORCE. `released`: the hold is gone (someone resumed it), so there is
154
+ * nothing left to wait for. `refused`: the server refused the read itself.
155
+ */
156
+ outcome: 'ready' | 'timeout' | 'released' | 'refused';
157
+ view: DaemonMaintenanceView | null;
158
+ error: MaintenanceFailure | null;
159
+ polls: number;
160
+ waitedMs: number;
161
+ }
162
+ /** The word and cause a progress line shows: the vocabulary's word, and the cause code as is. */
163
+ export declare function stateLine(view: DaemonMaintenanceView): string;
164
+ /**
165
+ * Poll the view until it says `ready`, the hold is gone, or the timeout passes.
166
+ *
167
+ * It stops waiting the moment the machine is `ready`; otherwise it keeps waiting until
168
+ * the timeout, because the server — not this loop — decides that `unknown` or
169
+ * `back_held` is final. At least one read is made even with a zero timeout. A read
170
+ * that cannot be answered (the network, a 5xx, a 429) is retried until the timeout and
171
+ * is never taken for progress, or for readiness; a read the server REFUSES (a 404, a
172
+ * 403) ends the wait.
173
+ *
174
+ * Reaching the timeout does nothing to the hold. This function has no way to release
175
+ * one: it is given a `read` and nothing else.
176
+ */
177
+ export declare function waitForReady(io: {
178
+ read: () => Promise<MaintenanceResult<DaemonMaintenanceView>>;
179
+ now: () => number;
180
+ sleep: (ms: number) => Promise<void>;
181
+ progress: (line: string) => void;
182
+ }, options: {
183
+ timeoutMs: number;
184
+ intervalMs: number;
185
+ }): Promise<WaitResult>;
186
+ export type MaintenanceCommandName = 'status' | 'hold' | 'resume' | 'attest';
187
+ export type MaintenanceExitCode = (typeof DAEMON_MAINTENANCE_EXIT_CODES)[keyof typeof DAEMON_MAINTENANCE_EXIT_CODES];
188
+ /** What a run produces: the one `--json` document, the exit code, and the text for a person. */
189
+ export interface MaintenanceRun {
190
+ document: Record<string, unknown>;
191
+ exit: MaintenanceExitCode;
192
+ /** Printed to stdout when not `--json`. */
193
+ stdout: string[];
194
+ /** Printed to stderr when not `--json` (errors, refusals, and what to do next). */
195
+ stderr: string[];
196
+ }
197
+ export interface MaintenanceIo {
198
+ api: MaintenanceApi;
199
+ now: () => number;
200
+ sleep: (ms: number) => Promise<void>;
201
+ /** A progress line. Always stderr, so stdout stays one document. */
202
+ progress: (line: string) => void;
203
+ }
204
+ export declare function defaultIo(progress: (line: string) => void): MaintenanceIo;
205
+ /**
206
+ * What became of the work a released hold had parked (OSK-19623): one summary line and, where
207
+ * something could not restart or ran out of time, one line per cause in the CLI's own words.
208
+ *
209
+ * A count that was never measured is "not counted", never zero, and a re-drive that has not
210
+ * finished says so: the numbers are what it has done so far. The causes are closed classes
211
+ * (`DAEMON_MAINTENANCE_RESTART_REFUSAL_WORDS`), so nothing here prints a run id or a reason
212
+ * the server wrote.
213
+ */
214
+ export declare function outcomeLines(outcome: DaemonMaintenanceOutcome | null | undefined): string[];
215
+ /** The lines `status` and the end of `hold` print for one machine. */
216
+ export declare function describeView(view: DaemonMaintenanceView, options?: {
217
+ explain?: boolean;
218
+ }): string[];
219
+ /** `--explain`: each source the reading used, in the order it was read, and what each said. */
220
+ export declare function explainLines(view: DaemonMaintenanceView): string[];
221
+ /** `status`: every hold the owner has, or one machine's state. */
222
+ export declare function runStatus(input: {
223
+ ref?: string;
224
+ explain?: boolean;
225
+ }, io: MaintenanceIo): Promise<MaintenanceRun>;
226
+ export interface HoldInput {
227
+ ref?: string;
228
+ reason?: string;
229
+ autoResume?: boolean;
230
+ /** Wait for `ready`. Undefined: take the hold and return. */
231
+ wait?: {
232
+ timeoutMs: number;
233
+ intervalMs?: number;
234
+ };
235
+ explain?: boolean;
236
+ }
237
+ /**
238
+ * `hold`: take the hold, and optionally wait for the machine to be ready.
239
+ *
240
+ * A hold already in force is not a refusal here: asking to hold a machine you have
241
+ * already held is the retry after a lost response, or the re-run after a Ctrl-C
242
+ * during `--wait`. The live hold is reported (`created: false`), its reason is kept
243
+ * and a different `--reason` is said to have been ignored, and `--wait` then waits
244
+ * on it.
245
+ */
246
+ export declare function runHold(input: HoldInput, io: MaintenanceIo): Promise<MaintenanceRun>;
247
+ export interface ResumeInput {
248
+ ref?: string;
249
+ generation?: number;
250
+ }
251
+ /** `resume`: release the hold. A compare-and-set on the generation. */
252
+ export declare function runResume(input: ResumeInput, io: MaintenanceIo): Promise<MaintenanceRun>;
253
+ export interface AttestInput {
254
+ ref?: string;
255
+ kind: 'attest_ready' | 'proceed_anyway';
256
+ generation?: number;
257
+ }
258
+ /** The labels of the work the reading shows, for a `proceed_anyway` the owner confirmed. */
259
+ export declare function holdersShown(view: DaemonMaintenanceView): string[];
260
+ /**
261
+ * `attest`: the owner says the machine is ready (`--ready`, only where the server
262
+ * allows it) or proceeds anyway (`--proceed`, naming what was running). The server
263
+ * decides whether an attestation applies; the CLI never decides it from a phase.
264
+ */
265
+ export declare function runAttest(input: AttestInput, io: MaintenanceIo): Promise<MaintenanceRun>;
266
+ /** `--timeout`, parsed and bounded. */
267
+ export declare function parseTimeout(value: string | undefined): {
268
+ ok: true;
269
+ ms: number;
270
+ } | {
271
+ ok: false;
272
+ message: string;
273
+ };
274
+ /** A failed flag, as a refusal the command prints the way every other refusal is printed. */
275
+ export declare function invalidFlagRun(command: MaintenanceCommandName, message: string): MaintenanceRun;