@skrr-ai/cli 0.1.15 → 0.1.18
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 +10 -4
- package/dist/commands/commitments/action-proposals/decide.d.ts +13 -0
- package/dist/commands/commitments/action-proposals/decide.js +41 -0
- package/dist/commands/commitments/action-proposals/execute.d.ts +12 -0
- package/dist/commands/commitments/action-proposals/execute.js +29 -0
- package/dist/commands/commitments/action-proposals.d.ts +13 -0
- package/dist/commands/commitments/action-proposals.js +56 -0
- package/dist/commands/commitments/autonomy.d.ts +7 -11
- package/dist/commands/commitments/autonomy.js +16 -17
- package/dist/commands/commitments/bundle.d.ts +14 -0
- package/dist/commands/commitments/bundle.js +49 -0
- package/dist/commands/commitments/create.d.ts +33 -5
- package/dist/commands/commitments/create.js +234 -27
- package/dist/commands/commitments/delivery.d.ts +16 -0
- package/dist/commands/commitments/delivery.js +71 -0
- package/dist/commands/commitments/doctor.d.ts +20 -0
- package/dist/commands/commitments/doctor.js +88 -0
- package/dist/commands/commitments/effective-policy.d.ts +2 -0
- package/dist/commands/commitments/effective-policy.js +50 -5
- package/dist/commands/commitments/endpoints/connect.d.ts +3 -10
- package/dist/commands/commitments/endpoints/connect.js +6 -37
- package/dist/commands/commitments/endpoints/create.d.ts +2 -9
- package/dist/commands/commitments/endpoints/create.js +10 -23
- package/dist/commands/commitments/mode.d.ts +15 -0
- package/dist/commands/commitments/mode.js +57 -0
- package/dist/commands/commitments/pack/promote.d.ts +1 -1
- package/dist/commands/commitments/pack/promote.js +7 -3
- package/dist/commands/commitments/pack/shadow.d.ts +3 -2
- package/dist/commands/commitments/pack/shadow.js +6 -4
- package/dist/commands/commitments/patch.d.ts +14 -0
- package/dist/commands/commitments/patch.js +51 -0
- package/dist/commands/commitments/preflight.d.ts +5 -2
- package/dist/commands/commitments/preflight.js +47 -6
- package/dist/commands/commitments/receipt.d.ts +15 -0
- package/dist/commands/commitments/receipt.js +34 -0
- package/dist/commands/commitments/remediate.d.ts +0 -1
- package/dist/commands/commitments/remediate.js +5 -3
- package/dist/commands/commitments/reports.js +27 -5
- package/dist/commands/commitments/show.d.ts +1 -0
- package/dist/commands/commitments/show.js +22 -1
- package/dist/commands/commitments/update.d.ts +9 -2
- package/dist/commands/commitments/update.js +40 -4
- package/dist/commands/commitments/wake-capabilities.d.ts +5 -0
- package/dist/commands/commitments/wake-capabilities.js +23 -7
- package/dist/commands/spaces/bootstrap.js +1 -1
- package/dist/commands/tasks/complete.js +57 -0
- package/dist/commands/tasks/create.js +2 -1
- package/dist/commands/tasks/deliverable/confirm.d.ts +35 -0
- package/dist/commands/tasks/deliverable/confirm.js +77 -0
- package/dist/commands/tasks/expectations.js +20 -1
- package/dist/commands/tasks/report.js +24 -0
- package/dist/commands/tasks/trust.d.ts +35 -0
- package/dist/commands/tasks/trust.js +75 -0
- package/dist/commands/tasks/waive.js +1 -1
- package/dist/lib/commitment-endpoints.d.ts +3 -2
- package/dist/lib/commitment-endpoints.js +12 -9
- package/dist/lib/commitment-product.d.ts +14 -0
- package/dist/lib/commitment-product.js +78 -0
- package/dist/lib/commitments.d.ts +67 -20
- package/dist/lib/commitments.js +89 -39
- package/dist/lib/tasks.js +27 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +3733 -3570
- package/oclif.manifest.json +9291 -8306
- package/package.json +1 -1
|
@@ -15,7 +15,6 @@ const commitments_1 = require("../../lib/commitments");
|
|
|
15
15
|
* pause_commitment stop the loop entirely
|
|
16
16
|
* mute_user_nudges keep watching, stop interrupting (max nudges → 0)
|
|
17
17
|
* reduce_nudge_frequency at most one nudge per day
|
|
18
|
-
* tighten_policy require approval for the risky action classes
|
|
19
18
|
* mark_noop record that this fired for no reason
|
|
20
19
|
*/
|
|
21
20
|
class CommitmentsRemediate extends base_command_1.BaseCommand {
|
|
@@ -30,8 +29,11 @@ class CommitmentsRemediate extends base_command_1.BaseCommand {
|
|
|
30
29
|
static flags = {
|
|
31
30
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
32
31
|
action: core_1.Flags.string({
|
|
33
|
-
description: 'Remediation action',
|
|
34
|
-
|
|
32
|
+
description: 'Remediation action. Change work authority with commitments mode; Workspace approval rules belong in Workspace governance.',
|
|
33
|
+
// `tighten_policy` remains a REST compatibility value for legacy rows. It
|
|
34
|
+
// is deliberately absent from the product CLI: v2 authority changes are
|
|
35
|
+
// explicit Mode changes, never a hidden risk/approval tier.
|
|
36
|
+
options: commitments_1.COMMITMENT_REMEDIATION_ACTIONS.filter((action) => action !== 'tighten_policy'),
|
|
35
37
|
required: true,
|
|
36
38
|
}),
|
|
37
39
|
reason: core_1.Flags.string({ description: 'Why (recorded on the boundary-change ledger)' }),
|
|
@@ -6,14 +6,24 @@ const base_command_1 = require("../../base-command");
|
|
|
6
6
|
const commitments_1 = require("../../lib/commitments");
|
|
7
7
|
const commitment_terms_1 = require("../../lib/commitment-terms");
|
|
8
8
|
/** Destinations that address one specific place and therefore need a target. */
|
|
9
|
-
const DESTINATIONS_NEEDING_TARGET = new Set(['slack_channel'
|
|
9
|
+
const DESTINATIONS_NEEDING_TARGET = new Set(['slack_channel']);
|
|
10
|
+
/**
|
|
11
|
+
* Keep the CLI safe across a rolling data-provider build. Older installed
|
|
12
|
+
* packages expose the compatibility destination list but not the narrowed
|
|
13
|
+
* authoring list; derive the same restriction instead of crashing command
|
|
14
|
+
* discovery or accidentally offering the inert email transport.
|
|
15
|
+
*/
|
|
16
|
+
const AUTHORABLE_REPORT_DESTINATIONS = Array.isArray(data_provider_1.COMMITMENT_AUTHORABLE_REPORT_DESTINATIONS)
|
|
17
|
+
? data_provider_1.COMMITMENT_AUTHORABLE_REPORT_DESTINATIONS
|
|
18
|
+
: data_provider_1.COMMITMENT_REPORT_DESTINATIONS.filter((destination) => destination !== 'email');
|
|
10
19
|
/**
|
|
11
20
|
* Identity of a report target = destination + its target id. The same channel
|
|
12
21
|
* may legitimately appear twice with different `on` conditions (a digest on
|
|
13
22
|
* completion, a ping on escalation), so `on` is NOT part of the key.
|
|
14
23
|
*/
|
|
15
24
|
function reportKey(r) {
|
|
16
|
-
|
|
25
|
+
const target = r.destinationTarget ? `${r.destination}:${r.destinationTarget}` : r.destination;
|
|
26
|
+
return `${target}:${r.on ?? 'material_change'}`;
|
|
17
27
|
}
|
|
18
28
|
/**
|
|
19
29
|
* `skrr commitments reports <id>` — where this commitment tells you things.
|
|
@@ -40,10 +50,10 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
40
50
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
41
51
|
add: core_1.Flags.string({
|
|
42
52
|
description: 'Destination to add',
|
|
43
|
-
options: [...
|
|
53
|
+
options: [...AUTHORABLE_REPORT_DESTINATIONS],
|
|
44
54
|
}),
|
|
45
55
|
target: core_1.Flags.string({
|
|
46
|
-
description: 'Channel id
|
|
56
|
+
description: 'Channel id for slack_channel. App and owner-DM destinations need no target.',
|
|
47
57
|
}),
|
|
48
58
|
on: core_1.Flags.string({
|
|
49
59
|
description: 'When to report (default: material_change)',
|
|
@@ -98,8 +108,20 @@ class CommitmentsReports extends base_command_1.BaseCommand {
|
|
|
98
108
|
payload = { reports: (0, commitment_terms_1.appendUnique)(reports, next, reportKey, 'Report target') };
|
|
99
109
|
}
|
|
100
110
|
else {
|
|
111
|
+
const base = String(flags.remove);
|
|
112
|
+
const matches = reports.filter((report) => {
|
|
113
|
+
const target = report.destinationTarget
|
|
114
|
+
? `${report.destination}:${report.destinationTarget}`
|
|
115
|
+
: report.destination;
|
|
116
|
+
return target === base && (!flags.on || (report.on ?? 'material_change') === flags.on);
|
|
117
|
+
});
|
|
118
|
+
if (matches.length !== 1) {
|
|
119
|
+
throw new Error(matches.length > 1
|
|
120
|
+
? `Multiple report targets match ${base}. Pass --on to select one condition.`
|
|
121
|
+
: `Report target ${base} is not attached to this commitment.`);
|
|
122
|
+
}
|
|
101
123
|
payload = {
|
|
102
|
-
reports: (0, commitment_terms_1.removeByKey)(reports,
|
|
124
|
+
reports: (0, commitment_terms_1.removeByKey)(reports, reportKey(matches[0]), reportKey, 'Report target'),
|
|
103
125
|
};
|
|
104
126
|
}
|
|
105
127
|
}
|
|
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const base_command_1 = require("../../base-command");
|
|
5
5
|
const commitments_1 = require("../../lib/commitments");
|
|
6
6
|
const web_url_1 = require("../../lib/web-url");
|
|
7
|
+
const commitment_product_1 = require("../../lib/commitment-product");
|
|
7
8
|
/**
|
|
8
9
|
* `skrr commitments show <id>` — the commitment's contract + live control-loop
|
|
9
10
|
* state (health, last check, next check, unresolved-check streak), plus the most
|
|
@@ -23,6 +24,9 @@ class CommitmentsShow extends base_command_1.BaseCommand {
|
|
|
23
24
|
};
|
|
24
25
|
static flags = {
|
|
25
26
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
27
|
+
verbose: core_1.Flags.boolean({
|
|
28
|
+
description: 'Include raw compatibility policy and check diagnostics',
|
|
29
|
+
}),
|
|
26
30
|
};
|
|
27
31
|
async run() {
|
|
28
32
|
this.requireAuth();
|
|
@@ -46,13 +50,30 @@ class CommitmentsShow extends base_command_1.BaseCommand {
|
|
|
46
50
|
return;
|
|
47
51
|
}
|
|
48
52
|
(0, commitments_1.renderCommitmentSummary)(response.commitment, (line) => this.log(line), response.latestCheck);
|
|
49
|
-
|
|
53
|
+
try {
|
|
54
|
+
const receipts = await commitments_1.commitmentApi.receipts(args.id, 1);
|
|
55
|
+
if (receipts.receipts[0]) {
|
|
56
|
+
this.log('');
|
|
57
|
+
(0, commitment_product_1.renderExecutionReceipt)(receipts.receipts[0], (line) => this.log(line), flags.verbose);
|
|
58
|
+
}
|
|
59
|
+
else
|
|
60
|
+
this.log('No wake has been observed yet.');
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
this.log('Execution receipt is unavailable. Retry with commitments receipt <id> --latest.');
|
|
64
|
+
}
|
|
65
|
+
if (flags.verbose && response.latestCheck) {
|
|
50
66
|
this.log('');
|
|
51
67
|
this.log('Latest check:');
|
|
52
68
|
(0, commitments_1.renderCheckList)([response.latestCheck], (line) => this.log(line));
|
|
53
69
|
this.log('');
|
|
54
70
|
this.log(`Full history: ${this.config.bin} commitments checks ${args.id}`);
|
|
55
71
|
}
|
|
72
|
+
if (flags.verbose)
|
|
73
|
+
this.log(`Compatibility policy: ${JSON.stringify(response.commitment.policy)}`);
|
|
74
|
+
const url = (0, web_url_1.commitmentUrlFrom)(this.cliConfig.baseURL, response.commitment);
|
|
75
|
+
if (url)
|
|
76
|
+
this.log(`URL: ${url}`);
|
|
56
77
|
}
|
|
57
78
|
}
|
|
58
79
|
exports.default = CommitmentsShow;
|
|
@@ -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],
|
|
@@ -76,12 +89,22 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
76
89
|
description: 'Signal Monitor id to watch (repeatable). Implies --watch monitor.',
|
|
77
90
|
multiple: true,
|
|
78
91
|
}),
|
|
79
|
-
cadence: core_1.Flags.string({
|
|
92
|
+
cadence: core_1.Flags.string({
|
|
93
|
+
description: 'New check interval, e.g. "15m", "6h", "30d" (1m..365d)',
|
|
94
|
+
}),
|
|
80
95
|
'cadence-mode': core_1.Flags.string({
|
|
81
96
|
description: 'Cadence mode',
|
|
82
|
-
options: [...commitments_1.
|
|
97
|
+
options: [...commitments_1.COMMITMENT_AUTHORABLE_CADENCE_MODES],
|
|
83
98
|
}),
|
|
84
99
|
timezone: core_1.Flags.string({ description: 'IANA timezone for the cadence' }),
|
|
100
|
+
isolation: core_1.Flags.string({
|
|
101
|
+
// Sent as a single-key `policy` patch. The API deep-merges it, so this
|
|
102
|
+
// cannot blank an autonomy mode or an attention budget set elsewhere.
|
|
103
|
+
description: 'Where autonomous runs do their work: "ephemeral" (one-shot git worktree per run) or ' +
|
|
104
|
+
'"shared" (the daemon working tree, in place). Cannot be combined with a remediation ' +
|
|
105
|
+
'capability.',
|
|
106
|
+
options: [...commitments_1.COMMITMENT_EXECUTION_ISOLATION_MODES],
|
|
107
|
+
}),
|
|
85
108
|
};
|
|
86
109
|
async run() {
|
|
87
110
|
this.requireAuth();
|
|
@@ -115,10 +138,18 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
115
138
|
let payload;
|
|
116
139
|
try {
|
|
117
140
|
payload = await (0, prompt_1.readJsonBody)(flags['from-json']);
|
|
141
|
+
if (flags['if-version'] !== undefined)
|
|
142
|
+
payload.expectedVersion = flags['if-version'];
|
|
118
143
|
if (flags.title)
|
|
119
144
|
payload.title = flags.title;
|
|
120
145
|
if (flags.description !== undefined)
|
|
121
146
|
payload.description = flags.description;
|
|
147
|
+
const agentDirective = await (0, commitments_1.readCommitmentAgentDirective)({
|
|
148
|
+
directive: flags['agent-directive'],
|
|
149
|
+
file: flags['agent-directive-file'],
|
|
150
|
+
});
|
|
151
|
+
if (agentDirective !== undefined)
|
|
152
|
+
payload.agentDirective = agentDirective;
|
|
122
153
|
if (flags.status)
|
|
123
154
|
payload.status = flags.status;
|
|
124
155
|
if (wantsTarget) {
|
|
@@ -189,6 +220,11 @@ class CommitmentsUpdate extends base_command_1.BaseCommand {
|
|
|
189
220
|
cadence.timezone = flags.timezone;
|
|
190
221
|
payload.cadence = cadence;
|
|
191
222
|
}
|
|
223
|
+
// A single key, deliberately. `mergePolicyPatch` on the server merges it
|
|
224
|
+
// into the stored policy, so naming only this field is what keeps the
|
|
225
|
+
// rest of the contract intact.
|
|
226
|
+
if (flags.isolation)
|
|
227
|
+
payload.policy = { executionIsolation: flags.isolation };
|
|
192
228
|
}
|
|
193
229
|
catch (err) {
|
|
194
230
|
this.error(err.message, { exit: 1 });
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export declare function wakePolicyHeadline(result: {
|
|
3
|
+
workPromotionModel?: string;
|
|
4
|
+
}): string;
|
|
2
5
|
/**
|
|
3
6
|
* `skrr commitments wake-capabilities <id>` — which wakes an Agent may pick.
|
|
4
7
|
*
|
|
@@ -10,6 +13,7 @@ import { BaseCommand } from '../../base-command';
|
|
|
10
13
|
* misconfiguration. Showing only one list would make those indistinguishable.
|
|
11
14
|
*/
|
|
12
15
|
export default class CommitmentsWakeCapabilities extends BaseCommand {
|
|
16
|
+
static hidden: boolean;
|
|
13
17
|
static description: string;
|
|
14
18
|
static examples: string[];
|
|
15
19
|
static args: {
|
|
@@ -17,6 +21,7 @@ export default class CommitmentsWakeCapabilities extends BaseCommand {
|
|
|
17
21
|
};
|
|
18
22
|
static flags: {
|
|
19
23
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
24
|
+
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
25
|
};
|
|
21
26
|
run(): Promise<void>;
|
|
22
27
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wakePolicyHeadline = wakePolicyHeadline;
|
|
3
4
|
const core_1 = require("@oclif/core");
|
|
4
5
|
const base_command_1 = require("../../base-command");
|
|
5
6
|
const commitments_1 = require("../../lib/commitments");
|
|
6
7
|
const format_1 = require("../../lib/format");
|
|
8
|
+
function wakePolicyHeadline(result) {
|
|
9
|
+
return result.workPromotionModel === 'monitor_prepare_execute_v1'
|
|
10
|
+
? 'Wake behavior: configured Commitment sources may wake it automatically; there is no separate permission level.'
|
|
11
|
+
: 'Compatibility wake policy is in use. Migrate the Commitment by choosing Monitor, Prepare, or Execute.';
|
|
12
|
+
}
|
|
7
13
|
/**
|
|
8
14
|
* `skrr commitments wake-capabilities <id>` — which wakes an Agent may pick.
|
|
9
15
|
*
|
|
@@ -15,7 +21,10 @@ const format_1 = require("../../lib/format");
|
|
|
15
21
|
* misconfiguration. Showing only one list would make those indistinguishable.
|
|
16
22
|
*/
|
|
17
23
|
class CommitmentsWakeCapabilities extends base_command_1.BaseCommand {
|
|
18
|
-
|
|
24
|
+
// Compatibility/operator diagnostic. Product users configure sources and
|
|
25
|
+
// cadence directly; v2 has no separate wake-permission level.
|
|
26
|
+
static hidden = true;
|
|
27
|
+
static description = 'Inspect configured wake-source diagnostics for a commitment';
|
|
19
28
|
static examples = [
|
|
20
29
|
'<%= config.bin %> commitments wake-capabilities obj_abc123',
|
|
21
30
|
'<%= config.bin %> commitments wake-capabilities obj_abc123 --json',
|
|
@@ -23,7 +32,10 @@ class CommitmentsWakeCapabilities extends base_command_1.BaseCommand {
|
|
|
23
32
|
static args = {
|
|
24
33
|
commitmentId: core_1.Args.string({ ignoreStdin: true, description: 'Commitment ID', required: true }),
|
|
25
34
|
};
|
|
26
|
-
static flags = {
|
|
35
|
+
static flags = {
|
|
36
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
37
|
+
verbose: core_1.Flags.boolean({ description: 'Include raw legacy wake-policy values' }),
|
|
38
|
+
};
|
|
27
39
|
async run() {
|
|
28
40
|
this.requireAuth();
|
|
29
41
|
const { args, flags } = await this.parse(CommitmentsWakeCapabilities);
|
|
@@ -38,11 +50,15 @@ class CommitmentsWakeCapabilities extends base_command_1.BaseCommand {
|
|
|
38
50
|
this.log(JSON.stringify(result, null, 2));
|
|
39
51
|
return;
|
|
40
52
|
}
|
|
41
|
-
|
|
53
|
+
const productModel = result.workPromotionModel === 'monitor_prepare_execute_v1';
|
|
54
|
+
this.log(wakePolicyHeadline(result));
|
|
42
55
|
const selected = result.selectedCapabilityIds;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
56
|
+
if (flags.verbose) {
|
|
57
|
+
this.log(`Raw compatibility mode: ${result.mode}`);
|
|
58
|
+
this.log(selected === undefined
|
|
59
|
+
? 'Raw allowlist: not configured'
|
|
60
|
+
: `Raw allowlist: ${selected.length ? selected.join(', ') : '(empty)'}`);
|
|
61
|
+
}
|
|
46
62
|
this.log('');
|
|
47
63
|
const visible = new Set(result.visibleCapabilities.map((item) => item.id));
|
|
48
64
|
(0, format_1.renderTable)(result.eligibleCapabilities.map((item) => ({
|
|
@@ -54,7 +70,7 @@ class CommitmentsWakeCapabilities extends base_command_1.BaseCommand {
|
|
|
54
70
|
{ key: 'id', header: 'CAPABILITY' },
|
|
55
71
|
{ key: 'kind', header: 'KIND' },
|
|
56
72
|
{ key: 'source', header: 'SOURCE' },
|
|
57
|
-
{ key: 'offered', header: 'OFFERED' },
|
|
73
|
+
{ key: 'offered', header: productModel ? 'ACTIVE' : 'OFFERED' },
|
|
58
74
|
], (line) => this.log(line));
|
|
59
75
|
}
|
|
60
76
|
}
|
|
@@ -60,7 +60,7 @@ class SpacesBootstrap extends base_command_1.BaseCommand {
|
|
|
60
60
|
// one. It names the scope now, and the command prints the server's own
|
|
61
61
|
// contract so the boundary is visible at the point of use rather than buried
|
|
62
62
|
// in a route comment.
|
|
63
|
-
static description = 'Fetch the Space first-paint payload (space, summary,
|
|
63
|
+
static description = 'Fetch the Space first-paint payload (space, summary, and permissions). ' +
|
|
64
64
|
'NOT a complete Space export — tasks, members, Room, files and wiki have their own commands; ' +
|
|
65
65
|
'the printed contract names each one.';
|
|
66
66
|
static examples = [
|
|
@@ -22,6 +22,38 @@ const task_transcript_1 = require("../../lib/task-transcript");
|
|
|
22
22
|
const web_url_1 = require("../../lib/web-url");
|
|
23
23
|
const tasks_1 = require("../../lib/tasks");
|
|
24
24
|
const git_task_1 = require("../../lib/git-task");
|
|
25
|
+
/**
|
|
26
|
+
* Forward any `--deliverable` value that is really a ledger coordinate.
|
|
27
|
+
*
|
|
28
|
+
* FAIL-OPEN, and quietly. This is a convenience bridge on the completion path:
|
|
29
|
+
* the completion itself is the operation the caller asked for, and a ledger
|
|
30
|
+
* write that fails must not take it down. A caller who needed the row and did
|
|
31
|
+
* not get it meets the gate's refusal, which names the command that writes it.
|
|
32
|
+
*
|
|
33
|
+
* `local`, never anything stronger — this is the executor talking about its own
|
|
34
|
+
* work, which is exactly what the authority ladder is built to weigh.
|
|
35
|
+
*/
|
|
36
|
+
async function recordCoordinateDeliverables({ taskId, values, warn, }) {
|
|
37
|
+
const seen = new Set();
|
|
38
|
+
for (const value of values) {
|
|
39
|
+
const raw = (value ?? '').trim();
|
|
40
|
+
if (!raw || raw === 'none' || seen.has(raw)) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
seen.add(raw);
|
|
44
|
+
const parsed = (0, tasks_1.parseDeliverableCoordinate)(raw);
|
|
45
|
+
if (!parsed.ok) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
await data_provider_1.dataService.addTaskDeliverable(taskId, parsed.value);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
warn(`Recorded "${raw}" in the report but not in the deliverables ledger. ` +
|
|
53
|
+
`If the task refuses to close, run \`tasks deliverable add\` for it.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
25
57
|
/**
|
|
26
58
|
* Mutation endpoints require the task's canonical UUID even though the CLI
|
|
27
59
|
* accepts human-readable refs and titles. Resolve the display reference before
|
|
@@ -483,6 +515,31 @@ class TasksComplete extends base_command_1.BaseCommand {
|
|
|
483
515
|
});
|
|
484
516
|
}
|
|
485
517
|
}
|
|
518
|
+
// THE THIRD SPELLING, BRIDGED.
|
|
519
|
+
//
|
|
520
|
+
// `--deliverable` here is PROSE for the TASK_OUTPUT block. The ledger the
|
|
521
|
+
// completion gate reads is written by `tasks deliverable add`, and nothing
|
|
522
|
+
// connected the two — so an agent that ran
|
|
523
|
+
// `tasks complete --deliverable code:abc@origin/main` had, from its own
|
|
524
|
+
// point of view, recorded its deliverable, and was then refused by a gate
|
|
525
|
+
// whose message told it to record its deliverable.
|
|
526
|
+
//
|
|
527
|
+
// Three surfaces in one CLI answer to the word (`tasks deliverable add`,
|
|
528
|
+
// this flag, and `tasks report --deliverable`), and the project's own
|
|
529
|
+
// operating instructions teach the two that do NOT write the ledger. That
|
|
530
|
+
// is a documentation problem only if you believe people read the docs
|
|
531
|
+
// before the error; the cheaper fix is to make the wrong spelling do the
|
|
532
|
+
// right thing when what was typed is unambiguously a coordinate.
|
|
533
|
+
//
|
|
534
|
+
// Deliberately narrow: only values that PARSE as `<kind>:<identity>` are
|
|
535
|
+
// forwarded. A prose reference like `report.pdf` is left exactly as it was —
|
|
536
|
+
// guessing a coordinate out of prose is how the ledger fills with rows
|
|
537
|
+
// nobody can look up again.
|
|
538
|
+
await recordCoordinateDeliverables({
|
|
539
|
+
taskId: completionTaskId,
|
|
540
|
+
values: [...(flags.deliverable ?? []), ...(flags.deliverables ?? [])],
|
|
541
|
+
warn: (message) => this.warn(message),
|
|
542
|
+
});
|
|
486
543
|
let result;
|
|
487
544
|
try {
|
|
488
545
|
result = await completeTaskDurably({
|
|
@@ -71,7 +71,8 @@ class TasksCreate extends base_command_1.BaseCommand {
|
|
|
71
71
|
description: 'Validate and print the create payload without writing a task',
|
|
72
72
|
}),
|
|
73
73
|
'from-json': core_1.Flags.string({
|
|
74
|
-
description: 'Path to a JSON file (or "-" for stdin) to use as the request body'
|
|
74
|
+
description: 'Path to a JSON file (or "-" for stdin) to use as the request body. ' +
|
|
75
|
+
'Accepts stored names (projectId, goalId) and create-flag aliases (project, goal, spawnedBy).',
|
|
75
76
|
}),
|
|
76
77
|
template: core_1.Flags.string({
|
|
77
78
|
description: 'Saved task template ID, or an exact template name with --space. Creates its whole task tree; supplied task flags override the root.',
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr tasks deliverable confirm <task> <kind>:<identity>[@<location>] --reason "<what you checked>"`
|
|
4
|
+
*
|
|
5
|
+
* Somebody looked, and it is there.
|
|
6
|
+
*
|
|
7
|
+
* WHY THIS IS A SEPARATE COMMAND from `deliverable add`. Recording and vouching
|
|
8
|
+
* are different claims. `add` says "this exists, and I am the one who made it";
|
|
9
|
+
* this says "I checked, independently of whoever made it". Five of the six
|
|
10
|
+
* outcome kinds have no automatic observer — nothing in the platform watches a
|
|
11
|
+
* Drive folder or a Slack channel — so without this rung an expectation for a
|
|
12
|
+
* PDF or a posted message could only ever be closed by waiving it, which
|
|
13
|
+
* records "we decided we did not need this" about work that was actually done.
|
|
14
|
+
*
|
|
15
|
+
* The reason is required, for the same purpose a waiver's and a judgement's
|
|
16
|
+
* are: the entire value of a confirmation is that a person actually looked, and
|
|
17
|
+
* a confirmation with nothing written down is indistinguishable from a click.
|
|
18
|
+
*
|
|
19
|
+
* It UPSERTS. Confirming something the executor never recorded is legitimate —
|
|
20
|
+
* the thing is there either way — and making a person file the row first before
|
|
21
|
+
* they may vouch for it is ceremony that buys nothing.
|
|
22
|
+
*/
|
|
23
|
+
export default class TasksDeliverableConfirm extends BaseCommand {
|
|
24
|
+
static description: string;
|
|
25
|
+
static examples: string[];
|
|
26
|
+
static args: {
|
|
27
|
+
task: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
28
|
+
coordinate: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
29
|
+
};
|
|
30
|
+
static flags: {
|
|
31
|
+
reason: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
32
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
33
|
+
};
|
|
34
|
+
run(): Promise<void>;
|
|
35
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
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 tasks_1 = require("../../../lib/tasks");
|
|
7
|
+
/**
|
|
8
|
+
* `skrr tasks deliverable confirm <task> <kind>:<identity>[@<location>] --reason "<what you checked>"`
|
|
9
|
+
*
|
|
10
|
+
* Somebody looked, and it is there.
|
|
11
|
+
*
|
|
12
|
+
* WHY THIS IS A SEPARATE COMMAND from `deliverable add`. Recording and vouching
|
|
13
|
+
* are different claims. `add` says "this exists, and I am the one who made it";
|
|
14
|
+
* this says "I checked, independently of whoever made it". Five of the six
|
|
15
|
+
* outcome kinds have no automatic observer — nothing in the platform watches a
|
|
16
|
+
* Drive folder or a Slack channel — so without this rung an expectation for a
|
|
17
|
+
* PDF or a posted message could only ever be closed by waiving it, which
|
|
18
|
+
* records "we decided we did not need this" about work that was actually done.
|
|
19
|
+
*
|
|
20
|
+
* The reason is required, for the same purpose a waiver's and a judgement's
|
|
21
|
+
* are: the entire value of a confirmation is that a person actually looked, and
|
|
22
|
+
* a confirmation with nothing written down is indistinguishable from a click.
|
|
23
|
+
*
|
|
24
|
+
* It UPSERTS. Confirming something the executor never recorded is legitimate —
|
|
25
|
+
* the thing is there either way — and making a person file the row first before
|
|
26
|
+
* they may vouch for it is ceremony that buys nothing.
|
|
27
|
+
*/
|
|
28
|
+
class TasksDeliverableConfirm extends base_command_1.BaseCommand {
|
|
29
|
+
static description = 'Confirm you checked a deliverable and it is there — the evidence an expectation needs when nothing observes it automatically';
|
|
30
|
+
static examples = [
|
|
31
|
+
'<%= config.bin %> tasks deliverable confirm <task-id> file/pdf:report_92@Drive/Reports --reason "Opened it; all four sections are there."',
|
|
32
|
+
'<%= config.bin %> tasks deliverable confirm <task-id> message:m_51@#general --reason "Read the thread; it went out at 09:04."',
|
|
33
|
+
];
|
|
34
|
+
static args = {
|
|
35
|
+
task: core_1.Args.string({ description: 'Task id or ref', required: true, ignoreStdin: true }),
|
|
36
|
+
coordinate: core_1.Args.string({
|
|
37
|
+
description: '<kind>[/<format>]:<identity>[@<location>] — the thing you checked',
|
|
38
|
+
required: true,
|
|
39
|
+
ignoreStdin: true,
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
static flags = {
|
|
43
|
+
reason: core_1.Flags.string({
|
|
44
|
+
required: true,
|
|
45
|
+
description: 'What you looked at. A confirmation without one is not a confirmation.',
|
|
46
|
+
}),
|
|
47
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
48
|
+
};
|
|
49
|
+
async run() {
|
|
50
|
+
this.requireAuth();
|
|
51
|
+
const { args, flags } = await this.parse(TasksDeliverableConfirm);
|
|
52
|
+
const parsed = (0, tasks_1.parseDeliverableCoordinate)(args.coordinate);
|
|
53
|
+
if (!parsed.ok) {
|
|
54
|
+
// For an agent the refusal IS the documentation — it hits the error and
|
|
55
|
+
// corrects — so it carries the whole form and vocabulary.
|
|
56
|
+
this.error(parsed.error, { exit: 1 });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
let result;
|
|
60
|
+
try {
|
|
61
|
+
result = await data_provider_1.dataService.confirmTaskDeliverable(args.task, {
|
|
62
|
+
...parsed.value,
|
|
63
|
+
reason: flags.reason,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
this.handleApiError(err);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (flags.json) {
|
|
71
|
+
this.log(JSON.stringify(result, null, 2));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.log(`Confirmed ${parsed.value.kind}:${parsed.value.identity}: ${flags.reason}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.default = TasksDeliverableConfirm;
|
|
@@ -15,6 +15,10 @@ const STATE_LABEL = {
|
|
|
15
15
|
met: 'done',
|
|
16
16
|
waived: 'dropped',
|
|
17
17
|
blocked: 'stuck',
|
|
18
|
+
// Its own word, because its next action is its own: somebody looks, rather
|
|
19
|
+
// than somebody works. Reading it as 'not yet' sends people to redo finished
|
|
20
|
+
// work, which is precisely the confusion the state was added to remove.
|
|
21
|
+
unverified: 'needs a look',
|
|
18
22
|
underway: 'on its way',
|
|
19
23
|
owed: 'not yet',
|
|
20
24
|
unjudged: 'needs a person',
|
|
@@ -26,7 +30,13 @@ function line(expectation) {
|
|
|
26
30
|
// trusted.
|
|
27
31
|
const gate = expectation.gating ? '' : ' (does not block completion)';
|
|
28
32
|
const from = expectation.source === 'space' ? ' [space default]' : '';
|
|
29
|
-
|
|
33
|
+
// Only shown when the work exists and the evidence is short — stating the
|
|
34
|
+
// required authority on every row would be noise on the rows where it is
|
|
35
|
+
// already satisfied or not yet relevant.
|
|
36
|
+
const evidence = expectation.state === 'unverified'
|
|
37
|
+
? ` (has ${expectation.evidenceAuthority}, needs ${expectation.requiredAuthority})`
|
|
38
|
+
: '';
|
|
39
|
+
return ` ${expectation.id.padEnd(18)} ${label.padEnd(14)} ${expectation.sentence}${evidence}${gate}${from}`;
|
|
30
40
|
}
|
|
31
41
|
class TasksExpectations extends base_command_1.BaseCommand {
|
|
32
42
|
static description = 'Show what a task must produce and how far each expectation got ("Done when")';
|
|
@@ -83,6 +93,15 @@ class TasksExpectations extends base_command_1.BaseCommand {
|
|
|
83
93
|
if (settleable > 0) {
|
|
84
94
|
this.log(`${settleable} awaiting a person — settle with \`${this.config.bin} tasks judge\`.`);
|
|
85
95
|
}
|
|
96
|
+
// Named separately from `unjudged`, and with a different command, because
|
|
97
|
+
// the two look alike on the board and are not: one needs a verdict on prose,
|
|
98
|
+
// the other needs somebody to look at a thing that already exists.
|
|
99
|
+
const unverified = acceptance.expectations.filter((e) => e.state === 'unverified').length;
|
|
100
|
+
if (unverified > 0) {
|
|
101
|
+
this.log(`${unverified} produced but not vouched for — confirm with ` +
|
|
102
|
+
`\`${this.config.bin} tasks deliverable confirm\`, or lower the bar with ` +
|
|
103
|
+
`\`${this.config.bin} tasks trust\`.`);
|
|
104
|
+
}
|
|
86
105
|
const inherited = acceptance.unjudged - settleable;
|
|
87
106
|
if (inherited > 0) {
|
|
88
107
|
this.log(`${inherited} inherited from the space default — declare them on the task to settle them.`);
|