@skrr-ai/cli 0.1.36 → 0.1.37

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 (152) hide show
  1. package/README.md +17 -4
  2. package/dist/commands/agents/actions/create.d.ts +5 -0
  3. package/dist/commands/agents/actions/create.js +26 -0
  4. package/dist/commands/agents/actions/update.d.ts +5 -0
  5. package/dist/commands/agents/actions/update.js +24 -0
  6. package/dist/commands/agents/api-actions/add.d.ts +41 -0
  7. package/dist/commands/agents/api-actions/add.js +202 -0
  8. package/dist/commands/agents/api-actions/index.d.ts +28 -0
  9. package/dist/commands/agents/api-actions/index.js +77 -0
  10. package/dist/commands/agents/api-actions/remove.d.ts +14 -0
  11. package/dist/commands/agents/api-actions/remove.js +36 -0
  12. package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
  13. package/dist/commands/agents/avatar/default/apply.js +56 -0
  14. package/dist/commands/agents/avatar/default/index.d.ts +18 -0
  15. package/dist/commands/agents/avatar/default/index.js +44 -0
  16. package/dist/commands/agents/avatar/default/set.d.ts +23 -0
  17. package/dist/commands/agents/avatar/default/set.js +95 -0
  18. package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
  19. package/dist/commands/agents/avatar/library/delete.js +47 -0
  20. package/dist/commands/agents/avatar/library/index.d.ts +16 -0
  21. package/dist/commands/agents/avatar/library/index.js +56 -0
  22. package/dist/commands/agents/avatar/presets.d.ts +19 -0
  23. package/dist/commands/agents/avatar/presets.js +56 -0
  24. package/dist/commands/agents/categories/create.d.ts +14 -0
  25. package/dist/commands/agents/categories/create.js +46 -0
  26. package/dist/commands/agents/categories/delete.d.ts +13 -0
  27. package/dist/commands/agents/categories/delete.js +33 -0
  28. package/dist/commands/agents/categories/index.d.ts +20 -0
  29. package/dist/commands/agents/categories/index.js +82 -0
  30. package/dist/commands/agents/categories/update.d.ts +22 -0
  31. package/dist/commands/agents/categories/update.js +59 -0
  32. package/dist/commands/agents/create.d.ts +10 -0
  33. package/dist/commands/agents/create.js +57 -3
  34. package/dist/commands/agents/ensure-default.d.ts +27 -0
  35. package/dist/commands/agents/ensure-default.js +65 -0
  36. package/dist/commands/agents/mute.d.ts +16 -0
  37. package/dist/commands/agents/mute.js +38 -0
  38. package/dist/commands/agents/pin.d.ts +16 -0
  39. package/dist/commands/agents/pin.js +38 -0
  40. package/dist/commands/agents/tools/auth.d.ts +19 -0
  41. package/dist/commands/agents/tools/auth.js +41 -0
  42. package/dist/commands/agents/tools/calls.d.ts +18 -0
  43. package/dist/commands/agents/tools/calls.js +54 -0
  44. package/dist/commands/agents/tools/index.d.ts +20 -0
  45. package/dist/commands/agents/tools/index.js +77 -0
  46. package/dist/commands/agents/unmute.d.ts +16 -0
  47. package/dist/commands/agents/unmute.js +38 -0
  48. package/dist/commands/agents/unpin.d.ts +16 -0
  49. package/dist/commands/agents/unpin.js +38 -0
  50. package/dist/commands/agents/update.d.ts +12 -0
  51. package/dist/commands/agents/update.js +64 -3
  52. package/dist/commands/followups/act.d.ts +22 -0
  53. package/dist/commands/followups/act.js +102 -0
  54. package/dist/commands/followups/cancel.d.ts +17 -0
  55. package/dist/commands/followups/cancel.js +40 -0
  56. package/dist/commands/followups/checkin.d.ts +27 -0
  57. package/dist/commands/followups/checkin.js +107 -0
  58. package/dist/commands/followups/list.d.ts +24 -0
  59. package/dist/commands/followups/list.js +90 -0
  60. package/dist/commands/followups/remind.d.ts +26 -0
  61. package/dist/commands/followups/remind.js +106 -0
  62. package/dist/commands/followups/reschedule.d.ts +15 -0
  63. package/dist/commands/followups/reschedule.js +48 -0
  64. package/dist/commands/followups/resolve.d.ts +23 -0
  65. package/dist/commands/followups/resolve.js +54 -0
  66. package/dist/commands/followups/show.d.ts +12 -0
  67. package/dist/commands/followups/show.js +45 -0
  68. package/dist/commands/followups/watch.d.ts +51 -0
  69. package/dist/commands/followups/watch.js +207 -0
  70. package/dist/commands/goals/labels/add.js +19 -2
  71. package/dist/commands/goals/labels/remove.js +22 -2
  72. package/dist/commands/labels/list.d.ts +24 -1
  73. package/dist/commands/labels/list.js +62 -19
  74. package/dist/commands/memory/governance/index.d.ts +21 -0
  75. package/dist/commands/memory/governance/index.js +64 -0
  76. package/dist/commands/memory/governance/set.d.ts +24 -0
  77. package/dist/commands/memory/governance/set.js +95 -0
  78. package/dist/commands/memory/provenance.d.ts +18 -0
  79. package/dist/commands/memory/provenance.js +66 -0
  80. package/dist/commands/spaces/create.d.ts +3 -0
  81. package/dist/commands/spaces/create.js +32 -2
  82. package/dist/commands/spaces/labels/add.js +19 -2
  83. package/dist/commands/spaces/labels/remove.js +22 -2
  84. package/dist/commands/spaces/show.js +2 -0
  85. package/dist/commands/spaces/update.d.ts +5 -0
  86. package/dist/commands/spaces/update.js +41 -4
  87. package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
  88. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +45 -0
  89. package/dist/commands/tasks/complete.d.ts +1 -0
  90. package/dist/commands/tasks/complete.js +8 -1
  91. package/dist/commands/tasks/create.d.ts +3 -0
  92. package/dist/commands/tasks/create.js +34 -2
  93. package/dist/commands/tasks/expectations/assess.d.ts +11 -0
  94. package/dist/commands/tasks/expectations/assess.js +85 -14
  95. package/dist/commands/tasks/expectations.js +19 -2
  96. package/dist/commands/tasks/labels/attach.js +20 -3
  97. package/dist/commands/tasks/labels/detach.js +21 -3
  98. package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
  99. package/dist/commands/tasks/lifecycle/attach.js +47 -0
  100. package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
  101. package/dist/commands/tasks/lifecycle/definitions.js +40 -0
  102. package/dist/commands/tasks/lifecycle/detach.d.ts +12 -0
  103. package/dist/commands/tasks/lifecycle/detach.js +32 -0
  104. package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
  105. package/dist/commands/tasks/lifecycle/history.js +38 -0
  106. package/dist/commands/tasks/lifecycle/migrate.d.ts +12 -0
  107. package/dist/commands/tasks/lifecycle/migrate.js +29 -0
  108. package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
  109. package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
  110. package/dist/commands/tasks/lifecycle/reopen.d.ts +13 -0
  111. package/dist/commands/tasks/lifecycle/reopen.js +34 -0
  112. package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
  113. package/dist/commands/tasks/lifecycle/show.js +27 -0
  114. package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
  115. package/dist/commands/tasks/lifecycle/start.js +30 -0
  116. package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
  117. package/dist/commands/tasks/lifecycle/transition.js +78 -0
  118. package/dist/commands/tasks/move.d.ts +1 -0
  119. package/dist/commands/tasks/move.js +31 -0
  120. package/dist/commands/tasks/result/submit.js +11 -1
  121. package/dist/commands/tasks/review-queue.d.ts +29 -0
  122. package/dist/commands/tasks/review-queue.js +165 -0
  123. package/dist/commands/tasks/show.js +42 -0
  124. package/dist/commands/tasks/update.d.ts +1 -0
  125. package/dist/commands/tasks/update.js +47 -0
  126. package/dist/lib/agent-actions.d.ts +36 -10
  127. package/dist/lib/agent-actions.js +63 -9
  128. package/dist/lib/agent-config.d.ts +11 -0
  129. package/dist/lib/agent-config.js +85 -3
  130. package/dist/lib/agent-pin-mute.d.ts +24 -0
  131. package/dist/lib/agent-pin-mute.js +17 -0
  132. package/dist/lib/agent-visual-refs.d.ts +6 -0
  133. package/dist/lib/agent-visual-refs.js +142 -0
  134. package/dist/lib/first-party-harness-agent.js +7 -0
  135. package/dist/lib/followups.d.ts +107 -0
  136. package/dist/lib/followups.js +102 -0
  137. package/dist/lib/label-ref.d.ts +95 -0
  138. package/dist/lib/label-ref.js +163 -0
  139. package/dist/lib/label-scope.d.ts +2 -2
  140. package/dist/lib/label-scope.js +3 -3
  141. package/dist/lib/task-closure.d.ts +32 -0
  142. package/dist/lib/task-closure.js +106 -0
  143. package/dist/lib/task-lifecycle-output.d.ts +14 -0
  144. package/dist/lib/task-lifecycle-output.js +101 -0
  145. package/dist/lib/tasks.d.ts +3 -0
  146. package/dist/lib/tasks.js +31 -0
  147. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
  148. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
  149. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  150. package/dist/node_modules/@skrr-ai/data-provider/index.js +5079 -4546
  151. package/oclif.manifest.json +20216 -16002
  152. package/package.json +16 -4
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
+ const label_ref_1 = require("../../../lib/label-ref");
6
7
  const web_url_1 = require("../../../lib/web-url");
7
8
  class SpacesLabelsRemove extends base_command_1.BaseCommand {
8
9
  static description = 'Detach a label from a space';
@@ -15,16 +16,35 @@ class SpacesLabelsRemove extends base_command_1.BaseCommand {
15
16
  };
16
17
  static flags = {
17
18
  json: core_1.Flags.boolean({ description: 'Output the updated space as JSON' }),
18
- label: core_1.Flags.string({ description: 'Label ID to detach', required: true }),
19
+ label: core_1.Flags.string({
20
+ description: 'Label — id, or a name from `skrr labels list --applicable-to space`. An unknown name is refused, never created.',
21
+ required: true,
22
+ }),
19
23
  };
20
24
  async run() {
21
25
  this.requireAuth();
22
26
  const { args, flags } = await this.parse(SpacesLabelsRemove);
23
27
  // Detach is intentionally permissive server-side: you can remove a label
24
28
  // you can no longer read, so a revoked label never gets stuck on a space.
29
+ // A name is resolved against the DECLARED vocabulary; an unknown one is
30
+ // refused with the near misses named, never created. See lib/label-ref.
31
+ let labelId = flags.label;
32
+ try {
33
+ [labelId] = await (0, label_ref_1.resolveLabelRefs)([flags.label], {
34
+ applicableTo: 'space',
35
+ ...(process.env.OVERSKY_WORKSPACE_ID
36
+ ? { workspaceId: process.env.OVERSKY_WORKSPACE_ID }
37
+ : {}),
38
+ });
39
+ }
40
+ catch (err) {
41
+ if (err instanceof label_ref_1.LabelRefError)
42
+ this.error(err.message, { exit: 1 });
43
+ this.handleApiError(err);
44
+ }
25
45
  let result;
26
46
  try {
27
- result = await data_provider_1.dataService.removeLabelFromSpace({ spaceId: args.id, labelId: flags.label });
47
+ result = await data_provider_1.dataService.removeLabelFromSpace({ spaceId: args.id, labelId });
28
48
  }
29
49
  catch (err) {
30
50
  this.handleApiError(err);
@@ -52,6 +52,8 @@ class SpacesShow extends base_command_1.BaseCommand {
52
52
  this.log(`URL: ${url}`);
53
53
  this.log(`Status: ${s.status ?? '-'}`);
54
54
  this.log(`Color: ${s.color ?? '-'}`);
55
+ this.log(`Icon: ${s.icon ?? '-'}`);
56
+ this.log(`Icon Color: ${s.iconColor ?? '-'}`);
55
57
  this.log(`Leader: ${s.leadAgentId ?? '-'}`);
56
58
  this.log(`Target Date: ${s.targetDate ?? '-'}`);
57
59
  this.log(`Goals: ${Array.isArray(s.goalIds) ? s.goalIds.length : 0}`);
@@ -12,6 +12,8 @@ export default class SpacesUpdate extends BaseCommand {
12
12
  description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
13
13
  status: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
14
  color: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ icon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ 'icon-color': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
17
  'lead-agent': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
18
  'target-date': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
19
  goal: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
@@ -25,6 +27,9 @@ export default class SpacesUpdate extends BaseCommand {
25
27
  'integration-branch': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
26
28
  'auto-merge-tier': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
27
29
  'worktree-isolation': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
30
+ 'auto-start-on-backlog-exit': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
31
+ 'triage-external-intake': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
32
+ 'default-task-template': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
28
33
  };
29
34
  run(): Promise<void>;
30
35
  }
@@ -6,11 +6,19 @@ const tasks_1 = require("../../lib/tasks");
6
6
  const base_command_1 = require("../../base-command");
7
7
  const web_url_1 = require("../../lib/web-url");
8
8
  const prompt_1 = require("../../lib/prompt");
9
+ /**
10
+ * Nullable PATCH fields take `none`/`null` as the clear sentinel — the same
11
+ * spelling `goals update` uses for --target-date/--project. `undefined` means
12
+ * the flag was not passed and mergeDefined leaves the field untouched.
13
+ */
14
+ const clearable = (value) => value === undefined ? undefined : ['none', 'null'].includes(value.toLowerCase()) ? null : value;
9
15
  class SpacesUpdate extends base_command_1.BaseCommand {
10
16
  static description = 'Update an existing space (partial patch)';
11
17
  static examples = [
12
18
  '<%= config.bin %> spaces update <space-id> --title "New title"',
13
19
  '<%= config.bin %> spaces update <space-id> --status in_progress --color "#4f46e5"',
20
+ '<%= config.bin %> spaces update <space-id> --icon Rocket --icon-color "#2DD4BF"',
21
+ '<%= config.bin %> spaces update <space-id> --icon none',
14
22
  '<%= config.bin %> spaces update <space-id> --lead-agent <agent-id>',
15
23
  '<%= config.bin %> spaces update <space-id> --no-inherit-access',
16
24
  '<%= config.bin %> spaces update <space-id> --from-json patch.json',
@@ -28,8 +36,18 @@ class SpacesUpdate extends base_command_1.BaseCommand {
28
36
  description: core_1.Flags.string({ description: 'New description' }),
29
37
  status: core_1.Flags.string({ description: 'New status', options: [...data_provider_1.SPACE_STATUSES] }),
30
38
  color: core_1.Flags.string({ description: 'New color (hex)' }),
31
- 'lead-agent': core_1.Flags.string({ description: 'New Space Leader agent ID' }),
32
- 'target-date': core_1.Flags.string({ description: 'New target date (ISO string)' }),
39
+ icon: core_1.Flags.string({
40
+ description: 'New space icon — a curated icon name or an emoji. Pass "none" to restore the default folder.',
41
+ }),
42
+ 'icon-color': core_1.Flags.string({
43
+ description: 'New color applied to the space icon (hex). Pass "none" to restore the neutral color.',
44
+ }),
45
+ 'lead-agent': core_1.Flags.string({
46
+ description: 'New Space Leader agent ID. Pass "none" to clear the Leader.',
47
+ }),
48
+ 'target-date': core_1.Flags.string({
49
+ description: 'New target date (ISO string). Pass "none" to clear it.',
50
+ }),
33
51
  goal: core_1.Flags.string({
34
52
  description: 'Link a goal to this space by ID (repeatable; additive). Routed through the ' +
35
53
  'atomic link endpoint — re-linking an already-linked goal is a no-op.',
@@ -103,6 +121,20 @@ class SpacesUpdate extends base_command_1.BaseCommand {
103
121
  'tree/branch. A per-task --worktree override wins. Merged into deliveryPolicy without ' +
104
122
  'clobbering its other fields.',
105
123
  }),
124
+ 'auto-start-on-backlog-exit': core_1.Flags.boolean({
125
+ allowNo: true,
126
+ description: 'Emit a nudge event when a task is dragged out of backlog, so the client can offer ' +
127
+ 'a "Run now" toast. No silent execution.',
128
+ }),
129
+ 'triage-external-intake': core_1.Flags.boolean({
130
+ allowNo: true,
131
+ description: 'Route externally sourced tasks (bots/channels) through the triage workflow state ' +
132
+ 'instead of backlog. Enabling materializes the triage state server-side.',
133
+ }),
134
+ 'default-task-template': core_1.Flags.string({
135
+ description: 'Default task template for new tasks in this space — a template id, reference, or ' +
136
+ 'exact title (the server resolves it to the template). Pass "none" to clear.',
137
+ }),
106
138
  };
107
139
  async run() {
108
140
  this.requireAuth();
@@ -119,9 +151,14 @@ class SpacesUpdate extends base_command_1.BaseCommand {
119
151
  description: flags.description,
120
152
  status: flags.status,
121
153
  color: flags.color,
122
- leadAgentId: flags['lead-agent'],
123
- targetDate: flags['target-date'],
154
+ icon: clearable(flags.icon),
155
+ iconColor: clearable(flags['icon-color']),
156
+ leadAgentId: clearable(flags['lead-agent']),
157
+ targetDate: clearable(flags['target-date']),
124
158
  inheritAccess: flags['inherit-access'],
159
+ autoStartOnBacklogExit: flags['auto-start-on-backlog-exit'],
160
+ triageExternalIntake: flags['triage-external-intake'],
161
+ defaultTaskTemplateId: clearable(flags['default-task-template']),
125
162
  estimateScale: flags['estimate-scale'],
126
163
  estimateScaleMigration: flags['estimate-migration'],
127
164
  defaultEstimate: flags['default-estimate'],
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ export default class SpacesWorkflowsLifecycleDiagnostics extends BaseCommand {
3
+ static description: string;
4
+ static args: {
5
+ spaceId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const data_provider_1 = require("@skrr-ai/data-provider");
5
+ const base_command_1 = require("../../../base-command");
6
+ class SpacesWorkflowsLifecycleDiagnostics extends base_command_1.BaseCommand {
7
+ static description = 'Bounded lifecycle operational counters for a Space — pending effect age, repairs, transition conflicts, orphan stages';
8
+ static args = {
9
+ spaceId: core_1.Args.string({ required: true, ignoreStdin: true, description: 'Owning Space ID' }),
10
+ };
11
+ static flags = { json: core_1.Flags.boolean({ description: 'Output JSON' }) };
12
+ async run() {
13
+ this.requireAuth();
14
+ const { args, flags } = await this.parse(SpacesWorkflowsLifecycleDiagnostics);
15
+ let response;
16
+ try {
17
+ response = await data_provider_1.dataService.getSpaceLifecycleDiagnostics(args.spaceId);
18
+ }
19
+ catch (error) {
20
+ this.handleApiError(error);
21
+ }
22
+ if (flags.json)
23
+ return this.log(JSON.stringify(response, null, 2));
24
+ this.log(`Lifecycle diagnostics for space ${response.spaceId}:`);
25
+ this.log(` bindings: ${response.bindings.bound} bound, ${response.bindings.active} active` +
26
+ ` (sampled ${response.sampledRuns} runs${response.truncated ? ', truncated' : ''})`);
27
+ const runStates = Object.entries(response.runs)
28
+ .map(([status, count]) => `${status}: ${count}`)
29
+ .join(', ');
30
+ this.log(` runs: ${runStates || 'none'}`);
31
+ this.log(` stages: ${response.stages.waiting} waiting` +
32
+ ` (oldest ${Math.round(response.stages.oldestWaitingMs / 1000)}s)` +
33
+ `, ${response.stages.completed} completed` +
34
+ ` (median ${Math.round(response.stages.durationMs.median / 1000)}s` +
35
+ `, max ${Math.round(response.stages.durationMs.max / 1000)}s)`);
36
+ this.log(` effects: ${response.effects.pending} pending` +
37
+ ` (oldest ${Math.round(response.effects.oldestPendingMs / 1000)}s)` +
38
+ `, ${response.effects.repairs} repaired`);
39
+ this.log(` transitions: ${response.transitions.applied} applied` +
40
+ `, ${response.transitions.gated} gated` +
41
+ `, ${response.transitions.superseded} superseded`);
42
+ this.log(` orphan stages: ${response.orphans}`);
43
+ }
44
+ }
45
+ exports.default = SpacesWorkflowsLifecycleDiagnostics;
@@ -31,6 +31,7 @@ export default class TasksComplete extends BaseCommand {
31
31
  'run-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
32
32
  'spec-version': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
33
33
  'idempotency-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
34
+ force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
34
35
  'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
35
36
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
36
37
  };
@@ -60,7 +60,9 @@ function describePendingReview({ statusType, taskId, resultId, bin, advisories,
60
60
  }
61
61
  return ('The Result was submitted, but the Task is not done yet. It is waiting on an independent ' +
62
62
  `accepted Review — someone OTHER than the submitter runs: ${bin} tasks review ${taskId} ` +
63
- `--result-id ${resultId || '<result-id>'} --decision accepted`);
63
+ `--result-id ${resultId || '<result-id>'} --decision accepted. ` +
64
+ `(The Task owner, or a non-owner with ${bin} tasks move ${taskId} --status done --force, ` +
65
+ 'may close without one — an override is recorded on the resolution.)');
64
66
  }
65
67
  class TasksComplete extends base_command_1.BaseCommand {
66
68
  static description = 'Submit one versioned Result and advance the Task workflow';
@@ -101,6 +103,9 @@ class TasksComplete extends base_command_1.BaseCommand {
101
103
  description: 'Task specification version this Result answers',
102
104
  }),
103
105
  'idempotency-key': core_1.Flags.string({ description: 'Stable retry key for this exact closeout' }),
106
+ force: core_1.Flags.boolean({
107
+ description: "Close past an owner-declared required Review as a non-owner; the override is recorded on the task's resolution",
108
+ }),
104
109
  'from-json': core_1.Flags.string({
105
110
  description: 'JSON file containing the same canonical Result fields; "-" for stdin',
106
111
  }),
@@ -188,6 +193,7 @@ class TasksComplete extends base_command_1.BaseCommand {
188
193
  expectedRunId: flags['run-id'],
189
194
  expectedSpecVersion: flags['spec-version'],
190
195
  idempotencyKey: flags['idempotency-key'],
196
+ force: flags.force === true ? true : undefined,
191
197
  });
192
198
  let status;
193
199
  let summary;
@@ -224,6 +230,7 @@ class TasksComplete extends base_command_1.BaseCommand {
224
230
  sourceRunIds: stringArray(input.sourceRunIds),
225
231
  expectedRunId: optionalString(input.expectedRunId),
226
232
  expectedSpecVersion: typeof input.expectedSpecVersion === 'number' ? input.expectedSpecVersion : undefined,
233
+ ...(input.force === true ? { force: true } : {}),
227
234
  };
228
235
  const idempotencyKey = optionalString(input.idempotencyKey) ||
229
236
  (0, outbox_1.idempotencyKeyFor)('task-complete', identity.id, JSON.stringify(payload));
@@ -66,6 +66,9 @@ export default class TasksCreate extends BaseCommand {
66
66
  tag: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
67
67
  'label-id': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
68
68
  worktree: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
69
+ 'lifecycle-definition': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
70
+ 'lifecycle-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
71
+ 'lifecycle-pack': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
69
72
  };
70
73
  run(): Promise<void>;
71
74
  private createTaskOrRecover;
@@ -6,6 +6,7 @@ exports.taskMatchesCreateIdentity = taskMatchesCreateIdentity;
6
6
  const core_1 = require("@oclif/core");
7
7
  const data_provider_1 = require("@skrr-ai/data-provider");
8
8
  const base_command_1 = require("../../base-command");
9
+ const label_ref_1 = require("../../lib/label-ref");
9
10
  const prompt_1 = require("../../lib/prompt");
10
11
  const tasks_1 = require("../../lib/tasks");
11
12
  const task_instruction_offer_1 = require("../../lib/task-instruction-offer");
@@ -220,8 +221,8 @@ class TasksCreate extends base_command_1.BaseCommand {
220
221
  }),
221
222
  tag: core_1.Flags.string({ description: 'Tag (repeatable)', multiple: true }),
222
223
  'label-id': core_1.Flags.string({
223
- description: 'Attach a task label by id (repeatable). Manage labels with `skrr tasks labels`. ' +
224
- 'Every id must be an attachable label or the server rejects the create.',
224
+ description: 'Attach a task label (repeatable) — id, or a name from `skrr labels list --applicable-to task`. ' +
225
+ 'An unknown name is refused, never created. Manage labels with `skrr labels`.',
225
226
  multiple: true,
226
227
  }),
227
228
  worktree: core_1.Flags.boolean({
@@ -230,6 +231,18 @@ class TasksCreate extends base_command_1.BaseCommand {
230
231
  'or force the shared daemon tree (--no-worktree). Omit to inherit the space ' +
231
232
  'policy / global default (shared).',
232
233
  }),
234
+ 'lifecycle-definition': core_1.Flags.string({
235
+ description: 'Bind the created task to a task_lifecycle Workflow definition in its space. ' +
236
+ 'Validated before the write; attach failure rolls the task back.',
237
+ }),
238
+ 'lifecycle-version': core_1.Flags.string({
239
+ description: 'Exact published version to bind (requires --lifecycle-definition). ' +
240
+ 'Omit to pin the definition’s current published version at create time.',
241
+ }),
242
+ 'lifecycle-pack': core_1.Flags.string({
243
+ description: 'Bind the created task to a built-in lifecycle pack (e.g. finding, doc-to-task). ' +
244
+ 'Alternative to --lifecycle-definition.',
245
+ }),
233
246
  };
234
247
  async run() {
235
248
  this.requireAuth();
@@ -260,8 +273,27 @@ class TasksCreate extends base_command_1.BaseCommand {
260
273
  retryable: false,
261
274
  });
262
275
  }
276
+ // Resolve `--label-id` names before the create so a typo fails here, with
277
+ // the near misses named, rather than reaching the server as an id it will
278
+ // reject with no idea what was meant. Ids pass through untouched.
279
+ let resolvedLabelIds;
280
+ try {
281
+ const ids = await (0, label_ref_1.resolveLabelRefs)(flags['label-id'], {
282
+ applicableTo: 'task',
283
+ ...(process.env.OVERSKY_WORKSPACE_ID
284
+ ? { workspaceId: process.env.OVERSKY_WORKSPACE_ID }
285
+ : {}),
286
+ });
287
+ resolvedLabelIds = ids.length > 0 ? ids : undefined;
288
+ }
289
+ catch (err) {
290
+ if (err instanceof label_ref_1.LabelRefError)
291
+ this.error(err.message, { exit: 1 });
292
+ this.handleApiError(err);
293
+ }
263
294
  const payload = (0, tasks_1.buildTaskCreatePayload)(body, {
264
295
  ...flags,
296
+ 'label-id': resolvedLabelIds,
265
297
  expectations: parsedExpectations.ok && parsedExpectations.value.length > 0
266
298
  ? parsedExpectations.value
267
299
  : undefined,
@@ -15,7 +15,18 @@ export default class TasksExpectationsAssess extends BaseCommand {
15
15
  evidence: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
16
  'spec-version': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
17
  'idempotency-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ all: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
19
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
19
20
  };
21
+ /**
22
+ * Which Expectations `--all` covers.
23
+ *
24
+ * ONLY the ones nothing has settled. An already-assessed Expectation carries
25
+ * somebody's judgement, and a bulk pass that overwrote it would silently
26
+ * replace a considered `unmet` with a blanket `met` — which is the one thing a
27
+ * batch verb must never do. Overriding an existing assessment stays a
28
+ * deliberate, single, named act.
29
+ */
30
+ private awaitingIds;
20
31
  run(): Promise<void>;
21
32
  }
@@ -41,21 +41,50 @@ class TasksExpectationsAssess extends base_command_1.BaseCommand {
41
41
  }),
42
42
  'spec-version': core_1.Flags.integer({ description: 'Task specification version being assessed' }),
43
43
  'idempotency-key': core_1.Flags.string({ description: 'Stable retry key' }),
44
+ all: core_1.Flags.boolean({
45
+ description: 'Assess every Expectation still awaiting one on this Task, with the same decision ' +
46
+ 'and reason. Already-settled Expectations are left alone.',
47
+ }),
44
48
  json: core_1.Flags.boolean({ description: 'Output JSON' }),
45
49
  };
50
+ /**
51
+ * Which Expectations `--all` covers.
52
+ *
53
+ * ONLY the ones nothing has settled. An already-assessed Expectation carries
54
+ * somebody's judgement, and a bulk pass that overwrote it would silently
55
+ * replace a considered `unmet` with a blanket `met` — which is the one thing a
56
+ * batch verb must never do. Overriding an existing assessment stays a
57
+ * deliberate, single, named act.
58
+ */
59
+ async awaitingIds(taskId) {
60
+ const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskId);
61
+ return acceptance.expectations
62
+ .filter((expectation) => expectation.gating && !expectation.met && !expectation.assessmentId)
63
+ .map((expectation) => expectation.id);
64
+ }
46
65
  async run() {
47
66
  this.requireAuth();
48
67
  const { args, flags } = await this.parse(TasksExpectationsAssess);
49
68
  // `assess <task> <expectation>` gives both; `assess <expectation>` inside a
50
69
  // task runtime gives one, and it is the Expectation.
51
70
  const expectationId = args.expectation ?? args.task;
52
- if (!expectationId) {
53
- this.error('An Expectation id is required: `tasks expectations assess <task> <expectation>`', {
71
+ if (!expectationId && !flags.all) {
72
+ this.error('An Expectation id is required: `tasks expectations assess <task> <expectation>`, ' +
73
+ 'or pass --all to settle every Expectation still awaiting one.', {
54
74
  exit: 1,
55
75
  });
56
76
  }
77
+ /*
78
+ * Which positional is the TASK.
79
+ *
80
+ * `assess <task> <expectation>` gives both, so the first is the Task.
81
+ * `assess <expectation>` inside a task runtime gives one, and it is the
82
+ * Expectation — there is no Task positional to read. With `--all` there is
83
+ * no Expectation to name at all, so a lone positional is the Task again.
84
+ */
85
+ const taskPositional = flags.all || args.expectation ? args.task : undefined;
57
86
  const task = (0, task_resolver_1.resolveTaskIdentity)({
58
- positionalId: args.expectation ? args.task : undefined,
87
+ positionalId: taskPositional,
59
88
  flagTask: flags.task,
60
89
  });
61
90
  const evidenceRefs = (flags.evidence || []).map((raw) => {
@@ -75,22 +104,64 @@ class TasksExpectationsAssess extends base_command_1.BaseCommand {
75
104
  evidenceRefs,
76
105
  expectedSpecVersion: flags['spec-version'],
77
106
  };
78
- let result;
79
- try {
107
+ const reuseCallerKey = Boolean(flags['idempotency-key']) && !flags.all;
108
+ const submit = async (id) => {
80
109
  const data = {
81
110
  ...payload,
82
- expectationId,
83
- idempotencyKey: flags['idempotency-key'] ||
84
- (0, outbox_1.idempotencyKeyFor)('task-expectation-assessment', task.id, JSON.stringify({ expectationId, ...payload })),
111
+ expectationId: id,
112
+ // A per-expectation key under `--all`: one caller-supplied key reused
113
+ // across the set would make the second write a duplicate of the first,
114
+ // settling exactly one Expectation while reporting several.
115
+ idempotencyKey: reuseCallerKey
116
+ ? flags['idempotency-key']
117
+ : (0, outbox_1.idempotencyKeyFor)('task-expectation-assessment', task.id, JSON.stringify({ expectationId: id, ...payload })),
85
118
  };
86
119
  const sessionPath = await (0, session_task_endpoints_1.sessionScopedTaskPath)('assessment');
87
- result = sessionPath
120
+ return sessionPath
88
121
  ? await (0, api_fetch_1.apiFetch)(sessionPath, { method: 'POST', body: data })
89
- : await data_provider_1.dataService.assessTaskExpectation({
90
- taskId: task.id,
91
- expectationId,
92
- data,
93
- });
122
+ : await data_provider_1.dataService.assessTaskExpectation({ taskId: task.id, expectationId: id, data });
123
+ };
124
+ if (flags.all) {
125
+ let ids;
126
+ try {
127
+ ids = await this.awaitingIds(task.id);
128
+ }
129
+ catch (error) {
130
+ this.handleApiError(error);
131
+ return;
132
+ }
133
+ if (ids.length === 0) {
134
+ this.log('Nothing is awaiting assessment on this Task.');
135
+ return;
136
+ }
137
+ // Each write is reported on its own. A partial failure must leave the
138
+ // caller knowing exactly which Expectations were settled, because the
139
+ // remedy is to re-run for the rest — a single rolled-up "failed" would
140
+ // make that impossible to work out.
141
+ const settled = [];
142
+ const failed = [];
143
+ for (const id of ids) {
144
+ try {
145
+ await submit(id);
146
+ settled.push(id);
147
+ }
148
+ catch (error) {
149
+ failed.push({ id, message: error?.message || 'unknown error' });
150
+ }
151
+ }
152
+ if (flags.json) {
153
+ return this.log(JSON.stringify({ decision: flags.decision, settled, failed }, null, 2));
154
+ }
155
+ this.log(`Recorded ${settled.length} Expectation(s) as ${flags.decision}: ${settled.join(', ')}`);
156
+ for (const failure of failed)
157
+ this.log(` FAILED ${failure.id}: ${failure.message}`);
158
+ if (failed.length > 0)
159
+ this.exit(1);
160
+ return;
161
+ }
162
+ let result;
163
+ try {
164
+ result = await submit(expectationId);
94
165
  }
95
166
  catch (error) {
96
167
  this.handleApiError(error);
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const data_provider_2 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../base-command");
7
+ const task_closure_1 = require("../../lib/task-closure");
7
8
  /**
8
9
  * `skrr tasks expectations <task>` — what this task owes, and how far each got.
9
10
  *
@@ -62,8 +63,24 @@ function evidenceGap(expectation) {
62
63
  return '';
63
64
  return ` (has ${expectation.evidenceLevel}, needs ${expectation.requiredEvidence})`;
64
65
  }
66
+ /**
67
+ * `done (agent)` rather than `done`.
68
+ *
69
+ * An agent may assess any Expectation, so the control that keeps this honest is
70
+ * not permission — it is that a reader can always see whose judgement closed a
71
+ * row and decide how much to trust it. Printed only on rows an assessment
72
+ * actually settled; a state derived from the deliverable ledger has no assessor
73
+ * and must not be given a fake one.
74
+ */
75
+ function assessorSuffix(expectation) {
76
+ if (!expectation.assessedByKind)
77
+ return '';
78
+ if (!['met', 'waived'].includes(expectation.state))
79
+ return '';
80
+ return ` (${(0, task_closure_1.describeAssessor)(expectation.assessedByKind)})`;
81
+ }
65
82
  function line(expectation) {
66
- const label = STATE_LABEL[expectation.state] || expectation.state;
83
+ const label = (STATE_LABEL[expectation.state] || expectation.state) + assessorSuffix(expectation);
67
84
  const from = expectation.source === 'space' ? ' [space default]' : '';
68
85
  /*
69
86
  * `sentence` before `text`.
@@ -75,7 +92,7 @@ function line(expectation) {
75
92
  * thing is owed. The fallback is for a row that predates the resolved field.
76
93
  */
77
94
  const sentence = expectation.sentence || expectation.text;
78
- return ` ${expectation.id.padEnd(18)} ${label.padEnd(18)} ${sentence}${evidenceGap(expectation)}${from}`;
95
+ return ` ${expectation.id.padEnd(18)} ${label.padEnd(22)} ${sentence}${evidenceGap(expectation)}${from}`;
79
96
  }
80
97
  class TasksExpectations extends base_command_1.BaseCommand {
81
98
  static description = 'Show what must be true before the Task can close and the evidence-backed assessment state';
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
+ const label_ref_1 = require("../../../lib/label-ref");
6
7
  /**
7
8
  * Incremental label attach. `dataService.updateTask` only accepts a whole-list
8
9
  * `labelIds: string[]`, so we fetch the current task, append the new label
@@ -27,7 +28,7 @@ class TasksLabelsAttach extends base_command_1.BaseCommand {
27
28
  static flags = {
28
29
  json: core_1.Flags.boolean({ description: 'Output the updated task as JSON' }),
29
30
  'label-id': core_1.Flags.string({
30
- description: 'Label id to attach (repeatable). Create labels with `skrr tasks labels create`.',
31
+ description: 'Label to attach — id, or a name from `skrr labels list --applicable-to task`. An unknown name is refused, never created (repeatable).',
31
32
  multiple: true,
32
33
  required: true,
33
34
  }),
@@ -35,10 +36,26 @@ class TasksLabelsAttach extends base_command_1.BaseCommand {
35
36
  async run() {
36
37
  this.requireAuth();
37
38
  const { args, flags } = await this.parse(TasksLabelsAttach);
38
- const incoming = (flags['label-id'] ?? []).map((id) => id.trim()).filter((id) => id.length > 0);
39
- if (incoming.length === 0) {
39
+ const refs = (flags['label-id'] ?? []).map((id) => id.trim()).filter((id) => id.length > 0);
40
+ if (refs.length === 0) {
40
41
  this.error('At least one --label-id is required.', { exit: 1 });
41
42
  }
43
+ // A name is resolved against the DECLARED vocabulary; an unknown one is
44
+ // refused with the near misses named, never created. See lib/label-ref.
45
+ let incoming = [];
46
+ try {
47
+ incoming = await (0, label_ref_1.resolveLabelRefs)(refs, {
48
+ applicableTo: 'task',
49
+ ...(process.env.OVERSKY_WORKSPACE_ID
50
+ ? { workspaceId: process.env.OVERSKY_WORKSPACE_ID }
51
+ : {}),
52
+ });
53
+ }
54
+ catch (err) {
55
+ if (err instanceof label_ref_1.LabelRefError)
56
+ this.error(err.message, { exit: 1 });
57
+ this.handleApiError(err);
58
+ }
42
59
  let current;
43
60
  try {
44
61
  current = await data_provider_1.dataService.getTask(args.id, { enrich: false });
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
+ const label_ref_1 = require("../../../lib/label-ref");
6
7
  /**
7
8
  * Incremental label detach. Mirror of `labels attach` — fetch, filter, write
8
9
  * back the whole `labelIds` list. Matches label ids exactly (they are opaque
@@ -20,7 +21,7 @@ class TasksLabelsDetach extends base_command_1.BaseCommand {
20
21
  static flags = {
21
22
  json: core_1.Flags.boolean({ description: 'Output the updated task as JSON' }),
22
23
  'label-id': core_1.Flags.string({
23
- description: 'Label id to detach (repeatable)',
24
+ description: 'Label to detach — id, or a name from `skrr labels list --applicable-to task` (repeatable)',
24
25
  multiple: true,
25
26
  required: true,
26
27
  }),
@@ -28,10 +29,27 @@ class TasksLabelsDetach extends base_command_1.BaseCommand {
28
29
  async run() {
29
30
  this.requireAuth();
30
31
  const { args, flags } = await this.parse(TasksLabelsDetach);
31
- const targets = new Set((flags['label-id'] ?? []).map((id) => id.trim()).filter((id) => id.length > 0));
32
- if (targets.size === 0) {
32
+ const refs = (flags['label-id'] ?? []).map((id) => id.trim()).filter((id) => id.length > 0);
33
+ if (refs.length === 0) {
33
34
  this.error('At least one --label-id is required.', { exit: 1 });
34
35
  }
36
+ // A name is resolved against the DECLARED vocabulary; an unknown one is
37
+ // refused with the near misses named, never created. See lib/label-ref.
38
+ let resolvedTargets = [];
39
+ try {
40
+ resolvedTargets = await (0, label_ref_1.resolveLabelRefs)(refs, {
41
+ applicableTo: 'task',
42
+ ...(process.env.OVERSKY_WORKSPACE_ID
43
+ ? { workspaceId: process.env.OVERSKY_WORKSPACE_ID }
44
+ : {}),
45
+ });
46
+ }
47
+ catch (err) {
48
+ if (err instanceof label_ref_1.LabelRefError)
49
+ this.error(err.message, { exit: 1 });
50
+ this.handleApiError(err);
51
+ }
52
+ const targets = new Set(resolvedTargets);
35
53
  let current;
36
54
  try {
37
55
  current = await data_provider_1.dataService.getTask(args.id, { enrich: false });
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ export default class TasksLifecycleAttach extends BaseCommand {
3
+ static description: string;
4
+ static args: {
5
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ pack: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ definition: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ version: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ };
13
+ run(): Promise<void>;
14
+ }