@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.
- package/README.md +83 -73
- package/bin/dev-fallback.js +221 -0
- package/bin/run.js +43 -0
- package/dist/base-command.d.ts +15 -0
- package/dist/base-command.js +71 -10
- package/dist/commands/agents/attach-harness.d.ts +37 -0
- package/dist/commands/agents/attach-harness.js +102 -3
- package/dist/commands/agents/chat.d.ts +69 -1
- package/dist/commands/agents/chat.js +202 -22
- package/dist/commands/agents/create.d.ts +38 -0
- package/dist/commands/agents/create.js +95 -2
- package/dist/commands/agents/schedule-trace.js +11 -0
- package/dist/commands/agents/show.js +29 -1
- package/dist/commands/api-keys/create.d.ts +24 -0
- package/dist/commands/api-keys/create.js +80 -0
- package/dist/commands/api-keys/list.d.ts +11 -0
- package/dist/commands/api-keys/list.js +42 -0
- package/dist/commands/api-keys/revoke.d.ts +14 -0
- package/dist/commands/api-keys/revoke.js +33 -0
- package/dist/commands/api-keys/rotate.d.ts +19 -0
- package/dist/commands/api-keys/rotate.js +42 -0
- package/dist/commands/balance/index.d.ts +18 -0
- package/dist/commands/balance/index.js +29 -0
- package/dist/commands/balance/show.d.ts +25 -0
- package/dist/commands/balance/show.js +60 -0
- package/dist/commands/balance/statement.d.ts +19 -0
- package/dist/commands/balance/statement.js +52 -0
- package/dist/commands/browser/doctor.d.ts +11 -0
- package/dist/commands/browser/doctor.js +11 -0
- package/dist/commands/code/jobs/approve.d.ts +25 -0
- package/dist/commands/code/jobs/approve.js +52 -0
- package/dist/commands/code/jobs/cancel.d.ts +12 -0
- package/dist/commands/code/jobs/cancel.js +39 -0
- package/dist/commands/code/jobs/index.d.ts +19 -0
- package/dist/commands/code/jobs/index.js +38 -0
- package/dist/commands/code/jobs/list.d.ts +12 -0
- package/dist/commands/code/jobs/list.js +87 -0
- package/dist/commands/code/jobs/run.d.ts +32 -0
- package/dist/commands/code/jobs/run.js +151 -0
- package/dist/commands/code/jobs/show.d.ts +12 -0
- package/dist/commands/code/jobs/show.js +86 -0
- package/dist/commands/commitments/create.d.ts +1 -0
- package/dist/commands/commitments/create.js +19 -5
- package/dist/commands/commitments/preflight.js +18 -4
- package/dist/commands/commitments/receipt-metrics.d.ts +39 -0
- package/dist/commands/commitments/receipt-metrics.js +78 -0
- package/dist/commands/convos/search.js +5 -5
- package/dist/commands/harnesses/leases/list.d.ts +3 -0
- package/dist/commands/harnesses/leases/list.js +59 -12
- package/dist/commands/harnesses/leases/show.js +36 -0
- package/dist/commands/harnesses/list.d.ts +18 -0
- package/dist/commands/harnesses/list.js +30 -0
- package/dist/commands/harnesses/products.js +48 -3
- package/dist/commands/harnesses/quota.d.ts +16 -0
- package/dist/commands/harnesses/quota.js +26 -1
- package/dist/commands/harnesses/usage.js +17 -0
- package/dist/commands/inbox/index.d.ts +2 -1
- package/dist/commands/inbox/index.js +27 -4
- package/dist/commands/login.js +4 -1
- package/dist/commands/machines/list.d.ts +1 -0
- package/dist/commands/machines/list.js +33 -5
- package/dist/commands/memory/approvals/issue.d.ts +18 -0
- package/dist/commands/memory/approvals/issue.js +63 -0
- package/dist/commands/memory/commit.js +5 -2
- package/dist/commands/memory/context.d.ts +3 -2
- package/dist/commands/memory/context.js +9 -11
- package/dist/commands/memory/delete.d.ts +1 -1
- package/dist/commands/memory/list.d.ts +1 -1
- package/dist/commands/memory/list.js +1 -1
- package/dist/commands/memory/mounts/resolve.d.ts +10 -0
- package/dist/commands/memory/mounts/resolve.js +27 -0
- package/dist/commands/memory/proposals/commit.d.ts +18 -0
- package/dist/commands/memory/proposals/commit.js +32 -0
- package/dist/commands/memory/proposals/create.d.ts +18 -0
- package/dist/commands/memory/proposals/create.js +56 -0
- package/dist/commands/memory/proposals/list.d.ts +13 -0
- package/dist/commands/memory/proposals/list.js +31 -0
- package/dist/commands/memory/proposals/promote.d.ts +22 -0
- package/dist/commands/memory/proposals/promote.js +33 -0
- package/dist/commands/memory/proposals/reject.d.ts +16 -0
- package/dist/commands/memory/proposals/reject.js +28 -0
- package/dist/commands/memory/rebuild-index.d.ts +20 -0
- package/dist/commands/memory/rebuild-index.js +25 -0
- package/dist/commands/memory/save.d.ts +1 -1
- package/dist/commands/memory/save.js +1 -1
- package/dist/commands/memory/search.d.ts +6 -3
- package/dist/commands/memory/search.js +27 -3
- package/dist/commands/memory/show.d.ts +1 -1
- package/dist/commands/memory/stores/archive.d.ts +14 -0
- package/dist/commands/memory/stores/archive.js +31 -0
- package/dist/commands/memory/stores/create.d.ts +12 -0
- package/dist/commands/memory/stores/create.js +30 -0
- package/dist/commands/memory/stores/delete.d.ts +15 -0
- package/dist/commands/memory/stores/delete.js +38 -0
- package/dist/commands/memory/stores/list.d.ts +10 -0
- package/dist/commands/memory/stores/list.js +29 -0
- package/dist/commands/memory/stores/show.d.ts +12 -0
- package/dist/commands/memory/stores/show.js +14 -0
- package/dist/commands/memory/stores/update.d.ts +15 -0
- package/dist/commands/memory/stores/update.js +39 -0
- package/dist/commands/memory/sync/delete.d.ts +13 -0
- package/dist/commands/memory/sync/delete.js +35 -0
- package/dist/commands/memory/sync/pull.d.ts +19 -0
- package/dist/commands/memory/sync/pull.js +52 -0
- package/dist/commands/memory/sync/push.d.ts +18 -0
- package/dist/commands/memory/sync/push.js +115 -0
- package/dist/commands/memory/sync/resolve.d.ts +23 -0
- package/dist/commands/memory/sync/resolve.js +27 -0
- package/dist/commands/memory/sync/status.d.ts +9 -0
- package/dist/commands/memory/sync/status.js +22 -0
- package/dist/commands/memory/topics/archive.d.ts +20 -0
- package/dist/commands/memory/topics/archive.js +29 -0
- package/dist/commands/memory/topics/create.d.ts +23 -0
- package/dist/commands/memory/topics/create.js +46 -0
- package/dist/commands/memory/topics/delete.d.ts +22 -0
- package/dist/commands/memory/topics/delete.js +30 -0
- package/dist/commands/memory/topics/forget.d.ts +22 -0
- package/dist/commands/memory/topics/forget.js +29 -0
- package/dist/commands/memory/topics/list.d.ts +13 -0
- package/dist/commands/memory/topics/list.js +22 -0
- package/dist/commands/memory/topics/move.d.ts +22 -0
- package/dist/commands/memory/topics/move.js +26 -0
- package/dist/commands/memory/topics/show.d.ts +17 -0
- package/dist/commands/memory/topics/show.js +21 -0
- package/dist/commands/memory/topics/update.d.ts +23 -0
- package/dist/commands/memory/topics/update.js +27 -0
- package/dist/commands/memory/tree.d.ts +5 -2
- package/dist/commands/memory/tree.js +20 -2
- package/dist/commands/memory/update.d.ts +1 -1
- package/dist/commands/memory/versions/list.d.ts +16 -0
- package/dist/commands/memory/versions/list.js +22 -0
- package/dist/commands/memory/versions/redact.d.ts +21 -0
- package/dist/commands/memory/versions/redact.js +22 -0
- package/dist/commands/memory/versions/restore.d.ts +20 -0
- package/dist/commands/memory/versions/restore.js +16 -0
- package/dist/commands/memory/versions/show.d.ts +15 -0
- package/dist/commands/memory/versions/show.js +17 -0
- package/dist/commands/messages/list.js +25 -8
- package/dist/commands/messages/show.js +10 -0
- package/dist/commands/store/install.js +5 -1
- package/dist/commands/store/releases.js +1 -1
- package/dist/commands/store/update.js +5 -1
- package/dist/commands/subscriptions/cancel.js +5 -1
- package/dist/commands/subscriptions/health.js +5 -1
- package/dist/commands/subscriptions/status.js +5 -1
- package/dist/commands/subscriptions/subscribe.js +5 -1
- package/dist/commands/tasks/activity.d.ts +2 -3
- package/dist/commands/tasks/activity.js +15 -5
- package/dist/commands/tasks/complete.d.ts +18 -150
- package/dist/commands/tasks/complete.js +161 -600
- package/dist/commands/tasks/create.d.ts +5 -0
- package/dist/commands/tasks/create.js +107 -4
- package/dist/commands/tasks/deliverable/add.d.ts +8 -0
- package/dist/commands/tasks/deliverable/add.js +41 -8
- package/dist/commands/tasks/deliverable/confirm.d.ts +5 -5
- package/dist/commands/tasks/deliverable/confirm.js +9 -18
- package/dist/commands/tasks/deliverable/list.d.ts +12 -0
- package/dist/commands/tasks/deliverable/list.js +37 -0
- package/dist/commands/tasks/events/append.d.ts +2 -0
- package/dist/commands/tasks/events/append.js +11 -4
- package/dist/commands/tasks/events/list.d.ts +1 -0
- package/dist/commands/tasks/events/list.js +1 -0
- package/dist/commands/tasks/events/tail.d.ts +1 -0
- package/dist/commands/tasks/events/tail.js +1 -0
- package/dist/commands/tasks/expectations/assess.d.ts +21 -0
- package/dist/commands/tasks/expectations/assess.js +77 -0
- package/dist/commands/tasks/expectations.js +14 -18
- package/dist/commands/tasks/judge.d.ts +1 -0
- package/dist/commands/tasks/judge.js +2 -1
- package/dist/commands/tasks/output.d.ts +2 -11
- package/dist/commands/tasks/output.js +64 -145
- package/dist/commands/tasks/report.d.ts +3 -3
- package/dist/commands/tasks/report.js +64 -41
- package/dist/commands/tasks/resource/add.d.ts +23 -0
- package/dist/commands/tasks/resource/add.js +76 -0
- package/dist/commands/tasks/resource/list.d.ts +13 -0
- package/dist/commands/tasks/resource/list.js +41 -0
- package/dist/commands/tasks/result/show.d.ts +13 -0
- package/dist/commands/tasks/result/show.js +46 -0
- package/dist/commands/tasks/result/submit.d.ts +26 -0
- package/dist/commands/tasks/result/submit.js +134 -0
- package/dist/commands/tasks/resume/save.d.ts +16 -0
- package/dist/commands/tasks/resume/save.js +59 -0
- package/dist/commands/tasks/resume/show.d.ts +13 -0
- package/dist/commands/tasks/resume/show.js +35 -0
- package/dist/commands/tasks/review.d.ts +17 -0
- package/dist/commands/tasks/review.js +54 -0
- package/dist/commands/tasks/runs.js +5 -0
- package/dist/commands/tasks/timeline.d.ts +2 -2
- package/dist/commands/tasks/timeline.js +10 -23
- package/dist/commands/tasks/updates/add.d.ts +22 -0
- package/dist/commands/tasks/updates/add.js +101 -0
- package/dist/commands/tasks/updates/list.d.ts +15 -0
- package/dist/commands/tasks/updates/list.js +57 -0
- package/dist/commands/tasks/waive.d.ts +1 -0
- package/dist/commands/tasks/waive.js +2 -1
- package/dist/lib/agentic-stream.d.ts +257 -0
- package/dist/lib/agentic-stream.js +490 -33
- package/dist/lib/balance.d.ts +8 -0
- package/dist/lib/commitment-product.d.ts +10 -1
- package/dist/lib/commitment-product.js +66 -2
- package/dist/lib/commitments.d.ts +4 -1
- package/dist/lib/commitments.js +32 -1
- package/dist/lib/conversation-search.d.ts +3 -0
- package/dist/lib/conversation-search.js +75 -0
- package/dist/lib/execution-target.d.ts +21 -0
- package/dist/lib/execution-target.js +22 -6
- package/dist/lib/harnesses.d.ts +82 -6
- package/dist/lib/harnesses.js +30 -2
- package/dist/lib/hosted-machines.js +9 -0
- package/dist/lib/inbox.d.ts +2 -1
- package/dist/lib/machines.d.ts +17 -0
- package/dist/lib/machines.js +29 -0
- package/dist/lib/managed-agent-keys.d.ts +104 -0
- package/dist/lib/managed-agent-keys.js +50 -0
- package/dist/lib/memory-scope.d.ts +4 -3
- package/dist/lib/memory-scope.js +9 -9
- package/dist/lib/memory-sync.d.ts +114 -0
- package/dist/lib/memory-sync.js +730 -0
- package/dist/lib/message-provenance.d.ts +42 -0
- package/dist/lib/message-provenance.js +89 -0
- package/dist/lib/scoped-memory-command.d.ts +68 -0
- package/dist/lib/scoped-memory-command.js +183 -0
- package/dist/lib/session-task-endpoints.d.ts +1 -1
- package/dist/lib/session-task-endpoints.js +7 -0
- package/dist/lib/sky-code-broker.d.ts +47 -0
- package/dist/lib/sky-code-broker.js +50 -0
- package/dist/lib/sky-code-doctor.js +10 -1
- package/dist/lib/task-artifact-flags.d.ts +2 -0
- package/dist/lib/task-artifact-flags.js +7 -0
- package/dist/lib/task-execution.d.ts +4 -5
- package/dist/lib/task-execution.js +4 -5
- package/dist/lib/task-extras.d.ts +1 -5
- package/dist/lib/task-extras.js +1 -5
- package/dist/lib/task-transcript.d.ts +5 -7
- package/dist/lib/task-transcript.js +8 -16
- package/dist/lib/tasks.d.ts +7 -21
- package/dist/lib/tasks.js +17 -20
- package/dist/lib/triggers.d.ts +39 -1
- package/dist/lib/triggers.js +70 -2
- package/dist/lib/usage-discovery.d.ts +17 -1
- package/dist/lib/usage-discovery.js +17 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3733 -3618
- package/oclif.manifest.json +25726 -19886
- 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
|
|
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}${
|
|
43
|
+
` ${mark.padEnd(5)} ${gate.label}${showReason && gate.reason ? ` — ${gate.reason}` : ''}`,
|
|
29
44
|
];
|
|
30
|
-
|
|
31
|
-
|
|
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
|
+
}
|