@skrr-ai/cli 0.1.21 → 0.1.23

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 (245) hide show
  1. package/README.md +83 -73
  2. package/bin/dev-fallback.js +221 -0
  3. package/bin/run.js +43 -0
  4. package/dist/base-command.d.ts +15 -0
  5. package/dist/base-command.js +71 -10
  6. package/dist/commands/agents/attach-harness.d.ts +37 -0
  7. package/dist/commands/agents/attach-harness.js +102 -3
  8. package/dist/commands/agents/chat.d.ts +69 -1
  9. package/dist/commands/agents/chat.js +202 -22
  10. package/dist/commands/agents/create.d.ts +38 -0
  11. package/dist/commands/agents/create.js +95 -2
  12. package/dist/commands/agents/schedule-trace.js +11 -0
  13. package/dist/commands/agents/show.js +29 -1
  14. package/dist/commands/api-keys/create.d.ts +24 -0
  15. package/dist/commands/api-keys/create.js +80 -0
  16. package/dist/commands/api-keys/list.d.ts +11 -0
  17. package/dist/commands/api-keys/list.js +42 -0
  18. package/dist/commands/api-keys/revoke.d.ts +14 -0
  19. package/dist/commands/api-keys/revoke.js +33 -0
  20. package/dist/commands/api-keys/rotate.d.ts +19 -0
  21. package/dist/commands/api-keys/rotate.js +42 -0
  22. package/dist/commands/balance/index.d.ts +18 -0
  23. package/dist/commands/balance/index.js +29 -0
  24. package/dist/commands/balance/show.d.ts +25 -0
  25. package/dist/commands/balance/show.js +60 -0
  26. package/dist/commands/balance/statement.d.ts +19 -0
  27. package/dist/commands/balance/statement.js +52 -0
  28. package/dist/commands/browser/doctor.d.ts +11 -0
  29. package/dist/commands/browser/doctor.js +11 -0
  30. package/dist/commands/code/jobs/approve.d.ts +25 -0
  31. package/dist/commands/code/jobs/approve.js +52 -0
  32. package/dist/commands/code/jobs/cancel.d.ts +12 -0
  33. package/dist/commands/code/jobs/cancel.js +39 -0
  34. package/dist/commands/code/jobs/index.d.ts +19 -0
  35. package/dist/commands/code/jobs/index.js +38 -0
  36. package/dist/commands/code/jobs/list.d.ts +12 -0
  37. package/dist/commands/code/jobs/list.js +87 -0
  38. package/dist/commands/code/jobs/run.d.ts +32 -0
  39. package/dist/commands/code/jobs/run.js +151 -0
  40. package/dist/commands/code/jobs/show.d.ts +12 -0
  41. package/dist/commands/code/jobs/show.js +86 -0
  42. package/dist/commands/commitments/create.d.ts +1 -0
  43. package/dist/commands/commitments/create.js +19 -5
  44. package/dist/commands/commitments/preflight.js +18 -4
  45. package/dist/commands/commitments/receipt-metrics.d.ts +39 -0
  46. package/dist/commands/commitments/receipt-metrics.js +78 -0
  47. package/dist/commands/convos/search.js +5 -5
  48. package/dist/commands/harnesses/leases/list.d.ts +3 -0
  49. package/dist/commands/harnesses/leases/list.js +59 -12
  50. package/dist/commands/harnesses/leases/show.js +36 -0
  51. package/dist/commands/harnesses/list.d.ts +18 -0
  52. package/dist/commands/harnesses/list.js +30 -0
  53. package/dist/commands/harnesses/products.js +48 -3
  54. package/dist/commands/harnesses/quota.d.ts +16 -0
  55. package/dist/commands/harnesses/quota.js +26 -1
  56. package/dist/commands/harnesses/usage.js +17 -0
  57. package/dist/commands/inbox/index.d.ts +2 -1
  58. package/dist/commands/inbox/index.js +27 -4
  59. package/dist/commands/login.js +4 -1
  60. package/dist/commands/machines/list.d.ts +1 -0
  61. package/dist/commands/machines/list.js +33 -5
  62. package/dist/commands/memory/approvals/issue.d.ts +18 -0
  63. package/dist/commands/memory/approvals/issue.js +63 -0
  64. package/dist/commands/memory/commit.js +5 -2
  65. package/dist/commands/memory/context.d.ts +3 -2
  66. package/dist/commands/memory/context.js +9 -11
  67. package/dist/commands/memory/delete.d.ts +1 -1
  68. package/dist/commands/memory/list.d.ts +1 -1
  69. package/dist/commands/memory/list.js +1 -1
  70. package/dist/commands/memory/mounts/resolve.d.ts +10 -0
  71. package/dist/commands/memory/mounts/resolve.js +27 -0
  72. package/dist/commands/memory/proposals/commit.d.ts +18 -0
  73. package/dist/commands/memory/proposals/commit.js +32 -0
  74. package/dist/commands/memory/proposals/create.d.ts +18 -0
  75. package/dist/commands/memory/proposals/create.js +56 -0
  76. package/dist/commands/memory/proposals/list.d.ts +13 -0
  77. package/dist/commands/memory/proposals/list.js +31 -0
  78. package/dist/commands/memory/proposals/promote.d.ts +22 -0
  79. package/dist/commands/memory/proposals/promote.js +33 -0
  80. package/dist/commands/memory/proposals/reject.d.ts +16 -0
  81. package/dist/commands/memory/proposals/reject.js +28 -0
  82. package/dist/commands/memory/rebuild-index.d.ts +20 -0
  83. package/dist/commands/memory/rebuild-index.js +25 -0
  84. package/dist/commands/memory/save.d.ts +1 -1
  85. package/dist/commands/memory/save.js +1 -1
  86. package/dist/commands/memory/search.d.ts +6 -3
  87. package/dist/commands/memory/search.js +27 -3
  88. package/dist/commands/memory/show.d.ts +1 -1
  89. package/dist/commands/memory/stores/archive.d.ts +14 -0
  90. package/dist/commands/memory/stores/archive.js +31 -0
  91. package/dist/commands/memory/stores/create.d.ts +12 -0
  92. package/dist/commands/memory/stores/create.js +30 -0
  93. package/dist/commands/memory/stores/delete.d.ts +15 -0
  94. package/dist/commands/memory/stores/delete.js +38 -0
  95. package/dist/commands/memory/stores/list.d.ts +10 -0
  96. package/dist/commands/memory/stores/list.js +29 -0
  97. package/dist/commands/memory/stores/show.d.ts +12 -0
  98. package/dist/commands/memory/stores/show.js +14 -0
  99. package/dist/commands/memory/stores/update.d.ts +15 -0
  100. package/dist/commands/memory/stores/update.js +39 -0
  101. package/dist/commands/memory/sync/delete.d.ts +13 -0
  102. package/dist/commands/memory/sync/delete.js +35 -0
  103. package/dist/commands/memory/sync/pull.d.ts +19 -0
  104. package/dist/commands/memory/sync/pull.js +52 -0
  105. package/dist/commands/memory/sync/push.d.ts +18 -0
  106. package/dist/commands/memory/sync/push.js +115 -0
  107. package/dist/commands/memory/sync/resolve.d.ts +23 -0
  108. package/dist/commands/memory/sync/resolve.js +27 -0
  109. package/dist/commands/memory/sync/status.d.ts +9 -0
  110. package/dist/commands/memory/sync/status.js +22 -0
  111. package/dist/commands/memory/topics/archive.d.ts +20 -0
  112. package/dist/commands/memory/topics/archive.js +29 -0
  113. package/dist/commands/memory/topics/create.d.ts +23 -0
  114. package/dist/commands/memory/topics/create.js +46 -0
  115. package/dist/commands/memory/topics/delete.d.ts +22 -0
  116. package/dist/commands/memory/topics/delete.js +30 -0
  117. package/dist/commands/memory/topics/forget.d.ts +22 -0
  118. package/dist/commands/memory/topics/forget.js +29 -0
  119. package/dist/commands/memory/topics/list.d.ts +13 -0
  120. package/dist/commands/memory/topics/list.js +22 -0
  121. package/dist/commands/memory/topics/move.d.ts +22 -0
  122. package/dist/commands/memory/topics/move.js +26 -0
  123. package/dist/commands/memory/topics/show.d.ts +17 -0
  124. package/dist/commands/memory/topics/show.js +21 -0
  125. package/dist/commands/memory/topics/update.d.ts +23 -0
  126. package/dist/commands/memory/topics/update.js +27 -0
  127. package/dist/commands/memory/tree.d.ts +5 -2
  128. package/dist/commands/memory/tree.js +20 -2
  129. package/dist/commands/memory/update.d.ts +1 -1
  130. package/dist/commands/memory/versions/list.d.ts +16 -0
  131. package/dist/commands/memory/versions/list.js +22 -0
  132. package/dist/commands/memory/versions/redact.d.ts +21 -0
  133. package/dist/commands/memory/versions/redact.js +22 -0
  134. package/dist/commands/memory/versions/restore.d.ts +20 -0
  135. package/dist/commands/memory/versions/restore.js +16 -0
  136. package/dist/commands/memory/versions/show.d.ts +15 -0
  137. package/dist/commands/memory/versions/show.js +17 -0
  138. package/dist/commands/messages/list.js +25 -8
  139. package/dist/commands/messages/show.js +10 -0
  140. package/dist/commands/store/install.js +5 -1
  141. package/dist/commands/store/releases.js +1 -1
  142. package/dist/commands/store/update.js +5 -1
  143. package/dist/commands/subscriptions/cancel.js +5 -1
  144. package/dist/commands/subscriptions/health.js +5 -1
  145. package/dist/commands/subscriptions/status.js +5 -1
  146. package/dist/commands/subscriptions/subscribe.js +5 -1
  147. package/dist/commands/tasks/activity.d.ts +2 -3
  148. package/dist/commands/tasks/activity.js +15 -5
  149. package/dist/commands/tasks/complete.d.ts +18 -150
  150. package/dist/commands/tasks/complete.js +161 -600
  151. package/dist/commands/tasks/create.d.ts +5 -0
  152. package/dist/commands/tasks/create.js +107 -4
  153. package/dist/commands/tasks/deliverable/add.d.ts +8 -0
  154. package/dist/commands/tasks/deliverable/add.js +41 -8
  155. package/dist/commands/tasks/deliverable/confirm.d.ts +5 -5
  156. package/dist/commands/tasks/deliverable/confirm.js +9 -18
  157. package/dist/commands/tasks/deliverable/list.d.ts +12 -0
  158. package/dist/commands/tasks/deliverable/list.js +37 -0
  159. package/dist/commands/tasks/events/append.d.ts +2 -0
  160. package/dist/commands/tasks/events/append.js +11 -4
  161. package/dist/commands/tasks/events/list.d.ts +1 -0
  162. package/dist/commands/tasks/events/list.js +1 -0
  163. package/dist/commands/tasks/events/tail.d.ts +1 -0
  164. package/dist/commands/tasks/events/tail.js +1 -0
  165. package/dist/commands/tasks/expectations/assess.d.ts +21 -0
  166. package/dist/commands/tasks/expectations/assess.js +77 -0
  167. package/dist/commands/tasks/expectations.js +14 -18
  168. package/dist/commands/tasks/judge.d.ts +1 -0
  169. package/dist/commands/tasks/judge.js +2 -1
  170. package/dist/commands/tasks/output.d.ts +2 -11
  171. package/dist/commands/tasks/output.js +64 -145
  172. package/dist/commands/tasks/report.d.ts +3 -3
  173. package/dist/commands/tasks/report.js +64 -41
  174. package/dist/commands/tasks/resource/add.d.ts +23 -0
  175. package/dist/commands/tasks/resource/add.js +76 -0
  176. package/dist/commands/tasks/resource/list.d.ts +13 -0
  177. package/dist/commands/tasks/resource/list.js +41 -0
  178. package/dist/commands/tasks/result/show.d.ts +13 -0
  179. package/dist/commands/tasks/result/show.js +46 -0
  180. package/dist/commands/tasks/result/submit.d.ts +26 -0
  181. package/dist/commands/tasks/result/submit.js +134 -0
  182. package/dist/commands/tasks/resume/save.d.ts +16 -0
  183. package/dist/commands/tasks/resume/save.js +59 -0
  184. package/dist/commands/tasks/resume/show.d.ts +13 -0
  185. package/dist/commands/tasks/resume/show.js +35 -0
  186. package/dist/commands/tasks/review.d.ts +17 -0
  187. package/dist/commands/tasks/review.js +54 -0
  188. package/dist/commands/tasks/runs.js +5 -0
  189. package/dist/commands/tasks/timeline.d.ts +2 -2
  190. package/dist/commands/tasks/timeline.js +10 -23
  191. package/dist/commands/tasks/updates/add.d.ts +22 -0
  192. package/dist/commands/tasks/updates/add.js +101 -0
  193. package/dist/commands/tasks/updates/list.d.ts +15 -0
  194. package/dist/commands/tasks/updates/list.js +57 -0
  195. package/dist/commands/tasks/waive.d.ts +1 -0
  196. package/dist/commands/tasks/waive.js +2 -1
  197. package/dist/lib/agentic-stream.d.ts +257 -0
  198. package/dist/lib/agentic-stream.js +490 -33
  199. package/dist/lib/balance.d.ts +8 -0
  200. package/dist/lib/commitment-product.d.ts +10 -1
  201. package/dist/lib/commitment-product.js +66 -2
  202. package/dist/lib/commitments.d.ts +4 -1
  203. package/dist/lib/commitments.js +32 -1
  204. package/dist/lib/conversation-search.d.ts +3 -0
  205. package/dist/lib/conversation-search.js +75 -0
  206. package/dist/lib/execution-target.d.ts +21 -0
  207. package/dist/lib/execution-target.js +22 -6
  208. package/dist/lib/harnesses.d.ts +82 -6
  209. package/dist/lib/harnesses.js +30 -2
  210. package/dist/lib/hosted-machines.js +9 -0
  211. package/dist/lib/inbox.d.ts +2 -1
  212. package/dist/lib/machines.d.ts +17 -0
  213. package/dist/lib/machines.js +29 -0
  214. package/dist/lib/managed-agent-keys.d.ts +104 -0
  215. package/dist/lib/managed-agent-keys.js +50 -0
  216. package/dist/lib/memory-scope.d.ts +4 -3
  217. package/dist/lib/memory-scope.js +9 -9
  218. package/dist/lib/memory-sync.d.ts +114 -0
  219. package/dist/lib/memory-sync.js +730 -0
  220. package/dist/lib/message-provenance.d.ts +42 -0
  221. package/dist/lib/message-provenance.js +89 -0
  222. package/dist/lib/scoped-memory-command.d.ts +68 -0
  223. package/dist/lib/scoped-memory-command.js +183 -0
  224. package/dist/lib/session-task-endpoints.d.ts +1 -1
  225. package/dist/lib/session-task-endpoints.js +7 -0
  226. package/dist/lib/sky-code-broker.d.ts +47 -0
  227. package/dist/lib/sky-code-broker.js +50 -0
  228. package/dist/lib/sky-code-doctor.js +10 -1
  229. package/dist/lib/task-artifact-flags.d.ts +2 -0
  230. package/dist/lib/task-artifact-flags.js +7 -0
  231. package/dist/lib/task-execution.d.ts +4 -5
  232. package/dist/lib/task-execution.js +4 -5
  233. package/dist/lib/task-extras.d.ts +1 -5
  234. package/dist/lib/task-extras.js +1 -5
  235. package/dist/lib/task-transcript.d.ts +5 -7
  236. package/dist/lib/task-transcript.js +8 -16
  237. package/dist/lib/tasks.d.ts +7 -21
  238. package/dist/lib/tasks.js +17 -20
  239. package/dist/lib/triggers.d.ts +39 -1
  240. package/dist/lib/triggers.js +70 -2
  241. package/dist/lib/usage-discovery.d.ts +17 -1
  242. package/dist/lib/usage-discovery.js +17 -1
  243. package/dist/node_modules/@skrr-ai/data-provider/index.js +3733 -3618
  244. package/oclif.manifest.json +25726 -19886
  245. package/package.json +26 -5
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ export default class CodeJobsCancel extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ job: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
+ const base_command_1 = require("../../../base-command");
6
+ class CodeJobsCancel extends base_command_1.BaseCommand {
7
+ static description = 'Stop a Hosted Job Machine job, and its billing';
8
+ static examples = [
9
+ '<%= config.bin %> code jobs cancel <job-id>',
10
+ '<%= config.bin %> code jobs cancel <job-id> --json',
11
+ ];
12
+ static args = {
13
+ job: core_1.Args.string({ description: 'Job id', required: true, ignoreStdin: true }),
14
+ };
15
+ static flags = { json: core_1.Flags.boolean({ description: 'Output as JSON' }) };
16
+ async run() {
17
+ this.requireAuth();
18
+ const { args, flags } = await this.parse(CodeJobsCancel);
19
+ let task;
20
+ try {
21
+ const res = await data_provider_1.dataService.cancelCloudCodingTask(args.job);
22
+ task = res?.task;
23
+ }
24
+ catch (err) {
25
+ this.handleApiError(err);
26
+ }
27
+ if (flags.json) {
28
+ this.log(JSON.stringify(task, null, 2));
29
+ return;
30
+ }
31
+ // Report the status the SERVER came back with, never the one we asked for.
32
+ // Cancel races a job that is already finishing, and printing "cancelled"
33
+ // over a `completed` row would be the CLI inventing an outcome.
34
+ this.log(`Job ${task?.id ?? args.job} is now ${task?.status ?? 'unknown'}.`);
35
+ if (task?.prUrl)
36
+ this.log(` ${String(task.prUrl)}`);
37
+ }
38
+ }
39
+ exports.default = CodeJobsCancel;
@@ -0,0 +1,19 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * `skrr code jobs` — the lifecycle of work running on a Hosted Job Machine.
4
+ *
5
+ * A job is the object, not the machine. A Hosted Job Machine is one-shot
6
+ * compute that exists for the duration of one job and is torn down after it, so
7
+ * there is nothing to create, update or resume; `skrr code handover` starts one
8
+ * and these verbs observe and stop it.
9
+ *
10
+ * They exist because `POST /api/cloud-coding/tasks` had a CLI binding and the
11
+ * rest of the surface did not. An operator could dispatch a job onto managed
12
+ * cloud compute and then had no way to see whether it was running, no way to
13
+ * read why it failed, and — the one that costs money — no way to cancel it.
14
+ */
15
+ export default class CodeJobs extends Command {
16
+ static description: string;
17
+ static examples: string[];
18
+ run(): Promise<void>;
19
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ /**
5
+ * `skrr code jobs` — the lifecycle of work running on a Hosted Job Machine.
6
+ *
7
+ * A job is the object, not the machine. A Hosted Job Machine is one-shot
8
+ * compute that exists for the duration of one job and is torn down after it, so
9
+ * there is nothing to create, update or resume; `skrr code handover` starts one
10
+ * and these verbs observe and stop it.
11
+ *
12
+ * They exist because `POST /api/cloud-coding/tasks` had a CLI binding and the
13
+ * rest of the surface did not. An operator could dispatch a job onto managed
14
+ * cloud compute and then had no way to see whether it was running, no way to
15
+ * read why it failed, and — the one that costs money — no way to cancel it.
16
+ */
17
+ class CodeJobs extends core_1.Command {
18
+ static description = 'Jobs running on a Hosted Job Machine';
19
+ static examples = [
20
+ '<%= config.bin %> code jobs run --to "Analyst" --prompt "..." --wait',
21
+ '<%= config.bin %> code jobs list',
22
+ '<%= config.bin %> code jobs show <job-id>',
23
+ '<%= config.bin %> code jobs cancel <job-id>',
24
+ '<%= config.bin %> code jobs approve <job-id>',
25
+ ];
26
+ async run() {
27
+ this.log('Hosted Job Machine job commands:');
28
+ this.log(' skrr code jobs run run a prompt on a fresh machine, no repo');
29
+ this.log(' skrr code jobs list list your jobs, newest first');
30
+ this.log(' skrr code jobs show show one job and its timeline');
31
+ this.log(' skrr code jobs cancel stop a job and its billing');
32
+ this.log(' skrr code jobs approve land the pull request a repo job opened');
33
+ this.log('');
34
+ this.log('`run` needs no repository. For a job that clones a repo and opens a');
35
+ this.log('pull request, use `skrr code handover`.');
36
+ }
37
+ }
38
+ exports.default = CodeJobs;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ export default class CodeJobsList extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
7
+ active: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
+ const base_command_1 = require("../../../base-command");
6
+ const format_1 = require("../../../lib/format");
7
+ /** Terminal states — a job here is no longer holding a machine or billing. */
8
+ const TERMINAL = new Set(['completed', 'failed', 'cancelled', 'timed_out']);
9
+ /** Cents are the server's unit for money everywhere else; jobs report dollars. */
10
+ function costCell(task) {
11
+ const raw = task.costUsd;
12
+ if (typeof raw !== 'number' || !Number.isFinite(raw))
13
+ return '-';
14
+ return `$${raw.toFixed(2)}`;
15
+ }
16
+ class CodeJobsList extends base_command_1.BaseCommand {
17
+ static description = 'List your Hosted Job Machine jobs, newest first';
18
+ static examples = [
19
+ '<%= config.bin %> code jobs list',
20
+ '<%= config.bin %> code jobs list --active',
21
+ '<%= config.bin %> code jobs list --status running --limit 5',
22
+ '<%= config.bin %> code jobs list --json',
23
+ ];
24
+ static flags = {
25
+ status: core_1.Flags.string({
26
+ description: 'Filter by one exact status (e.g. running, failed, completed)',
27
+ }),
28
+ // The question an operator actually opens this with is "what is costing me
29
+ // money right now", and the server has no such filter -- it takes one exact
30
+ // status. Filtering client-side is honest here because the page is already
31
+ // bounded by --limit.
32
+ active: core_1.Flags.boolean({
33
+ description: 'Show only jobs that are still running (and still billing)',
34
+ default: false,
35
+ exclusive: ['status'],
36
+ }),
37
+ limit: core_1.Flags.integer({ description: 'How many to return (1-100, default 20)' }),
38
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
39
+ };
40
+ async run() {
41
+ this.requireAuth();
42
+ const { flags } = await this.parse(CodeJobsList);
43
+ let tasks = [];
44
+ try {
45
+ const res = await data_provider_1.dataService.listCloudCodingTasks({
46
+ ...(flags.status ? { status: flags.status } : {}),
47
+ ...(flags.limit ? { limit: flags.limit } : {}),
48
+ });
49
+ tasks = res?.data ?? [];
50
+ }
51
+ catch (err) {
52
+ this.handleApiError(err);
53
+ }
54
+ if (flags.active) {
55
+ tasks = tasks.filter((t) => !TERMINAL.has(String(t.status)));
56
+ }
57
+ if (flags.json) {
58
+ this.log(JSON.stringify(tasks, null, 2));
59
+ return;
60
+ }
61
+ if (tasks.length === 0) {
62
+ // Say what empty MEANS. With --active it is the reassuring answer, not an
63
+ // empty query: nothing is running, so nothing is being billed.
64
+ this.log(flags.active
65
+ ? 'No jobs running — nothing is holding a Hosted Job Machine, and nothing is accruing.'
66
+ : 'No jobs. Start one with `skrr code jobs run`, or `skrr code handover`\n' +
67
+ 'for a job that clones a repository and opens a pull request.');
68
+ return;
69
+ }
70
+ (0, format_1.renderTable)(tasks.map((t) => ({
71
+ id: (0, format_1.formatCell)(t.id),
72
+ status: (0, format_1.formatCell)(t.status),
73
+ repo: (0, format_1.formatCell)(t.repoFullName),
74
+ cost: costCell(t),
75
+ created: (0, format_1.localStamp)(t.createdAt),
76
+ pr: (0, format_1.formatCell)(t.prUrl),
77
+ })), [
78
+ { key: 'id', header: 'JOB' },
79
+ { key: 'status', header: 'STATUS' },
80
+ { key: 'repo', header: 'REPO', maxWidth: 28 },
81
+ { key: 'cost', header: 'COST' },
82
+ { key: 'created', header: 'CREATED' },
83
+ { key: 'pr', header: 'PR', maxWidth: 40 },
84
+ ], (line) => this.log(line));
85
+ }
86
+ }
87
+ exports.default = CodeJobsList;
@@ -0,0 +1,32 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ /**
3
+ * `skrr code jobs run` — one-shot managed compute with no repository.
4
+ *
5
+ * OSK-7806. The sibling `skrr code handover` clones a GitHub repo, works it and
6
+ * opens a pull request. This runs the same Hosted Job Machine with no repo at
7
+ * all: a prompt in, a recorded result out, teardown. It is the shape for work
8
+ * that is not a code change — process some data, call an API, check something
9
+ * on a machine that is not yours and does not persist.
10
+ *
11
+ * Egress defaults to `isolated`: the control plane and nothing else. That is
12
+ * deliberate and worth knowing before you reach for `--egress`. The repository
13
+ * requirement used to be an abuse gate — burning managed compute meant first
14
+ * installing the GitHub App on a repo you own — and a job that needs no repo
15
+ * has no such gate, so its default reach must be the narrowest one that works.
16
+ */
17
+ export default class CodeJobsRun extends BaseCommand {
18
+ static description: string;
19
+ static examples: string[];
20
+ static flags: {
21
+ to: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ prompt: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ 'prompt-file': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ egress: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ wait: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
26
+ interval: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
27
+ timeout: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
28
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
29
+ };
30
+ private sleep;
31
+ run(): Promise<void>;
32
+ }
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const node_fs_1 = require("node:fs");
5
+ const node_crypto_1 = require("node:crypto");
6
+ const data_provider_1 = require("@skrr-ai/data-provider");
7
+ const base_command_1 = require("../../../base-command");
8
+ const code_handover_1 = require("../../../lib/code-handover");
9
+ const TERMINAL = new Set(['completed', 'failed', 'cancelled', 'timed_out']);
10
+ /**
11
+ * `skrr code jobs run` — one-shot managed compute with no repository.
12
+ *
13
+ * OSK-7806. The sibling `skrr code handover` clones a GitHub repo, works it and
14
+ * opens a pull request. This runs the same Hosted Job Machine with no repo at
15
+ * all: a prompt in, a recorded result out, teardown. It is the shape for work
16
+ * that is not a code change — process some data, call an API, check something
17
+ * on a machine that is not yours and does not persist.
18
+ *
19
+ * Egress defaults to `isolated`: the control plane and nothing else. That is
20
+ * deliberate and worth knowing before you reach for `--egress`. The repository
21
+ * requirement used to be an abuse gate — burning managed compute meant first
22
+ * installing the GitHub App on a repo you own — and a job that needs no repo
23
+ * has no such gate, so its default reach must be the narrowest one that works.
24
+ */
25
+ class CodeJobsRun extends base_command_1.BaseCommand {
26
+ static description = 'Run a prompt on a one-shot Hosted Job Machine, with no repository';
27
+ static examples = [
28
+ '<%= config.bin %> code jobs run --to "Analyst" --prompt "summarise the attached figures" --wait',
29
+ '<%= config.bin %> code jobs run --to agent_abc --prompt-file ./brief.md',
30
+ '<%= config.bin %> code jobs run --to agent_abc --prompt "fetch and chart" --egress allowlist --json',
31
+ ];
32
+ static flags = {
33
+ to: core_1.Flags.string({ description: 'Agent that runs the job — id or name', required: true }),
34
+ prompt: core_1.Flags.string({ description: 'What the agent should do', exclusive: ['prompt-file'] }),
35
+ 'prompt-file': core_1.Flags.string({
36
+ description: 'Read the prompt from a file (for prompts too long to type)',
37
+ exclusive: ['prompt'],
38
+ }),
39
+ egress: core_1.Flags.string({
40
+ description: 'Network reach. Default `isolated` — the control plane only, nothing else.',
41
+ options: ['isolated', 'allowlist', 'open'],
42
+ }),
43
+ wait: core_1.Flags.boolean({ description: 'Wait for the job to finish and print its result' }),
44
+ interval: core_1.Flags.integer({ description: 'Poll interval in seconds while waiting', default: 5 }),
45
+ timeout: core_1.Flags.integer({ description: 'Give up waiting after this many minutes', default: 30 }),
46
+ json: core_1.Flags.boolean({ description: 'Output the task as JSON' }),
47
+ };
48
+ async sleep(ms) {
49
+ return new Promise((resolve) => setTimeout(resolve, ms));
50
+ }
51
+ async run() {
52
+ this.requireAuth();
53
+ const { flags } = await this.parse(CodeJobsRun);
54
+ let prompt = flags.prompt ?? '';
55
+ if (flags['prompt-file']) {
56
+ try {
57
+ prompt = (0, node_fs_1.readFileSync)(flags['prompt-file'], 'utf8');
58
+ }
59
+ catch (err) {
60
+ this.error(`Could not read --prompt-file: ${err.message}`);
61
+ }
62
+ }
63
+ if (!prompt.trim()) {
64
+ this.error('A prompt is required — pass --prompt or --prompt-file.');
65
+ }
66
+ let agents = [];
67
+ try {
68
+ const resp = await data_provider_1.dataService.listAgents({ requiredPermission: data_provider_1.PermissionBits.VIEW });
69
+ agents = (resp?.data ?? []).filter(Boolean);
70
+ }
71
+ catch (err) {
72
+ this.handleApiError(err);
73
+ }
74
+ const matched = (0, code_handover_1.matchAgent)(flags.to, agents);
75
+ if (matched.kind === 'none') {
76
+ this.error(`No agent matches "${flags.to}". Run \`skrr agents list\` to see the agents you can use.`);
77
+ }
78
+ if (matched.kind === 'ambiguous') {
79
+ this.error(`"${flags.to}" matches ${matched.candidates.length} agents. Pass the agent id instead:\n` +
80
+ matched.candidates.map((a) => ` ${a.id} ${a.name ?? ''}`).join('\n'));
81
+ }
82
+ const target = matched.agent;
83
+ let task;
84
+ try {
85
+ const res = await data_provider_1.dataService.createCloudCodingTask({
86
+ agentId: target.id,
87
+ prompt,
88
+ mode: 'bare',
89
+ machineProduct: 'hosted-job-machine',
90
+ ...(flags.egress ? { egressPolicy: flags.egress } : {}),
91
+ clientRequestId: (0, node_crypto_1.randomUUID)(),
92
+ });
93
+ task = res?.task;
94
+ }
95
+ catch (err) {
96
+ this.handleApiError(err);
97
+ }
98
+ const jobId = String(task?.id ?? '');
99
+ if (!flags.wait) {
100
+ if (flags.json) {
101
+ this.log(JSON.stringify(task, null, 2));
102
+ return;
103
+ }
104
+ this.log(`Job ${jobId} ${task?.status ?? 'queued'} on ${target.name ?? target.id}`);
105
+ this.log(` ${this.config.bin} code jobs show ${jobId}`);
106
+ // It bills from here. Say the stop verb at the moment the spending starts,
107
+ // not only in the docs for a command they may never open.
108
+ this.log(` ${this.config.bin} code jobs cancel ${jobId} (it bills while it runs)`);
109
+ return;
110
+ }
111
+ const deadline = Date.now() + flags.timeout * 60_000;
112
+ let current = task;
113
+ while (!TERMINAL.has(String(current?.status)) && Date.now() < deadline) {
114
+ await this.sleep(Math.max(1, flags.interval) * 1000);
115
+ try {
116
+ current = (await data_provider_1.dataService.getCloudCodingTask(jobId))?.task;
117
+ }
118
+ catch (err) {
119
+ this.handleApiError(err);
120
+ }
121
+ }
122
+ if (flags.json) {
123
+ this.log(JSON.stringify(current, null, 2));
124
+ return;
125
+ }
126
+ if (!TERMINAL.has(String(current?.status))) {
127
+ // A timed-out WAIT is not a timed-out job. The job is still running and
128
+ // still billing, so say which of the two happened and how to stop it.
129
+ this.log(`Still ${current?.status ?? 'running'} after ${flags.timeout}m — the job continues.`);
130
+ this.log(` ${this.config.bin} code jobs show ${jobId}`);
131
+ this.log(` ${this.config.bin} code jobs cancel ${jobId}`);
132
+ return;
133
+ }
134
+ this.log(`Job ${jobId} ${current?.status}`);
135
+ const result = current?.result;
136
+ if (result?.text) {
137
+ this.log('');
138
+ this.log(result.text);
139
+ if (result.truncated) {
140
+ this.log('');
141
+ this.log(`[truncated — ${result.bytes} bytes produced; full record in --json]`);
142
+ }
143
+ }
144
+ const error = current?.error;
145
+ if (error?.code || error?.message) {
146
+ this.log('');
147
+ this.log(`Error: ${[error.code, error.message].filter(Boolean).join(': ')}`);
148
+ }
149
+ }
150
+ }
151
+ exports.default = CodeJobsRun;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ export default class CodeJobsShow extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ job: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
+ const base_command_1 = require("../../../base-command");
6
+ const format_1 = require("../../../lib/format");
7
+ const TERMINAL = new Set(['completed', 'failed', 'cancelled', 'timed_out']);
8
+ class CodeJobsShow extends base_command_1.BaseCommand {
9
+ static description = 'Show one Hosted Job Machine job and its timeline';
10
+ static examples = [
11
+ '<%= config.bin %> code jobs show <job-id>',
12
+ '<%= config.bin %> code jobs show <job-id> --json',
13
+ ];
14
+ static args = {
15
+ job: core_1.Args.string({ description: 'Job id', required: true, ignoreStdin: true }),
16
+ };
17
+ static flags = { json: core_1.Flags.boolean({ description: 'Output as JSON' }) };
18
+ async run() {
19
+ this.requireAuth();
20
+ const { args, flags } = await this.parse(CodeJobsShow);
21
+ let task;
22
+ try {
23
+ const res = await data_provider_1.dataService.getCloudCodingTask(args.job);
24
+ task = res?.task;
25
+ }
26
+ catch (err) {
27
+ this.handleApiError(err);
28
+ }
29
+ if (flags.json) {
30
+ this.log(JSON.stringify(task, null, 2));
31
+ return;
32
+ }
33
+ if (!task) {
34
+ this.log('Job not found.');
35
+ return;
36
+ }
37
+ const line = (label, value) => {
38
+ if (value === undefined || value === null || value === '')
39
+ return;
40
+ this.log(`${label.padEnd(14)}${String(value)}`);
41
+ };
42
+ line('ID:', task.id);
43
+ line('Status:', task.status);
44
+ line('Agent:', task.agentId);
45
+ if (task.repoFullName) {
46
+ line('Repo:', `${task.repoFullName}@${task.baseBranch ?? 'main'}`);
47
+ }
48
+ line('Work branch:', task.workBranch);
49
+ line('Machine:', task.machineProductLabel ?? task.machineProduct);
50
+ line('Lease:', task.machineLeaseId);
51
+ line('Model:', task.model);
52
+ if (typeof task.costUsd === 'number')
53
+ line('Cost:', `$${task.costUsd.toFixed(2)}`);
54
+ line('PR:', task.prUrl);
55
+ line('Preview:', task.previewUrl);
56
+ line('Created:', (0, format_1.localStamp)(task.createdAt));
57
+ const error = task.error;
58
+ if (error?.code || error?.message) {
59
+ line('Error:', [error.code, error.message].filter(Boolean).join(': '));
60
+ }
61
+ // The timeline is the closest thing to a log this surface has: the task
62
+ // persists its state transitions but not the agent's transcript, so this is
63
+ // where "what happened, and where did it stop" is answerable at all.
64
+ const timeline = Array.isArray(task.timeline) ? task.timeline : [];
65
+ if (timeline.length > 0) {
66
+ this.log('');
67
+ this.log('Timeline');
68
+ for (const entry of timeline) {
69
+ const at = entry.at ? (0, format_1.localStamp)(entry.at) : '-';
70
+ const took = typeof entry.durationMs === 'number' ? ` (${Math.round(entry.durationMs / 1000)}s)` : '';
71
+ const note = entry.note ? ` ${entry.note}` : '';
72
+ this.log(` ${at} ${String(entry.state ?? '-').padEnd(14)}${took}${note}`);
73
+ }
74
+ }
75
+ // A non-terminal job is still holding a machine. Say so, and say the verb —
76
+ // this is the whole reason the cancel binding exists.
77
+ if (!TERMINAL.has(String(task.status))) {
78
+ this.log('');
79
+ this.log(`Still running — it holds a machine and is billing. Stop it with:`);
80
+ this.log(` ${this.config.bin} code jobs cancel ${task.id}`);
81
+ }
82
+ this.log('');
83
+ this.log('Full record: --json');
84
+ }
85
+ }
86
+ exports.default = CodeJobsShow;
@@ -62,6 +62,7 @@ export default class CommitmentsCreate extends BaseCommand {
62
62
  measure: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
63
63
  source: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
64
64
  watch: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
65
+ 'github-event': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
65
66
  'metric-key': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
66
67
  'watch-space': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
67
68
  'watch-monitor': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -13,6 +13,15 @@ const commitment_product_1 = require("../../lib/commitment-product");
13
13
  const commitments_1 = require("../../lib/commitments");
14
14
  const DEFAULT_EVENT_DRIVEN_BACKSTOP_MS = 24 * 60 * 60 * 1000;
15
15
  const DEFAULT_EVENT_SOURCES = new Set(['github', 'slack', 'email', 'calendar']);
16
+ const GITHUB_EVENT_OPTIONS = [
17
+ 'pull_request_opened',
18
+ 'pull_request_merged',
19
+ 'review_requested',
20
+ 'check_run_failed',
21
+ 'check_run_succeeded',
22
+ 'issue_opened',
23
+ 'comment_created',
24
+ ];
16
25
  function record(value) {
17
26
  return value && typeof value === 'object' && !Array.isArray(value)
18
27
  ? value
@@ -66,7 +75,7 @@ function hasEventCapableWatchedSource(payload) {
66
75
  return Array.isArray(config?.events) ? hasStructurallyValidExplicitEvent(config) : true;
67
76
  }
68
77
  if (source === 'tasks') {
69
- return (goalId || configuredId(config, 'taskId', 'goalId', 'keyResultId'));
78
+ return goalId || configuredId(config, 'taskId', 'goalId', 'keyResultId');
70
79
  }
71
80
  if (source === 'goal') {
72
81
  return goalId || configuredId(config, 'goalId', 'keyResultId');
@@ -113,9 +122,7 @@ function createCadenceFromFlags({ eventDriven, cadence: cadenceInput, cadenceMod
113
122
  }
114
123
  return {
115
124
  mode: 'event_plus_interval',
116
- intervalMs: cadenceInput
117
- ? (0, commitments_1.parseIntervalToMs)(cadenceInput)
118
- : DEFAULT_EVENT_DRIVEN_BACKSTOP_MS,
125
+ intervalMs: cadenceInput ? (0, commitments_1.parseIntervalToMs)(cadenceInput) : DEFAULT_EVENT_DRIVEN_BACKSTOP_MS,
119
126
  ...(timezone ? { timezone } : {}),
120
127
  };
121
128
  }
@@ -180,7 +187,7 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
180
187
  '<%= config.bin %> commitments create --agent <agent-id> --title "SLA" --outcome "p95 under 200ms" --criterion "p95 latency confirmed" --evaluator metric --measure <measure-id>',
181
188
  '<%= config.bin %> commitments create --agent <agent-id> --title "AWS cost watch" --outcome "Cost regressions are investigated" --agent-directive-file ./aws-cost-policy.md',
182
189
  '<%= config.bin %> commitments create --from-json commitment.json --json',
183
- '<%= config.bin %> commitments create --agent <agent-id> --title "Keep CI healthy" --outcome "Failed checks are repaired" --watch github --event-driven --mode execute --delivery draft-pr --repo owner/repo --base main --status draft',
190
+ '<%= config.bin %> commitments create --agent <agent-id> --title "Keep CI healthy" --outcome "Failed checks are repaired" --watch github --github-event check_run_failed --event-driven --mode execute --delivery draft-pr --repo owner/repo --base main --status draft',
184
191
  ];
185
192
  static flags = {
186
193
  json: core_1.Flags.boolean({ description: 'Output the created commitment as JSON' }),
@@ -228,6 +235,11 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
228
235
  multiple: true,
229
236
  options: [...commitments_1.COMMITMENT_WATCHED_SOURCES],
230
237
  }),
238
+ 'github-event': core_1.Flags.string({
239
+ description: 'GitHub event to watch (repeatable; implies --watch github). Use check_run_failed for CI remediation.',
240
+ multiple: true,
241
+ options: [...GITHUB_EVENT_OPTIONS],
242
+ }),
231
243
  'metric-key': core_1.Flags.string({
232
244
  description: 'Metric key to read when --watch metrics is used (repeatable)',
233
245
  multiple: true,
@@ -360,6 +372,8 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
360
372
  metricKey: (0, triggers_1.splitRepeated)(flags['metric-key']),
361
373
  spaceIds: resolvedSpaceIds,
362
374
  monitorIds: (0, triggers_1.splitRepeated)(flags['watch-monitor']),
375
+ githubEvents: (0, triggers_1.splitRepeated)(flags['github-event']),
376
+ githubRepository: flags.repo,
363
377
  });
364
378
  if (built)
365
379
  payload.watchedSources = built;
@@ -24,12 +24,26 @@ const prompt_1 = require("../../lib/prompt");
24
24
  */
25
25
  function preflightGateLines(gate, verbose = false) {
26
26
  const mark = gate.verdict === 'pass' ? 'ok' : gate.verdict === 'block' ? 'BLOCK' : 'warn';
27
+ // A BLOCKING gate always states its reason. `ok` gates got a helpful `note`
28
+ // and `warn` gates got a reason token, and the BLOCK gates — the only ones
29
+ // that stop the run — got the label and nothing: two of them side by side,
30
+ // one meaning "still a draft" (completely benign) and one meaning "this
31
+ // runtime cannot enforce the contract", rendered identically. The reasons
32
+ // were in the `--json` payload the whole time; the plain renderer just
33
+ // dropped `reason` for exactly the verdict that needs it (OSK-7700).
34
+ //
35
+ // A gate that HAS a note keeps the reason behind `--verbose`, because the
36
+ // note is the same fact in words a reader can act on and the token beside it
37
+ // is then just noise: "Will the platform wake it? — status_paused" above
38
+ // "Resume it first." says one thing twice, in two vocabularies.
39
+ const note = gate.detail?.note;
40
+ const hasNote = typeof note === 'string' && Boolean(note.trim());
41
+ const showReason = verbose || (gate.verdict === 'block' && !hasNote);
27
42
  const lines = [
28
- ` ${mark.padEnd(5)} ${gate.label}${verbose && gate.reason ? ` — ${gate.reason}` : ''}`,
43
+ ` ${mark.padEnd(5)} ${gate.label}${showReason && gate.reason ? ` — ${gate.reason}` : ''}`,
29
44
  ];
30
- const note = gate.detail?.note;
31
- if (typeof note === 'string' && note.trim()) {
32
- lines.push(` ${note.trim()}`);
45
+ if (hasNote) {
46
+ lines.push(` ${String(note).trim()}`);
33
47
  }
34
48
  // `detail.hint` is the actionable plain-words sentence — why the gate is
35
49
  // capped and the exact command to lift it. It lived only in --json, so the
@@ -0,0 +1,39 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * The quarter to report when the caller names none.
4
+ *
5
+ * Computed in **UTC**, deliberately. The server buckets a quarter on UTC
6
+ * boundaries, so a local-time computation would disagree with it for a few
7
+ * hours either side of a quarter change — `skrr` would ask for Q3 and the
8
+ * server would answer about the Q4 it thinks we are in. Same clock, no seam.
9
+ *
10
+ * The previous calendar quarter is always closed, which is the cohort this
11
+ * endpoint reports on (`scope: 'closed_quarter'`); the current one is not, so
12
+ * it is never a safe default.
13
+ */
14
+ export declare function previousClosedQuarter(now?: Date): {
15
+ year: number;
16
+ quarter: number;
17
+ };
18
+ /**
19
+ * `skrr commitments receipt-metrics <id>` — the closed-quarter rollup behind
20
+ * `commitments receipt`.
21
+ *
22
+ * `receipt` explains ONE wake. This aggregates a whole closed quarter, which is
23
+ * the window you need to answer "is this commitment actually delivering" rather
24
+ * than "what happened last night".
25
+ */
26
+ export default class CommitmentsReceiptMetrics extends BaseCommand {
27
+ static description: string;
28
+ static examples: string[];
29
+ static args: {
30
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
31
+ };
32
+ static flags: {
33
+ year: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
34
+ quarter: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
35
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
36
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
37
+ };
38
+ run(): Promise<void>;
39
+ }