@skrr-ai/cli 0.1.14 → 0.1.17
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 +3 -0
- package/dist/base-command.d.ts +14 -0
- package/dist/base-command.js +60 -1
- package/dist/commands/agents/create.d.ts +1 -0
- package/dist/commands/agents/create.js +6 -1
- package/dist/commands/agents/instructions/add.d.ts +21 -0
- package/dist/commands/agents/instructions/add.js +115 -0
- package/dist/commands/agents/instructions/disable.d.ts +13 -0
- package/dist/commands/agents/instructions/disable.js +50 -0
- package/dist/commands/agents/instructions/edit.d.ts +16 -0
- package/dist/commands/agents/instructions/edit.js +79 -0
- package/dist/commands/agents/instructions/enable.d.ts +13 -0
- package/dist/commands/agents/instructions/enable.js +50 -0
- package/dist/commands/agents/instructions/move.d.ts +15 -0
- package/dist/commands/agents/instructions/move.js +61 -0
- package/dist/commands/agents/instructions/preview.d.ts +13 -0
- package/dist/commands/agents/instructions/preview.js +59 -0
- package/dist/commands/agents/instructions/remove.d.ts +13 -0
- package/dist/commands/agents/instructions/remove.js +49 -0
- package/dist/commands/agents/instructions/set.d.ts +17 -0
- package/dist/commands/agents/instructions/set.js +79 -0
- package/dist/commands/agents/instructions/show.d.ts +15 -0
- package/dist/commands/agents/instructions/show.js +76 -0
- package/dist/commands/agents/instructions/upgrade.d.ts +16 -0
- package/dist/commands/agents/instructions/upgrade.js +77 -0
- package/dist/commands/agents/show.js +5 -0
- package/dist/commands/agents/triggers/policy.js +8 -2
- package/dist/commands/agents/update.d.ts +1 -0
- package/dist/commands/agents/update.js +8 -2
- package/dist/commands/commitments/autonomy.js +9 -1
- package/dist/commands/commitments/create.d.ts +8 -5
- package/dist/commands/commitments/create.js +38 -8
- package/dist/commands/commitments/doctor.d.ts +19 -0
- package/dist/commands/commitments/doctor.js +72 -0
- package/dist/commands/commitments/preflight.d.ts +3 -1
- package/dist/commands/commitments/preflight.js +25 -3
- package/dist/commands/commitments/reports.js +15 -2
- package/dist/commands/commitments/update.d.ts +9 -2
- package/dist/commands/commitments/update.js +36 -2
- package/dist/commands/daemon/index.js +2 -0
- package/dist/commands/daemon/recover-offline-queue.d.ts +9 -0
- package/dist/commands/daemon/recover-offline-queue.js +24 -0
- package/dist/commands/daemon/start.js +29 -1
- package/dist/commands/instruction-blocks/create.d.ts +19 -0
- package/dist/commands/instruction-blocks/create.js +94 -0
- package/dist/commands/instruction-blocks/delete.d.ts +13 -0
- package/dist/commands/instruction-blocks/delete.js +35 -0
- package/dist/commands/instruction-blocks/list.d.ts +13 -0
- package/dist/commands/instruction-blocks/list.js +71 -0
- package/dist/commands/instruction-blocks/show.d.ts +12 -0
- package/dist/commands/instruction-blocks/show.js +35 -0
- package/dist/commands/instruction-blocks/update.d.ts +23 -0
- package/dist/commands/instruction-blocks/update.js +94 -0
- package/dist/commands/spaces/auto-executor/preview.d.ts +1 -0
- package/dist/commands/spaces/auto-executor/preview.js +62 -3
- package/dist/commands/spaces/auto-executor/update.d.ts +4 -0
- package/dist/commands/spaces/auto-executor/update.js +78 -7
- package/dist/commands/spaces/capacity.js +14 -2
- package/dist/commands/spaces/update.d.ts +4 -0
- package/dist/commands/spaces/update.js +49 -2
- package/dist/commands/tasks/complete.d.ts +12 -5
- package/dist/commands/tasks/complete.js +107 -28
- package/dist/commands/tasks/continue-ready.js +9 -1
- package/dist/commands/tasks/create.d.ts +1 -0
- package/dist/commands/tasks/create.js +27 -2
- package/dist/commands/tasks/deliverable/add.d.ts +23 -0
- package/dist/commands/tasks/deliverable/add.js +70 -0
- package/dist/commands/tasks/deliverable/confirm.d.ts +35 -0
- package/dist/commands/tasks/deliverable/confirm.js +77 -0
- package/dist/commands/tasks/events/append.d.ts +1 -1
- package/dist/commands/tasks/events/append.js +4 -4
- package/dist/commands/tasks/expectations.d.ts +12 -0
- package/dist/commands/tasks/expectations.js +111 -0
- package/dist/commands/tasks/judge.d.ts +29 -0
- package/dist/commands/tasks/judge.js +68 -0
- package/dist/commands/tasks/report.d.ts +1 -1
- package/dist/commands/tasks/report.js +27 -3
- package/dist/commands/tasks/trust.d.ts +35 -0
- package/dist/commands/tasks/trust.js +75 -0
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +34 -4
- package/dist/commands/tasks/waive.d.ts +25 -0
- package/dist/commands/tasks/waive.js +58 -0
- package/dist/lib/agent-config.js +5 -0
- package/dist/lib/agent-instructions.d.ts +15 -0
- package/dist/lib/agent-instructions.js +55 -0
- package/dist/lib/command-hygiene.d.ts +6 -1
- package/dist/lib/command-hygiene.js +49 -29
- package/dist/lib/commitments.d.ts +28 -3
- package/dist/lib/commitments.js +20 -11
- package/dist/lib/exec-runtime-binary.d.ts +13 -0
- package/dist/lib/exec-runtime-binary.js +45 -0
- package/dist/lib/git-task.d.ts +37 -0
- package/dist/lib/git-task.js +151 -0
- package/dist/lib/instruction-blocks.d.ts +29 -0
- package/dist/lib/instruction-blocks.js +159 -0
- package/dist/lib/runtime-start-verification.d.ts +49 -0
- package/dist/lib/runtime-start-verification.js +108 -0
- package/dist/lib/task-execution.d.ts +18 -2
- package/dist/lib/task-execution.js +19 -14
- package/dist/lib/task-transcript.js +1 -1
- package/dist/lib/tasks.d.ts +50 -0
- package/dist/lib/tasks.js +93 -2
- package/dist/node_modules/@skrr-ai/data-provider/index.js +2393 -2197
- package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
- package/oclif.manifest.json +17725 -15563
- package/package.json +4 -1
|
@@ -8,11 +8,11 @@ const prompt_1 = require("../../lib/prompt");
|
|
|
8
8
|
const triggers_1 = require("../../lib/triggers");
|
|
9
9
|
const commitments_1 = require("../../lib/commitments");
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
* mode
|
|
13
|
-
*
|
|
14
|
-
* boundary; otherwise a successful create response
|
|
15
|
-
* autonomy is live when
|
|
11
|
+
* Creation preserves the policy its author wrote, so the mode that comes back
|
|
12
|
+
* is normally the mode that was asked for. When it is not — normalization
|
|
13
|
+
* rejected the value, or a governance layer sits lower — the difference has to
|
|
14
|
+
* be said out loud at the CLI boundary; otherwise a successful create response
|
|
15
|
+
* reads like the requested autonomy is live when something else is running.
|
|
16
16
|
*/
|
|
17
17
|
function autonomyStagingNotice({ payload, commitment, bin, }) {
|
|
18
18
|
const requestedPolicy = payload.policy && typeof payload.policy === 'object' && !Array.isArray(payload.policy)
|
|
@@ -27,8 +27,8 @@ function autonomyStagingNotice({ payload, commitment, bin, }) {
|
|
|
27
27
|
return undefined;
|
|
28
28
|
const id = typeof commitment.id === 'string' ? commitment.id : '<commitment-id>';
|
|
29
29
|
return [
|
|
30
|
-
`Requested autonomy ${requested} was
|
|
31
|
-
`To
|
|
30
|
+
`Requested autonomy ${requested} was not applied; this commitment is running as ${admitted || 'suggestions_only'}.`,
|
|
31
|
+
`To set it explicitly: ${bin} commitments autonomy ${id} --mode ${requested} --reason "<why this scope is safe>"`,
|
|
32
32
|
].join('\n');
|
|
33
33
|
}
|
|
34
34
|
/**
|
|
@@ -47,6 +47,7 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
|
|
|
47
47
|
'<%= config.bin %> commitments create --agent <agent-id> --title "Ship v2" --outcome "v2 is live for all users" --cadence 6h',
|
|
48
48
|
'<%= config.bin %> commitments create --agent <agent-id> --title "Hiring loop" --outcome "Every candidate hears back in 48h" --watch tasks --watch email --cadence 12h --status active',
|
|
49
49
|
'<%= config.bin %> commitments create --agent <agent-id> --title "SLA" --outcome "p95 under 200ms" --criterion "p95 latency confirmed" --evaluator metric --measure <measure-id>',
|
|
50
|
+
'<%= config.bin %> commitments create --agent <agent-id> --title "AWS cost watch" --outcome "Cost regressions are investigated" --agent-directive-file ./aws-cost-policy.md',
|
|
50
51
|
'<%= config.bin %> commitments create --from-json commitment.json --json',
|
|
51
52
|
];
|
|
52
53
|
static flags = {
|
|
@@ -64,6 +65,12 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
|
|
|
64
65
|
description: 'The outcome to hold true — required when setting any target field',
|
|
65
66
|
}),
|
|
66
67
|
description: core_1.Flags.string({ description: 'Longer description' }),
|
|
68
|
+
'agent-directive': core_1.Flags.string({
|
|
69
|
+
description: 'Per-Commitment domain policy (max 8,000 characters). Mutually exclusive with --agent-directive-file.',
|
|
70
|
+
}),
|
|
71
|
+
'agent-directive-file': core_1.Flags.string({
|
|
72
|
+
description: 'Read the per-Commitment domain policy from a text file, or - for stdin. Mutually exclusive with --agent-directive.',
|
|
73
|
+
}),
|
|
67
74
|
goal: core_1.Flags.string({ description: 'Link to a goal ID' }),
|
|
68
75
|
status: core_1.Flags.string({
|
|
69
76
|
description: 'Create as draft (default) or active',
|
|
@@ -116,9 +123,24 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
|
|
|
116
123
|
}),
|
|
117
124
|
timezone: core_1.Flags.string({ description: 'IANA timezone for the cadence' }),
|
|
118
125
|
autonomy: core_1.Flags.string({
|
|
119
|
-
|
|
126
|
+
// `--help` is where someone decides what to type, so the ceiling that can
|
|
127
|
+
// still bind has to be stated HERE and not only in the notice that
|
|
128
|
+
// corrects them afterwards. `commitments autonomy --mode` learned the
|
|
129
|
+
// same lesson: what it must not keep is the silence.
|
|
130
|
+
description: 'Autonomy to set at creation (default suggestions_only). Explicit values are preserved; ' +
|
|
131
|
+
'Agent, Compass, and workspace governance can still impose a visible effective ceiling.',
|
|
120
132
|
options: [...commitments_1.COMMITMENT_AUTONOMY_MODES],
|
|
121
133
|
}),
|
|
134
|
+
isolation: core_1.Flags.string({
|
|
135
|
+
// Omitting this is not the same as passing `shared`: an omitted value
|
|
136
|
+
// leaves the daemon's own isolation heuristic in force, while `shared` is
|
|
137
|
+
// an explicit contract that suppresses it. Say so here, because `--help`
|
|
138
|
+
// is where someone decides which of the two they mean.
|
|
139
|
+
description: 'Where autonomous runs do their work. "ephemeral" cuts a one-shot git worktree per run ' +
|
|
140
|
+
'and destroys it after; "shared" lands them on the daemon working tree, in place. ' +
|
|
141
|
+
'Omit to leave the runtime default. Cannot be combined with a remediation capability.',
|
|
142
|
+
options: [...commitments_1.COMMITMENT_EXECUTION_ISOLATION_MODES],
|
|
143
|
+
}),
|
|
122
144
|
'max-nudges': core_1.Flags.integer({ description: 'Max user nudges per day (0..20)' }),
|
|
123
145
|
};
|
|
124
146
|
async run() {
|
|
@@ -138,6 +160,12 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
|
|
|
138
160
|
payload.title = flags.title;
|
|
139
161
|
if (flags.description !== undefined)
|
|
140
162
|
payload.description = flags.description;
|
|
163
|
+
const agentDirective = await (0, commitments_1.readCommitmentAgentDirective)({
|
|
164
|
+
directive: flags['agent-directive'],
|
|
165
|
+
file: flags['agent-directive-file'],
|
|
166
|
+
});
|
|
167
|
+
if (agentDirective !== undefined)
|
|
168
|
+
payload.agentDirective = agentDirective;
|
|
141
169
|
if (flags.goal)
|
|
142
170
|
payload.goalId = flags.goal;
|
|
143
171
|
if (flags.status)
|
|
@@ -197,6 +225,8 @@ class CommitmentsCreate extends base_command_1.BaseCommand {
|
|
|
197
225
|
const policy = {};
|
|
198
226
|
if (flags.autonomy)
|
|
199
227
|
policy.autonomyMode = flags.autonomy;
|
|
228
|
+
if (flags.isolation)
|
|
229
|
+
policy.executionIsolation = flags.isolation;
|
|
200
230
|
if (flags['max-nudges'] !== undefined)
|
|
201
231
|
policy.maxUserNudgesPerDay = flags['max-nudges'];
|
|
202
232
|
if (Object.keys(policy).length)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export declare function doctorVerdict(input: {
|
|
3
|
+
commitment?: Record<string, unknown>;
|
|
4
|
+
preflight?: Record<string, unknown>;
|
|
5
|
+
}): {
|
|
6
|
+
verdict: string;
|
|
7
|
+
next: string;
|
|
8
|
+
};
|
|
9
|
+
export default class CommitmentsDoctor extends BaseCommand {
|
|
10
|
+
static description: string;
|
|
11
|
+
static args: {
|
|
12
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
13
|
+
};
|
|
14
|
+
static flags: {
|
|
15
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
strict: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.doctorVerdict = doctorVerdict;
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const commitments_1 = require("../../lib/commitments");
|
|
7
|
+
function doctorVerdict(input) {
|
|
8
|
+
const commitment = input.commitment || {};
|
|
9
|
+
const preflight = input.preflight || {};
|
|
10
|
+
if (commitment.status !== 'active')
|
|
11
|
+
return { verdict: 'blocked', next: 'skrr commitments resume <id>' };
|
|
12
|
+
if (preflight.verdict === 'blocked')
|
|
13
|
+
return { verdict: 'blocked', next: 'skrr commitments preflight <id> --json' };
|
|
14
|
+
const attention = preflight.attention;
|
|
15
|
+
if (attention?.allowed === false)
|
|
16
|
+
return { verdict: 'attention_suppressed', next: 'skrr commitments effective-policy <id>' };
|
|
17
|
+
return { verdict: 'active_healthy', next: 'skrr commitments trace <id> --limit 50' };
|
|
18
|
+
}
|
|
19
|
+
class CommitmentsDoctor extends base_command_1.BaseCommand {
|
|
20
|
+
static description = 'Summarize commitment readiness and the next operator action';
|
|
21
|
+
static args = {
|
|
22
|
+
id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
|
|
23
|
+
};
|
|
24
|
+
static flags = {
|
|
25
|
+
json: core_1.Flags.boolean({ description: 'Output the composed health report as JSON' }),
|
|
26
|
+
strict: core_1.Flags.boolean({
|
|
27
|
+
description: 'Exit non-zero unless the commitment is active and healthy',
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
async run() {
|
|
31
|
+
this.requireAuth();
|
|
32
|
+
const { args, flags } = await this.parse(CommitmentsDoctor);
|
|
33
|
+
let commitment;
|
|
34
|
+
let preflight;
|
|
35
|
+
let triggerStatus;
|
|
36
|
+
let ledger;
|
|
37
|
+
try {
|
|
38
|
+
const [shown, pf, triggers, runs] = await Promise.all([
|
|
39
|
+
commitments_1.commitmentApi.get(args.id),
|
|
40
|
+
commitments_1.commitmentApi.preflight(args.id),
|
|
41
|
+
commitments_1.commitmentApi.triggerStatus(args.id, 5),
|
|
42
|
+
commitments_1.commitmentApi.ledger(args.id, { limit: 5 }),
|
|
43
|
+
]);
|
|
44
|
+
commitment = (shown.commitment || {});
|
|
45
|
+
preflight = pf;
|
|
46
|
+
triggerStatus = triggers;
|
|
47
|
+
ledger = runs;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
this.handleApiError(error);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const diagnosis = doctorVerdict({ commitment, preflight });
|
|
54
|
+
const report = {
|
|
55
|
+
...diagnosis,
|
|
56
|
+
commitment,
|
|
57
|
+
preflight,
|
|
58
|
+
triggerStatus,
|
|
59
|
+
ledger,
|
|
60
|
+
observedAt: new Date().toISOString(),
|
|
61
|
+
};
|
|
62
|
+
if (flags.json)
|
|
63
|
+
this.log(JSON.stringify(report, null, 2));
|
|
64
|
+
else {
|
|
65
|
+
this.log(`Verdict: ${diagnosis.verdict}`);
|
|
66
|
+
this.log(`Next: ${diagnosis.next.replace('<id>', args.id)}`);
|
|
67
|
+
}
|
|
68
|
+
if (flags.strict && diagnosis.verdict !== 'active_healthy')
|
|
69
|
+
process.exitCode = 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.default = CommitmentsDoctor;
|
|
@@ -28,11 +28,13 @@ export default class CommitmentsPreflight extends BaseCommand {
|
|
|
28
28
|
static description: string;
|
|
29
29
|
static examples: string[];
|
|
30
30
|
static args: {
|
|
31
|
-
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
31
|
+
id: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
32
32
|
};
|
|
33
33
|
static flags: {
|
|
34
34
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
35
35
|
next: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
36
|
+
'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
37
|
+
'event-fixture': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
36
38
|
};
|
|
37
39
|
run(): Promise<void>;
|
|
38
40
|
}
|
|
@@ -4,6 +4,7 @@ exports.preflightGateLines = preflightGateLines;
|
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const base_command_1 = require("../../base-command");
|
|
6
6
|
const commitments_1 = require("../../lib/commitments");
|
|
7
|
+
const prompt_1 = require("../../lib/prompt");
|
|
7
8
|
/**
|
|
8
9
|
* The lines one preflight gate contributes.
|
|
9
10
|
*
|
|
@@ -46,21 +47,42 @@ class CommitmentsPreflight extends base_command_1.BaseCommand {
|
|
|
46
47
|
'<%= config.bin %> commitments preflight <commitment-id> --json',
|
|
47
48
|
];
|
|
48
49
|
static args = {
|
|
49
|
-
id: core_1.Args.string({
|
|
50
|
+
id: core_1.Args.string({
|
|
51
|
+
description: 'Commitment ID (omit with --from-json to preview before creation)',
|
|
52
|
+
required: false,
|
|
53
|
+
ignoreStdin: true,
|
|
54
|
+
}),
|
|
50
55
|
};
|
|
51
56
|
static flags = {
|
|
52
57
|
json: core_1.Flags.boolean({ description: 'Output the complete preflight report as JSON' }),
|
|
53
58
|
next: core_1.Flags.integer({ description: 'Number of upcoming runs to project (1–10)' }),
|
|
59
|
+
'from-json': core_1.Flags.string({
|
|
60
|
+
description: 'Unsaved Commitment create body file, or - for stdin',
|
|
61
|
+
}),
|
|
62
|
+
'event-fixture': core_1.Flags.string({
|
|
63
|
+
description: 'Optional event fixture JSON file, or - for stdin',
|
|
64
|
+
}),
|
|
54
65
|
};
|
|
55
66
|
async run() {
|
|
56
67
|
this.requireAuth();
|
|
57
68
|
const { args, flags } = await this.parse(CommitmentsPreflight);
|
|
69
|
+
if (Boolean(args.id) === Boolean(flags['from-json'])) {
|
|
70
|
+
this.error('Pass either a commitment ID or --from-json <file|->.', { exit: 1 });
|
|
71
|
+
}
|
|
58
72
|
if (flags.next != null && (flags.next < 1 || flags.next > 10)) {
|
|
59
73
|
this.error('--next must be between 1 and 10', { exit: 1 });
|
|
60
74
|
}
|
|
61
75
|
let report;
|
|
62
76
|
try {
|
|
63
|
-
report =
|
|
77
|
+
report = args.id
|
|
78
|
+
? await commitments_1.commitmentApi.preflight(args.id, flags.next)
|
|
79
|
+
: await commitments_1.commitmentApi.draftPreflight({
|
|
80
|
+
commitment: (0, commitments_1.normalizeCreateBody)(await (0, prompt_1.readJsonBody)(flags['from-json'])),
|
|
81
|
+
...(flags['event-fixture']
|
|
82
|
+
? { eventFixture: await (0, prompt_1.readJsonBody)(flags['event-fixture']) }
|
|
83
|
+
: {}),
|
|
84
|
+
...(flags.next !== undefined ? { nextRunCount: flags.next } : {}),
|
|
85
|
+
});
|
|
64
86
|
}
|
|
65
87
|
catch (err) {
|
|
66
88
|
this.handleApiError(err);
|
|
@@ -70,7 +92,7 @@ class CommitmentsPreflight extends base_command_1.BaseCommand {
|
|
|
70
92
|
this.log(JSON.stringify(report, null, 2));
|
|
71
93
|
return;
|
|
72
94
|
}
|
|
73
|
-
this.log(
|
|
95
|
+
this.log(`${args.id ? 'Preflight' : 'Pre-create preview (nothing persisted)'}: ${String(report.verdict).replace(/_/g, ' ')}`);
|
|
74
96
|
this.log('\nGates:');
|
|
75
97
|
for (const gate of report.gates || []) {
|
|
76
98
|
for (const line of preflightGateLines(gate))
|
|
@@ -13,7 +13,8 @@ const DESTINATIONS_NEEDING_TARGET = new Set(['slack_channel', 'email']);
|
|
|
13
13
|
* completion, a ping on escalation), so `on` is NOT part of the key.
|
|
14
14
|
*/
|
|
15
15
|
function reportKey(r) {
|
|
16
|
-
|
|
16
|
+
const target = r.destinationTarget ? `${r.destination}:${r.destinationTarget}` : r.destination;
|
|
17
|
+
return `${target}:${r.on ?? 'material_change'}`;
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* `skrr commitments reports <id>` — where this commitment tells you things.
|
|
@@ -98,8 +99,20 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
98
99
|
payload = { reports: (0, commitment_terms_1.appendUnique)(reports, next, reportKey, 'Report target') };
|
|
99
100
|
}
|
|
100
101
|
else {
|
|
102
|
+
const base = String(flags.remove);
|
|
103
|
+
const matches = reports.filter((report) => {
|
|
104
|
+
const target = report.destinationTarget
|
|
105
|
+
? `${report.destination}:${report.destinationTarget}`
|
|
106
|
+
: report.destination;
|
|
107
|
+
return target === base && (!flags.on || (report.on ?? 'material_change') === flags.on);
|
|
108
|
+
});
|
|
109
|
+
if (matches.length !== 1) {
|
|
110
|
+
throw new Error(matches.length > 1
|
|
111
|
+
? `Multiple report targets match ${base}. Pass --on to select one condition.`
|
|
112
|
+
: `Report target ${base} is not attached to this commitment.`);
|
|
113
|
+
}
|
|
101
114
|
payload = {
|
|
102
|
-
reports: (0, commitment_terms_1.removeByKey)(reports,
|
|
115
|
+
reports: (0, commitment_terms_1.removeByKey)(reports, reportKey(matches[0]), reportKey, 'Report target'),
|
|
103
116
|
};
|
|
104
117
|
}
|
|
105
118
|
}
|
|
@@ -13,8 +13,11 @@ import { BaseCommand } from '../../base-command';
|
|
|
13
13
|
* `freshnessExpectation` thresholds the loop uses to detect stale open loops.
|
|
14
14
|
* `--criterion` still REPLACES the criteria list (that is its purpose).
|
|
15
15
|
*
|
|
16
|
-
* Autonomy is deliberately not settable here
|
|
17
|
-
*
|
|
16
|
+
* Autonomy is deliberately not settable here: raising it wants a recorded
|
|
17
|
+
* reason, which `skrr commitments autonomy <id>` requires and this command has
|
|
18
|
+
* no place for. Other policy fields ARE patchable — the API deep-merges a
|
|
19
|
+
* `policy` patch (`mergePolicyPatch`), so a single-key patch leaves the rest of
|
|
20
|
+
* the contract untouched.
|
|
18
21
|
*/
|
|
19
22
|
export default class CommitmentsUpdate extends BaseCommand {
|
|
20
23
|
static description: string;
|
|
@@ -25,8 +28,11 @@ export default class CommitmentsUpdate extends BaseCommand {
|
|
|
25
28
|
static flags: {
|
|
26
29
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
27
30
|
'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
31
|
+
'if-version': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
28
32
|
title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
29
33
|
description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
34
|
+
'agent-directive': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
35
|
+
'agent-directive-file': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
30
36
|
status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
31
37
|
outcome: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
32
38
|
deadline: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -40,6 +46,7 @@ export default class CommitmentsUpdate extends BaseCommand {
|
|
|
40
46
|
cadence: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
41
47
|
'cadence-mode': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
42
48
|
timezone: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
49
|
+
isolation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
43
50
|
};
|
|
44
51
|
run(): Promise<void>;
|
|
45
52
|
}
|
|
@@ -20,8 +20,11 @@ const commitments_1 = require("../../lib/commitments");
|
|
|
20
20
|
* `freshnessExpectation` thresholds the loop uses to detect stale open loops.
|
|
21
21
|
* `--criterion` still REPLACES the criteria list (that is its purpose).
|
|
22
22
|
*
|
|
23
|
-
* Autonomy is deliberately not settable here
|
|
24
|
-
*
|
|
23
|
+
* Autonomy is deliberately not settable here: raising it wants a recorded
|
|
24
|
+
* reason, which `skrr commitments autonomy <id>` requires and this command has
|
|
25
|
+
* no place for. Other policy fields ARE patchable — the API deep-merges a
|
|
26
|
+
* `policy` patch (`mergePolicyPatch`), so a single-key patch leaves the rest of
|
|
27
|
+
* the contract untouched.
|
|
25
28
|
*/
|
|
26
29
|
class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
27
30
|
static description = "Update a commitment's contract (title, target, cadence, sources)";
|
|
@@ -30,6 +33,7 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
30
33
|
'<%= config.bin %> commitments update <commitment-id> --title "Ship v2 (Q3)" --outcome "v2 is live for all users"',
|
|
31
34
|
'<%= config.bin %> commitments update <commitment-id> --watch tasks --watch github',
|
|
32
35
|
'<%= config.bin %> commitments update <commitment-id> --criterion "signups confirmed" --evaluator metric --measure <measure-id>',
|
|
36
|
+
'<%= config.bin %> commitments update <commitment-id> --agent-directive-file ./review-policy.md',
|
|
33
37
|
];
|
|
34
38
|
static args = {
|
|
35
39
|
id: core_1.Args.string({ description: 'Commitment ID', required: true, ignoreStdin: true }),
|
|
@@ -39,8 +43,17 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
39
43
|
'from-json': core_1.Flags.string({
|
|
40
44
|
description: 'Path to a JSON file (or "-" for stdin) for fields not exposed as flags',
|
|
41
45
|
}),
|
|
46
|
+
'if-version': core_1.Flags.integer({
|
|
47
|
+
description: 'Only update this observed contract version; returns a conflict if it changed',
|
|
48
|
+
}),
|
|
42
49
|
title: core_1.Flags.string({ description: 'New title' }),
|
|
43
50
|
description: core_1.Flags.string({ description: 'New description' }),
|
|
51
|
+
'agent-directive': core_1.Flags.string({
|
|
52
|
+
description: 'Replace the per-Commitment domain policy (max 8,000 characters). Mutually exclusive with --agent-directive-file.',
|
|
53
|
+
}),
|
|
54
|
+
'agent-directive-file': core_1.Flags.string({
|
|
55
|
+
description: 'Read replacement domain policy from a text file, or - for stdin. Mutually exclusive with --agent-directive.',
|
|
56
|
+
}),
|
|
44
57
|
status: core_1.Flags.string({
|
|
45
58
|
description: 'New status. Invalid lifecycle jumps (e.g. completed → active) are rejected by the API.',
|
|
46
59
|
options: [...commitments_1.COMMITMENT_STATUSES],
|
|
@@ -82,6 +95,14 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
82
95
|
options: [...commitments_1.COMMITMENT_CADENCE_MODES],
|
|
83
96
|
}),
|
|
84
97
|
timezone: core_1.Flags.string({ description: 'IANA timezone for the cadence' }),
|
|
98
|
+
isolation: core_1.Flags.string({
|
|
99
|
+
// Sent as a single-key `policy` patch. The API deep-merges it, so this
|
|
100
|
+
// cannot blank an autonomy mode or an attention budget set elsewhere.
|
|
101
|
+
description: 'Where autonomous runs do their work: "ephemeral" (one-shot git worktree per run) or ' +
|
|
102
|
+
'"shared" (the daemon working tree, in place). Cannot be combined with a remediation ' +
|
|
103
|
+
'capability.',
|
|
104
|
+
options: [...commitments_1.COMMITMENT_EXECUTION_ISOLATION_MODES],
|
|
105
|
+
}),
|
|
85
106
|
};
|
|
86
107
|
async run() {
|
|
87
108
|
this.requireAuth();
|
|
@@ -115,10 +136,18 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
115
136
|
let payload;
|
|
116
137
|
try {
|
|
117
138
|
payload = await (0, prompt_1.readJsonBody)(flags['from-json']);
|
|
139
|
+
if (flags['if-version'] !== undefined)
|
|
140
|
+
payload.expectedVersion = flags['if-version'];
|
|
118
141
|
if (flags.title)
|
|
119
142
|
payload.title = flags.title;
|
|
120
143
|
if (flags.description !== undefined)
|
|
121
144
|
payload.description = flags.description;
|
|
145
|
+
const agentDirective = await (0, commitments_1.readCommitmentAgentDirective)({
|
|
146
|
+
directive: flags['agent-directive'],
|
|
147
|
+
file: flags['agent-directive-file'],
|
|
148
|
+
});
|
|
149
|
+
if (agentDirective !== undefined)
|
|
150
|
+
payload.agentDirective = agentDirective;
|
|
122
151
|
if (flags.status)
|
|
123
152
|
payload.status = flags.status;
|
|
124
153
|
if (wantsTarget) {
|
|
@@ -189,6 +218,11 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
189
218
|
cadence.timezone = flags.timezone;
|
|
190
219
|
payload.cadence = cadence;
|
|
191
220
|
}
|
|
221
|
+
// A single key, deliberately. `mergePolicyPatch` on the server merges it
|
|
222
|
+
// into the stored policy, so naming only this field is what keeps the
|
|
223
|
+
// rest of the contract intact.
|
|
224
|
+
if (flags.isolation)
|
|
225
|
+
payload.policy = { executionIsolation: flags.isolation };
|
|
192
226
|
}
|
|
193
227
|
catch (err) {
|
|
194
228
|
this.error(err.message, { exit: 1 });
|
|
@@ -20,6 +20,7 @@ class Daemon extends core_1.Command {
|
|
|
20
20
|
'<%= config.bin %> daemon start',
|
|
21
21
|
'<%= config.bin %> daemon stop',
|
|
22
22
|
'<%= config.bin %> daemon logs',
|
|
23
|
+
'<%= config.bin %> daemon recover-offline-queue --apply',
|
|
23
24
|
'<%= config.bin %> daemon usage --refresh',
|
|
24
25
|
'<%= config.bin %> daemon byok status',
|
|
25
26
|
];
|
|
@@ -38,6 +39,7 @@ class Daemon extends core_1.Command {
|
|
|
38
39
|
this.log(' skrr daemon stop — stop the daemon');
|
|
39
40
|
this.log(' skrr daemon status — show running state and config');
|
|
40
41
|
this.log(' skrr daemon logs — tail recent daemon logs');
|
|
42
|
+
this.log(' skrr daemon recover-offline-queue — restore recoverable offline WALs');
|
|
41
43
|
this.log(' skrr daemon usage — show local Claude Code and Codex usage limits');
|
|
42
44
|
this.log(' skrr daemon byok — manage local BYOK Keychain credentials');
|
|
43
45
|
this.log('');
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
/** Restore explicitly selected offline-queue forensic WALs through the runtime. */
|
|
3
|
+
export default class DaemonRecoverOfflineQueue extends Command {
|
|
4
|
+
static aliases: string[];
|
|
5
|
+
static summary: string;
|
|
6
|
+
static description: string;
|
|
7
|
+
static strict: boolean;
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const exec_runtime_binary_1 = require("../../lib/exec-runtime-binary");
|
|
5
|
+
/** Restore explicitly selected offline-queue forensic WALs through the runtime. */
|
|
6
|
+
class DaemonRecoverOfflineQueue extends core_1.Command {
|
|
7
|
+
static aliases = ['daemons:recover-offline-queue'];
|
|
8
|
+
static summary = 'Restore recoverable offline-queue dead letters after a replay fix';
|
|
9
|
+
static description = (0, exec_runtime_binary_1.forwardedFlagsNote)('recover-offline-queue');
|
|
10
|
+
static strict = false;
|
|
11
|
+
async run() {
|
|
12
|
+
try {
|
|
13
|
+
this.exit(await (0, exec_runtime_binary_1.execRuntimeBinary)(['recover-offline-queue', ...this.argv]));
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (err.message === 'runtime-binary-not-installed') {
|
|
17
|
+
this.log((0, exec_runtime_binary_1.notInstalledMessage)());
|
|
18
|
+
this.exit(127);
|
|
19
|
+
}
|
|
20
|
+
throw err;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.default = DaemonRecoverOfflineQueue;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const core_1 = require("@oclif/core");
|
|
4
4
|
const exec_runtime_binary_1 = require("../../lib/exec-runtime-binary");
|
|
5
|
+
const runtime_start_verification_1 = require("../../lib/runtime-start-verification");
|
|
5
6
|
class DaemonStart extends core_1.Command {
|
|
6
7
|
// `skrr daemons <sub>` — the plural is advertised as an alias for the
|
|
7
8
|
// whole topic, and without a per-command alias only the bare topic
|
|
@@ -23,7 +24,34 @@ class DaemonStart extends core_1.Command {
|
|
|
23
24
|
const argv = this.argv;
|
|
24
25
|
try {
|
|
25
26
|
const code = await (0, exec_runtime_binary_1.execRuntimeBinary)(['start', ...argv]);
|
|
26
|
-
|
|
27
|
+
if (code !== 0)
|
|
28
|
+
this.exit(code);
|
|
29
|
+
// A supervisor's successful `kickstart` means only that it accepted the
|
|
30
|
+
// request. Older installed skrrd builds then write TOKEN_MISSING and exit
|
|
31
|
+
// cleanly, leaving the CLI that invoked them to report success. Query the
|
|
32
|
+
// same profile after every zero exit so the public command never claims a
|
|
33
|
+
// stopped service is running while users move through a staggered release.
|
|
34
|
+
const status = await (0, exec_runtime_binary_1.execRuntimeBinaryCapture)((0, runtime_start_verification_1.statusArgsForStart)(argv));
|
|
35
|
+
const verification = (0, runtime_start_verification_1.verifyRuntimeStart)(status.stdout, status.code, argv);
|
|
36
|
+
if (verification.status === 'reauth_required') {
|
|
37
|
+
this.logToStderr(`Local runtime did not start: profile '${verification.profile}' requires ` +
|
|
38
|
+
`re-authentication (reason: ${verification.reason ?? 'UNKNOWN'}). Run ` +
|
|
39
|
+
`\`${verification.recoveryCommand}\`, then retry \`skrr daemon start\`.`);
|
|
40
|
+
this.exit(runtime_start_verification_1.DAEMON_START_REAUTH_EXIT);
|
|
41
|
+
}
|
|
42
|
+
if (verification.status === 'not_running') {
|
|
43
|
+
this.logToStderr(`Local runtime did not remain running after skrrd exited successfully ` +
|
|
44
|
+
`(profile '${verification.profile}', service status: ` +
|
|
45
|
+
`${verification.runtimeStatus ?? 'unknown'}). Run \`skrr daemon logs\` for the reason.`);
|
|
46
|
+
this.exit(runtime_start_verification_1.DAEMON_START_UNVERIFIED_EXIT);
|
|
47
|
+
}
|
|
48
|
+
if (verification.status === 'unreadable_status') {
|
|
49
|
+
this.logToStderr(`skrrd start exited successfully, but skrr could not verify a running local runtime ` +
|
|
50
|
+
`for profile '${verification.profile}'; refusing to report success. ` +
|
|
51
|
+
'Run `skrr daemon status` and `skrr daemon logs` for the reason.');
|
|
52
|
+
this.exit(runtime_start_verification_1.DAEMON_START_UNVERIFIED_EXIT);
|
|
53
|
+
}
|
|
54
|
+
this.exit(0);
|
|
27
55
|
}
|
|
28
56
|
catch (err) {
|
|
29
57
|
if (err.message === 'runtime-binary-not-installed') {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class InstructionBlocksCreate extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
summary: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
body: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
file: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
category: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
tag: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
visibility: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
|
+
'parameter-schema': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
|
+
requirements: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
|
+
changelog: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
|
+
};
|
|
18
|
+
run(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
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 instruction_blocks_1 = require("../../lib/instruction-blocks");
|
|
7
|
+
const instruction_input_1 = require("../../lib/instruction-input");
|
|
8
|
+
const CATEGORIES = [
|
|
9
|
+
'github',
|
|
10
|
+
'communication',
|
|
11
|
+
'research',
|
|
12
|
+
'output',
|
|
13
|
+
'planning',
|
|
14
|
+
'other',
|
|
15
|
+
];
|
|
16
|
+
class InstructionBlocksCreate extends base_command_1.BaseCommand {
|
|
17
|
+
static description = 'Create a reusable, version-pinned Agent instruction block';
|
|
18
|
+
static examples = [
|
|
19
|
+
'<%= config.bin %> instruction-blocks create --name "Evidence first" --body "State evidence before conclusions."',
|
|
20
|
+
'<%= config.bin %> instruction-blocks create --name "PR review" --file ./review.md --category github --tag github --tag review',
|
|
21
|
+
'<%= config.bin %> instruction-blocks create --name "Team research" --file ./research.md --visibility workspace',
|
|
22
|
+
];
|
|
23
|
+
static flags = {
|
|
24
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
25
|
+
name: core_1.Flags.string({ description: 'Short, reusable block name', required: true }),
|
|
26
|
+
summary: core_1.Flags.string({ description: 'One-line description for library pickers' }),
|
|
27
|
+
body: core_1.Flags.string({ description: 'Instruction template text' }),
|
|
28
|
+
file: core_1.Flags.string({ description: 'Read template text from a file, or - for stdin' }),
|
|
29
|
+
category: core_1.Flags.string({ description: 'Library category', options: CATEGORIES }),
|
|
30
|
+
tag: core_1.Flags.string({ description: 'Library tag (repeatable)', multiple: true }),
|
|
31
|
+
visibility: core_1.Flags.string({
|
|
32
|
+
description: 'private (default), workspace, or public',
|
|
33
|
+
options: ['private', 'workspace', 'public'],
|
|
34
|
+
}),
|
|
35
|
+
'parameter-schema': core_1.Flags.string({
|
|
36
|
+
description: 'JSON array of typed parameter definitions (never secrets)',
|
|
37
|
+
}),
|
|
38
|
+
requirements: core_1.Flags.string({
|
|
39
|
+
description: 'JSON array of declarative capability/integration requirements; never grants access',
|
|
40
|
+
}),
|
|
41
|
+
changelog: core_1.Flags.string({ description: 'Why this initial version exists' }),
|
|
42
|
+
};
|
|
43
|
+
async run() {
|
|
44
|
+
this.requireAuth();
|
|
45
|
+
const { flags } = await this.parse(InstructionBlocksCreate);
|
|
46
|
+
let bodyTemplate;
|
|
47
|
+
let parameterSchema;
|
|
48
|
+
let requirements;
|
|
49
|
+
try {
|
|
50
|
+
bodyTemplate = (await (0, instruction_input_1.readInstructionBody)({
|
|
51
|
+
body: flags.body,
|
|
52
|
+
file: flags.file,
|
|
53
|
+
required: true,
|
|
54
|
+
}));
|
|
55
|
+
parameterSchema = (0, instruction_blocks_1.parseJsonFlag)(flags['parameter-schema'], '--parameter-schema');
|
|
56
|
+
requirements = (0, instruction_blocks_1.parseJsonFlag)(flags.requirements, '--requirements');
|
|
57
|
+
if (parameterSchema && !Array.isArray(parameterSchema)) {
|
|
58
|
+
throw new Error('--parameter-schema must be a JSON array');
|
|
59
|
+
}
|
|
60
|
+
if (requirements && !Array.isArray(requirements)) {
|
|
61
|
+
throw new Error('--requirements must be a JSON array');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
this.error(error.message, { exit: 2 });
|
|
66
|
+
}
|
|
67
|
+
let block;
|
|
68
|
+
try {
|
|
69
|
+
block = await data_provider_1.dataService.createInstructionBlock({
|
|
70
|
+
name: flags.name,
|
|
71
|
+
...(flags.summary !== undefined ? { summary: flags.summary } : {}),
|
|
72
|
+
...(flags.category !== undefined
|
|
73
|
+
? { category: flags.category }
|
|
74
|
+
: {}),
|
|
75
|
+
...(flags.tag?.length ? { tags: flags.tag } : {}),
|
|
76
|
+
...(flags.visibility !== undefined
|
|
77
|
+
? { visibility: flags.visibility }
|
|
78
|
+
: {}),
|
|
79
|
+
bodyTemplate,
|
|
80
|
+
...(parameterSchema !== undefined ? { parameterSchema } : {}),
|
|
81
|
+
...(requirements !== undefined ? { requirements } : {}),
|
|
82
|
+
...(flags.changelog !== undefined ? { changelog: flags.changelog } : {}),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
this.handleApiError(error);
|
|
87
|
+
}
|
|
88
|
+
if (flags.json)
|
|
89
|
+
return this.log(JSON.stringify(block, null, 2));
|
|
90
|
+
this.log(`Created ${block.name} (${block.id}) at v${block.currentVersion}.`);
|
|
91
|
+
this.log(`Attach it: skrr agents instructions add --agent <agent-id> --block ${block.id}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.default = InstructionBlocksCreate;
|