@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.
Files changed (107) hide show
  1. package/README.md +3 -0
  2. package/dist/base-command.d.ts +14 -0
  3. package/dist/base-command.js +60 -1
  4. package/dist/commands/agents/create.d.ts +1 -0
  5. package/dist/commands/agents/create.js +6 -1
  6. package/dist/commands/agents/instructions/add.d.ts +21 -0
  7. package/dist/commands/agents/instructions/add.js +115 -0
  8. package/dist/commands/agents/instructions/disable.d.ts +13 -0
  9. package/dist/commands/agents/instructions/disable.js +50 -0
  10. package/dist/commands/agents/instructions/edit.d.ts +16 -0
  11. package/dist/commands/agents/instructions/edit.js +79 -0
  12. package/dist/commands/agents/instructions/enable.d.ts +13 -0
  13. package/dist/commands/agents/instructions/enable.js +50 -0
  14. package/dist/commands/agents/instructions/move.d.ts +15 -0
  15. package/dist/commands/agents/instructions/move.js +61 -0
  16. package/dist/commands/agents/instructions/preview.d.ts +13 -0
  17. package/dist/commands/agents/instructions/preview.js +59 -0
  18. package/dist/commands/agents/instructions/remove.d.ts +13 -0
  19. package/dist/commands/agents/instructions/remove.js +49 -0
  20. package/dist/commands/agents/instructions/set.d.ts +17 -0
  21. package/dist/commands/agents/instructions/set.js +79 -0
  22. package/dist/commands/agents/instructions/show.d.ts +15 -0
  23. package/dist/commands/agents/instructions/show.js +76 -0
  24. package/dist/commands/agents/instructions/upgrade.d.ts +16 -0
  25. package/dist/commands/agents/instructions/upgrade.js +77 -0
  26. package/dist/commands/agents/show.js +5 -0
  27. package/dist/commands/agents/triggers/policy.js +8 -2
  28. package/dist/commands/agents/update.d.ts +1 -0
  29. package/dist/commands/agents/update.js +8 -2
  30. package/dist/commands/commitments/autonomy.js +9 -1
  31. package/dist/commands/commitments/create.d.ts +8 -5
  32. package/dist/commands/commitments/create.js +38 -8
  33. package/dist/commands/commitments/doctor.d.ts +19 -0
  34. package/dist/commands/commitments/doctor.js +72 -0
  35. package/dist/commands/commitments/preflight.d.ts +3 -1
  36. package/dist/commands/commitments/preflight.js +25 -3
  37. package/dist/commands/commitments/reports.js +15 -2
  38. package/dist/commands/commitments/update.d.ts +9 -2
  39. package/dist/commands/commitments/update.js +36 -2
  40. package/dist/commands/daemon/index.js +2 -0
  41. package/dist/commands/daemon/recover-offline-queue.d.ts +9 -0
  42. package/dist/commands/daemon/recover-offline-queue.js +24 -0
  43. package/dist/commands/daemon/start.js +29 -1
  44. package/dist/commands/instruction-blocks/create.d.ts +19 -0
  45. package/dist/commands/instruction-blocks/create.js +94 -0
  46. package/dist/commands/instruction-blocks/delete.d.ts +13 -0
  47. package/dist/commands/instruction-blocks/delete.js +35 -0
  48. package/dist/commands/instruction-blocks/list.d.ts +13 -0
  49. package/dist/commands/instruction-blocks/list.js +71 -0
  50. package/dist/commands/instruction-blocks/show.d.ts +12 -0
  51. package/dist/commands/instruction-blocks/show.js +35 -0
  52. package/dist/commands/instruction-blocks/update.d.ts +23 -0
  53. package/dist/commands/instruction-blocks/update.js +94 -0
  54. package/dist/commands/spaces/auto-executor/preview.d.ts +1 -0
  55. package/dist/commands/spaces/auto-executor/preview.js +62 -3
  56. package/dist/commands/spaces/auto-executor/update.d.ts +4 -0
  57. package/dist/commands/spaces/auto-executor/update.js +78 -7
  58. package/dist/commands/spaces/capacity.js +14 -2
  59. package/dist/commands/spaces/update.d.ts +4 -0
  60. package/dist/commands/spaces/update.js +49 -2
  61. package/dist/commands/tasks/complete.d.ts +12 -5
  62. package/dist/commands/tasks/complete.js +107 -28
  63. package/dist/commands/tasks/continue-ready.js +9 -1
  64. package/dist/commands/tasks/create.d.ts +1 -0
  65. package/dist/commands/tasks/create.js +27 -2
  66. package/dist/commands/tasks/deliverable/add.d.ts +23 -0
  67. package/dist/commands/tasks/deliverable/add.js +70 -0
  68. package/dist/commands/tasks/deliverable/confirm.d.ts +35 -0
  69. package/dist/commands/tasks/deliverable/confirm.js +77 -0
  70. package/dist/commands/tasks/events/append.d.ts +1 -1
  71. package/dist/commands/tasks/events/append.js +4 -4
  72. package/dist/commands/tasks/expectations.d.ts +12 -0
  73. package/dist/commands/tasks/expectations.js +111 -0
  74. package/dist/commands/tasks/judge.d.ts +29 -0
  75. package/dist/commands/tasks/judge.js +68 -0
  76. package/dist/commands/tasks/report.d.ts +1 -1
  77. package/dist/commands/tasks/report.js +27 -3
  78. package/dist/commands/tasks/trust.d.ts +35 -0
  79. package/dist/commands/tasks/trust.js +75 -0
  80. package/dist/commands/tasks/update.d.ts +1 -0
  81. package/dist/commands/tasks/update.js +34 -4
  82. package/dist/commands/tasks/waive.d.ts +25 -0
  83. package/dist/commands/tasks/waive.js +58 -0
  84. package/dist/lib/agent-config.js +5 -0
  85. package/dist/lib/agent-instructions.d.ts +15 -0
  86. package/dist/lib/agent-instructions.js +55 -0
  87. package/dist/lib/command-hygiene.d.ts +6 -1
  88. package/dist/lib/command-hygiene.js +49 -29
  89. package/dist/lib/commitments.d.ts +28 -3
  90. package/dist/lib/commitments.js +20 -11
  91. package/dist/lib/exec-runtime-binary.d.ts +13 -0
  92. package/dist/lib/exec-runtime-binary.js +45 -0
  93. package/dist/lib/git-task.d.ts +37 -0
  94. package/dist/lib/git-task.js +151 -0
  95. package/dist/lib/instruction-blocks.d.ts +29 -0
  96. package/dist/lib/instruction-blocks.js +159 -0
  97. package/dist/lib/runtime-start-verification.d.ts +49 -0
  98. package/dist/lib/runtime-start-verification.js +108 -0
  99. package/dist/lib/task-execution.d.ts +18 -2
  100. package/dist/lib/task-execution.js +19 -14
  101. package/dist/lib/task-transcript.js +1 -1
  102. package/dist/lib/tasks.d.ts +50 -0
  103. package/dist/lib/tasks.js +93 -2
  104. package/dist/node_modules/@skrr-ai/data-provider/index.js +2393 -2197
  105. package/dist/node_modules/@skrr-ai/inference-broker/package.json +1 -1
  106. package/oclif.manifest.json +17725 -15563
  107. package/package.json +4 -1
@@ -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,7 +15,7 @@ export default class TasksEventsAppend extends BaseCommand {
15
15
  changed: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
16
  next: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
17
  evidence: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
- artifact: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ deliverable: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
19
  };
20
20
  run(): Promise<void>;
21
21
  }
@@ -15,7 +15,7 @@ class TasksEventsAppend extends base_command_1.BaseCommand {
15
15
  static examples = [
16
16
  '<%= config.bin %> tasks events append <task-id> --kind checkpoint --idempotency-key "<task-id>:first-pass" --summary "Parser handles nested fences"',
17
17
  '<%= config.bin %> tasks events append <task-id> --kind decision --idempotency-key "<task-id>:storage-choice" --summary "Chose the CRDT path" --evidence "A direct contentHtml write is reverted by the next render tick"',
18
- '<%= config.bin %> tasks events append <task-id> --kind verification --idempotency-key "<task-id>:verified" --summary "Repro no longer reproduces" --artifact <commit-sha>',
18
+ '<%= config.bin %> tasks events append <task-id> --kind verification --idempotency-key "<task-id>:verified" --summary "Repro no longer reproduces" --deliverable <commit-sha>',
19
19
  ];
20
20
  static args = {
21
21
  id: core_1.Args.string({
@@ -54,9 +54,9 @@ class TasksEventsAppend extends base_command_1.BaseCommand {
54
54
  evidence: core_1.Flags.string({
55
55
  description: 'Why it is true — an observation, command output, or a before → after',
56
56
  }),
57
- artifact: core_1.Flags.string({
57
+ deliverable: core_1.Flags.string({
58
58
  multiple: true,
59
- description: 'Durable reference: a file path, commit sha, or URL. Repeatable. "in the conversation" is not an artifact',
59
+ description: 'Durable reference: a file path, commit sha, or URL. Repeatable. "in the conversation" is not a deliverable',
60
60
  }),
61
61
  };
62
62
  async run() {
@@ -70,7 +70,7 @@ class TasksEventsAppend extends base_command_1.BaseCommand {
70
70
  changed: flags.changed,
71
71
  next: flags.next,
72
72
  evidence: flags.evidence,
73
- artifacts: flags.artifact?.map((ref) => ({ label: 'artifact', ref })),
73
+ artifacts: flags.deliverable?.map((ref) => ({ label: 'deliverable', ref })),
74
74
  };
75
75
  const path = await (0, session_task_endpoints_1.sessionScopedTaskPath)('event');
76
76
  let result;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ export default class TasksExpectations extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ task: 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,111 @@
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
+ /**
7
+ * `skrr tasks expectations <task>` — what this task owes, and how far each got.
8
+ *
9
+ * Reads the SERVER's verdict rather than recomputing one. The judge and the
10
+ * completion gate are the same module, so a CLI that decided "met" for itself
11
+ * could disagree with the gate that refuses the task — and the reader would
12
+ * have no way to tell which was lying.
13
+ */
14
+ const STATE_LABEL = {
15
+ met: 'done',
16
+ waived: 'dropped',
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',
22
+ underway: 'on its way',
23
+ owed: 'not yet',
24
+ unjudged: 'needs a person',
25
+ };
26
+ function line(expectation) {
27
+ const label = STATE_LABEL[expectation.state] || expectation.state;
28
+ // A judged expectation is stated as NOT a gate. A list that reads like a
29
+ // contract while enforcing nothing is worse than no list, because it is
30
+ // trusted.
31
+ const gate = expectation.gating ? '' : ' (does not block completion)';
32
+ const from = expectation.source === 'space' ? ' [space default]' : '';
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}`;
40
+ }
41
+ class TasksExpectations extends base_command_1.BaseCommand {
42
+ static description = 'Show what a task must produce and how far each expectation got ("Done when")';
43
+ static examples = [
44
+ '<%= config.bin %> tasks expectations <task-id>',
45
+ '<%= config.bin %> tasks expectations <task-id> --json',
46
+ ];
47
+ static args = {
48
+ task: core_1.Args.string({ description: 'Task id or ref', required: true, ignoreStdin: true }),
49
+ };
50
+ static flags = {
51
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
52
+ };
53
+ async run() {
54
+ this.requireAuth();
55
+ const { args, flags } = await this.parse(TasksExpectations);
56
+ let acceptance;
57
+ try {
58
+ acceptance = await data_provider_1.dataService.getTaskAcceptance(args.task);
59
+ }
60
+ catch (err) {
61
+ this.handleApiError(err);
62
+ return;
63
+ }
64
+ if (flags.json) {
65
+ this.log(JSON.stringify(acceptance, null, 2));
66
+ return;
67
+ }
68
+ if (acceptance.expectations.length === 0) {
69
+ // An empty contract is a real answer, not an unfilled field. Say so
70
+ // plainly rather than prompting for something most tasks do not owe.
71
+ this.log('Nothing durable is expected of this task.');
72
+ return;
73
+ }
74
+ // The evidence read fails OPEN by design, so "produced nothing" and "we
75
+ // could not look" are indistinguishable downstream unless the server says
76
+ // which happened. Never print the first when it might be the second.
77
+ if (!acceptance.evidenceRead) {
78
+ this.warn('Could not read what this task produced — the states below may understate it. ' +
79
+ 'This is not a claim that nothing was produced.');
80
+ }
81
+ this.log('Done when:');
82
+ for (const expectation of acceptance.expectations) {
83
+ this.log(line(expectation));
84
+ }
85
+ const gating = acceptance.expectations.filter((e) => e.gating);
86
+ const met = gating.filter((e) => e.met).length;
87
+ this.log('');
88
+ this.log(`${met} of ${gating.length} met · overall: ${acceptance.state}`);
89
+ // Only the ones actually stored on the task can be judged. A space default
90
+ // is synthesised per read, so pointing at `tasks judge` for one would send
91
+ // the reader at a command that can only refuse it.
92
+ const settleable = acceptance.expectations.filter((e) => e.state === 'unjudged' && e.source !== 'space').length;
93
+ if (settleable > 0) {
94
+ this.log(`${settleable} awaiting a person — settle with \`${this.config.bin} tasks judge\`.`);
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
+ }
105
+ const inherited = acceptance.unjudged - settleable;
106
+ if (inherited > 0) {
107
+ this.log(`${inherited} inherited from the space default — declare them on the task to settle them.`);
108
+ }
109
+ }
110
+ }
111
+ exports.default = TasksExpectations;
@@ -0,0 +1,29 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr tasks judge <task> <expectation-id> --verdict met --reason "<why>"`
4
+ *
5
+ * Settle a `judged` expectation — one whose text nothing here can evaluate.
6
+ *
7
+ * Only a judged one. A checkable expectation is settled by recording what was
8
+ * produced, and letting a person mark it met by hand would make the deliverables
9
+ * ledger optional, which is the same as not having one. The server refuses that
10
+ * case with an error naming the command to use instead.
11
+ *
12
+ * The reason is REQUIRED, for the same purpose a waiver's is: a verdict with no
13
+ * reason is indistinguishable from a click, and the entire value of a judged
14
+ * expectation is that somebody actually looked.
15
+ */
16
+ export default class TasksJudge extends BaseCommand {
17
+ static description: string;
18
+ static examples: string[];
19
+ static args: {
20
+ task: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
21
+ expectation: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
22
+ };
23
+ static flags: {
24
+ verdict: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ reason: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
27
+ };
28
+ run(): Promise<void>;
29
+ }
@@ -0,0 +1,68 @@
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
+ /**
7
+ * `skrr tasks judge <task> <expectation-id> --verdict met --reason "<why>"`
8
+ *
9
+ * Settle a `judged` expectation — one whose text nothing here can evaluate.
10
+ *
11
+ * Only a judged one. A checkable expectation is settled by recording what was
12
+ * produced, and letting a person mark it met by hand would make the deliverables
13
+ * ledger optional, which is the same as not having one. The server refuses that
14
+ * case with an error naming the command to use instead.
15
+ *
16
+ * The reason is REQUIRED, for the same purpose a waiver's is: a verdict with no
17
+ * reason is indistinguishable from a click, and the entire value of a judged
18
+ * expectation is that somebody actually looked.
19
+ */
20
+ class TasksJudge extends base_command_1.BaseCommand {
21
+ static description = 'Settle a judged expectation with a verdict and a stated reason';
22
+ static examples = [
23
+ '<%= config.bin %> tasks judge <task-id> e2 --verdict met --reason "Read it end to end; a non-engineer follows it."',
24
+ '<%= config.bin %> tasks judge <task-id> e2 --verdict unmet --reason "Still assumes the reader knows the schema."',
25
+ ];
26
+ static args = {
27
+ task: core_1.Args.string({ description: 'Task id or ref', required: true, ignoreStdin: true }),
28
+ expectation: core_1.Args.string({
29
+ description: 'Expectation id (see `tasks expectations`)',
30
+ required: true,
31
+ ignoreStdin: true,
32
+ }),
33
+ };
34
+ static flags = {
35
+ verdict: core_1.Flags.string({
36
+ options: ['met', 'unmet'],
37
+ required: true,
38
+ description: 'Whether the expectation was met.',
39
+ }),
40
+ reason: core_1.Flags.string({
41
+ required: true,
42
+ description: 'What you looked at. A verdict without one is not a judgement.',
43
+ }),
44
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
45
+ };
46
+ async run() {
47
+ this.requireAuth();
48
+ const { args, flags } = await this.parse(TasksJudge);
49
+ let result;
50
+ try {
51
+ result = await data_provider_1.dataService.judgeTaskExpectation(args.task, {
52
+ expectationId: args.expectation,
53
+ verdict: flags.verdict,
54
+ reason: flags.reason,
55
+ });
56
+ }
57
+ catch (err) {
58
+ this.handleApiError(err);
59
+ return;
60
+ }
61
+ if (flags.json) {
62
+ this.log(JSON.stringify(result, null, 2));
63
+ return;
64
+ }
65
+ this.log(`Recorded ${args.expectation} as ${flags.verdict}: ${flags.reason}`);
66
+ }
67
+ }
68
+ exports.default = TasksJudge;
@@ -18,7 +18,7 @@ export default class TasksReport extends BaseCommand {
18
18
  finding: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
19
  evidence: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
20
  next: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
21
- artifact: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
21
+ deliverable: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
22
  };
23
23
  run(): Promise<void>;
24
24
  }
@@ -7,6 +7,7 @@ const api_fetch_1 = require("../../lib/api-fetch");
7
7
  const outbox_1 = require("../../lib/outbox");
8
8
  const task_report_1 = require("../../lib/task-report");
9
9
  const task_resolver_1 = require("../../lib/task-resolver");
10
+ const tasks_1 = require("../../lib/tasks");
10
11
  const session_task_endpoints_1 = require("../../lib/session-task-endpoints");
11
12
  const web_url_1 = require("../../lib/web-url");
12
13
  /**
@@ -18,7 +19,7 @@ class TasksReport extends base_command_1.BaseCommand {
18
19
  static description = 'Record a self-contained outcome, findings, evidence, and next actions';
19
20
  static examples = [
20
21
  '<%= config.bin %> tasks report <task-id> --outcome "Adopt the event ledger" --finding "The task page omits work-event details" --evidence "Task detail reads only legacy activity" --next "Add an Outcome section"',
21
- '<%= config.bin %> tasks report <task-id> --kind handoff --outcome "Ready for review" --finding "All acceptance criteria are met" --artifact "src/task.ts" --json',
22
+ '<%= config.bin %> tasks report <task-id> --kind handoff --outcome "Ready for review" --finding "All acceptance criteria are met" --deliverable "src/task.ts" --json',
22
23
  ];
23
24
  static args = {
24
25
  id: core_1.Args.string({
@@ -48,7 +49,7 @@ class TasksReport extends base_command_1.BaseCommand {
48
49
  multiple: true,
49
50
  }),
50
51
  next: core_1.Flags.string({ description: 'A follow-up or next action (repeatable)', multiple: true }),
51
- artifact: core_1.Flags.string({
52
+ deliverable: core_1.Flags.string({
52
53
  description: 'Durable file, commit, PR, or URL (repeatable)',
53
54
  multiple: true,
54
55
  }),
@@ -92,8 +93,31 @@ class TasksReport extends base_command_1.BaseCommand {
92
93
  idempotencyKey: (0, outbox_1.idempotencyKeyFor)('task-report', task.id, JSON.stringify({ report, kind: flags.kind })),
93
94
  kind,
94
95
  ...(0, task_report_1.taskReportEventFields)(report),
95
- artifacts: flags.artifact?.map((ref) => ({ label: 'artifact', ref })),
96
+ artifacts: flags.deliverable?.map((ref) => ({ label: 'deliverable', ref })),
96
97
  };
98
+ // THE SAME BRIDGE `tasks complete` CARRIES, for the same reason.
99
+ //
100
+ // `--deliverable` here is prose for a work event's `artifacts` list, and
101
+ // the ledger the completion gate reads is written by `tasks deliverable
102
+ // add`. Three commands in this CLI answer to the word and only one of them
103
+ // writes the ledger — and the project's own operating instructions teach
104
+ // this spelling. So a value that is unambiguously a coordinate is forwarded
105
+ // to the ledger too; prose is left exactly as it was, because guessing a
106
+ // coordinate out of prose fills the ledger with rows nobody can look up.
107
+ for (const ref of flags.deliverable ?? []) {
108
+ const parsed = (0, tasks_1.parseDeliverableCoordinate)(ref);
109
+ if (!parsed.ok) {
110
+ continue;
111
+ }
112
+ try {
113
+ await data_provider_1.dataService.addTaskDeliverable(task.id, parsed.value);
114
+ }
115
+ catch {
116
+ // Best-effort: a report must still be posted when the ledger write
117
+ // fails, and the completion gate's refusal names the command that
118
+ // writes it.
119
+ }
120
+ }
97
121
  const sessionPath = await (0, session_task_endpoints_1.sessionScopedTaskPath)('event');
98
122
  let result;
99
123
  try {
@@ -0,0 +1,35 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr tasks trust <task> <expectation-id> --level <authority> --reason "<why>"`
4
+ *
5
+ * Move how much evidence one expectation demands.
6
+ *
7
+ * A DECISION, not an edit — which is why it is its own command rather than a
8
+ * field on `tasks update`. It is the one control that turns a refusal into a
9
+ * pass with no new work done, so a reader later has to be able to see that it
10
+ * happened and why. Buried in a list patch it would record neither.
11
+ *
12
+ * Lowering is the common direction and it is legitimate: a contract that cannot
13
+ * express "an agent's word is enough for this one" pushes its authors back to
14
+ * declaring nothing at all, which is the failure the whole feature exists to
15
+ * end. Raising takes the same reason and costs nothing to allow.
16
+ *
17
+ * The three levels, weakest first:
18
+ * self_reported whoever did the work says it is done
19
+ * human_confirmed someone else looked and said so
20
+ * observation_backed the platform saw it itself (a merge webhook, an upload)
21
+ */
22
+ export default class TasksTrust extends BaseCommand {
23
+ static description: string;
24
+ static examples: string[];
25
+ static args: {
26
+ task: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
27
+ expectation: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
28
+ };
29
+ static flags: {
30
+ level: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
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,75 @@
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
+ /**
7
+ * `skrr tasks trust <task> <expectation-id> --level <authority> --reason "<why>"`
8
+ *
9
+ * Move how much evidence one expectation demands.
10
+ *
11
+ * A DECISION, not an edit — which is why it is its own command rather than a
12
+ * field on `tasks update`. It is the one control that turns a refusal into a
13
+ * pass with no new work done, so a reader later has to be able to see that it
14
+ * happened and why. Buried in a list patch it would record neither.
15
+ *
16
+ * Lowering is the common direction and it is legitimate: a contract that cannot
17
+ * express "an agent's word is enough for this one" pushes its authors back to
18
+ * declaring nothing at all, which is the failure the whole feature exists to
19
+ * end. Raising takes the same reason and costs nothing to allow.
20
+ *
21
+ * The three levels, weakest first:
22
+ * self_reported whoever did the work says it is done
23
+ * human_confirmed someone else looked and said so
24
+ * observation_backed the platform saw it itself (a merge webhook, an upload)
25
+ */
26
+ class TasksTrust extends base_command_1.BaseCommand {
27
+ static description = 'Set how much evidence one expectation demands, with a stated reason';
28
+ static examples = [
29
+ '<%= config.bin %> tasks trust <task-id> e1 --level self_reported --reason "Internal draft; nobody else needs to check it."',
30
+ '<%= config.bin %> tasks trust <task-id> e2 --level observation_backed --reason "Customer-facing; I want the platform to see it land."',
31
+ ];
32
+ static args = {
33
+ task: core_1.Args.string({ description: 'Task id or ref', required: true, ignoreStdin: true }),
34
+ expectation: core_1.Args.string({
35
+ description: 'Expectation id (see `tasks expectations`)',
36
+ required: true,
37
+ ignoreStdin: true,
38
+ }),
39
+ };
40
+ static flags = {
41
+ level: core_1.Flags.string({
42
+ options: [...data_provider_1.DELIVERABLE_AUTHORITIES],
43
+ required: true,
44
+ description: 'How well evidenced the answer must be: self_reported (the doer says so), ' +
45
+ 'human_confirmed (someone else looked), observation_backed (the platform saw it).',
46
+ }),
47
+ reason: core_1.Flags.string({
48
+ required: true,
49
+ description: 'Why this bar. Required — it is the record.',
50
+ }),
51
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
52
+ };
53
+ async run() {
54
+ this.requireAuth();
55
+ const { args, flags } = await this.parse(TasksTrust);
56
+ let result;
57
+ try {
58
+ result = await data_provider_1.dataService.setTaskExpectationTrust(args.task, {
59
+ expectationId: args.expectation,
60
+ level: flags.level,
61
+ reason: flags.reason,
62
+ });
63
+ }
64
+ catch (err) {
65
+ this.handleApiError(err);
66
+ return;
67
+ }
68
+ if (flags.json) {
69
+ this.log(JSON.stringify(result, null, 2));
70
+ return;
71
+ }
72
+ this.log(`${args.expectation} now needs ${flags.level}: ${flags.reason}`);
73
+ }
74
+ }
75
+ exports.default = TasksTrust;
@@ -10,6 +10,7 @@ export default class TasksUpdate extends BaseCommand {
10
10
  task: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
11
  'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
12
  title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
+ expect: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
14
  description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
15
  'description-format': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
16
  priority: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -5,8 +5,9 @@ const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../base-command");
6
6
  const web_url_1 = require("../../lib/web-url");
7
7
  const prompt_1 = require("../../lib/prompt");
8
- const task_resolver_1 = require("../../lib/task-resolver");
9
8
  const tasks_1 = require("../../lib/tasks");
9
+ const task_resolver_1 = require("../../lib/task-resolver");
10
+ const tasks_2 = require("../../lib/tasks");
10
11
  const create_1 = require("./create");
11
12
  class TasksUpdate extends base_command_1.BaseCommand {
12
13
  static description = 'Update an existing task (partial patch). Status and PROJECT changes go through ' +
@@ -41,6 +42,11 @@ class TasksUpdate extends base_command_1.BaseCommand {
41
42
  description: 'Path to a JSON file (or "-" for stdin) to use as the patch body; may include taskId',
42
43
  }),
43
44
  title: core_1.Flags.string({ description: 'New title' }),
45
+ expect: core_1.Flags.string({
46
+ multiple: true,
47
+ description: tasks_1.EXPECT_FLAG_HELP +
48
+ ' Replaces the whole list; pass "clear" to drop it and inherit the space default.',
49
+ }),
44
50
  description: core_1.Flags.string({ description: 'New description' }),
45
51
  'description-format': core_1.Flags.string({
46
52
  description: 'Input format for --description or from-json description',
@@ -48,7 +54,7 @@ class TasksUpdate extends base_command_1.BaseCommand {
48
54
  }),
49
55
  priority: core_1.Flags.string({
50
56
  description: 'New priority',
51
- options: [...tasks_1.TASK_PRIORITIES],
57
+ options: [...tasks_2.TASK_PRIORITIES],
52
58
  }),
53
59
  'start-date': core_1.Flags.string({ description: 'New planned start date (ISO string)' }),
54
60
  'due-date': core_1.Flags.string({ description: 'New due date (ISO string)' }),
@@ -198,8 +204,32 @@ class TasksUpdate extends base_command_1.BaseCommand {
198
204
  details: { suggestion: failure.suggestion, context: failure.details },
199
205
  });
200
206
  }
207
+ // `--expect clear` is an explicit empty list, which the API turns into $unset —
208
+ // distinct from omitting the flag, which leaves the declaration untouched.
209
+ // Without the sentinel there is no way to say "stop requiring an output"
210
+ // short of hand-writing --from-json.
211
+ // `--expect clear` empties the list; otherwise the flags REPLACE it, because
212
+ // a partial patch of a list has no honest meaning — "add one" and "this is
213
+ // now the whole contract" are different requests and the flag can only be
214
+ // one of them.
215
+ let expectationsPatch;
216
+ if (flags.expect !== undefined && flags.expect.length > 0) {
217
+ if (flags.expect.length === 1 && flags.expect[0].trim() === 'clear') {
218
+ expectationsPatch = null;
219
+ }
220
+ else {
221
+ const parsed = (0, tasks_1.parseExpectations)(flags.expect);
222
+ if (!parsed.ok) {
223
+ this.error(parsed.error, { exit: 1 });
224
+ }
225
+ else {
226
+ expectationsPatch = parsed.value;
227
+ }
228
+ }
229
+ }
201
230
  const payload = (0, prompt_1.mergeDefined)((0, task_resolver_1.stripTaskIdentityFields)(body), {
202
231
  title: flags.title,
232
+ expectations: expectationsPatch === null ? [] : (expectationsPatch ?? undefined),
203
233
  description: flags.description,
204
234
  descriptionFormat: flags['description-format'],
205
235
  priority: flags.priority,
@@ -231,7 +261,7 @@ class TasksUpdate extends base_command_1.BaseCommand {
231
261
  labelIds: flags['label-id'],
232
262
  // Worktree isolation override. --worktree ⇒ 'ephemeral', --no-worktree ⇒
233
263
  // 'shared', omitted ⇒ unchanged. (Clear-to-inherit via --from-json.)
234
- executionIsolation: (0, tasks_1.executionIsolationFromWorktreeFlag)(flags.worktree),
264
+ executionIsolation: (0, tasks_2.executionIsolationFromWorktreeFlag)(flags.worktree),
235
265
  // A mutation option, not a field — `undefined` unless explicitly asked
236
266
  // for, so it never counts toward the "nothing to update" check below.
237
267
  repairReleasePins: flags['repair-release-pins'] ? true : undefined,
@@ -253,7 +283,7 @@ class TasksUpdate extends base_command_1.BaseCommand {
253
283
  retryable: false,
254
284
  });
255
285
  }
256
- const mutationGuardFailure = (0, tasks_1.taskUpdateMutationGuard)(payload);
286
+ const mutationGuardFailure = (0, tasks_2.taskUpdateMutationGuard)(payload);
257
287
  if (mutationGuardFailure) {
258
288
  this.failWithCliError({
259
289
  message: mutationGuardFailure.message,
@@ -0,0 +1,25 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr tasks waive <task> <expectation-id> --reason "<why>"`
4
+ *
5
+ * Drop a requirement, on the record. The expectation is KEPT and marked, never
6
+ * deleted: deleting it expresses the same decision while destroying the only
7
+ * evidence that it was ever owed, which is what someone asking "why wasn't this
8
+ * done?" needs to read.
9
+ *
10
+ * The reason is required for the same purpose — a waiver without one is
11
+ * indistinguishable from having forgotten.
12
+ */
13
+ export default class TasksWaive extends BaseCommand {
14
+ static description: string;
15
+ static examples: string[];
16
+ static args: {
17
+ task: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
18
+ expectation: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
19
+ };
20
+ static flags: {
21
+ reason: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ };
24
+ run(): Promise<void>;
25
+ }