@skrr-ai/cli 0.1.37 → 0.1.38

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 (174) hide show
  1. package/bin/dev-fallback.js +167 -4
  2. package/dist/base-command.js +46 -2
  3. package/dist/commands/agents/actions/create.js +18 -7
  4. package/dist/commands/agents/actions/delete.d.ts +1 -0
  5. package/dist/commands/agents/actions/delete.js +7 -0
  6. package/dist/commands/agents/actions/update.js +5 -3
  7. package/dist/commands/agents/api-actions/add.js +5 -2
  8. package/dist/commands/agents/api-actions/index.d.ts +11 -0
  9. package/dist/commands/agents/api-actions/index.js +27 -1
  10. package/dist/commands/agents/avatar/default/index.d.ts +11 -0
  11. package/dist/commands/agents/avatar/default/index.js +17 -0
  12. package/dist/commands/agents/avatar/default/set.d.ts +2 -1
  13. package/dist/commands/agents/avatar/default/set.js +32 -7
  14. package/dist/commands/agents/avatar/upload.js +7 -1
  15. package/dist/commands/agents/categories/delete.js +8 -0
  16. package/dist/commands/agents/categories/index.d.ts +21 -5
  17. package/dist/commands/agents/categories/index.js +68 -15
  18. package/dist/commands/agents/chat.d.ts +21 -0
  19. package/dist/commands/agents/chat.js +94 -7
  20. package/dist/commands/agents/create.js +11 -4
  21. package/dist/commands/agents/list.d.ts +15 -0
  22. package/dist/commands/agents/list.js +31 -1
  23. package/dist/commands/agents/scene-background/upload.d.ts +30 -0
  24. package/dist/commands/agents/scene-background/upload.js +97 -0
  25. package/dist/commands/agents/show.js +13 -0
  26. package/dist/commands/agents/tools/calls.d.ts +23 -5
  27. package/dist/commands/agents/tools/calls.js +81 -18
  28. package/dist/commands/agents/update.js +15 -5
  29. package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
  30. package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
  31. package/dist/commands/convos/messages.d.ts +13 -0
  32. package/dist/commands/convos/messages.js +40 -16
  33. package/dist/commands/daemon/index.js +8 -1
  34. package/dist/commands/daemon/logs.d.ts +26 -0
  35. package/dist/commands/daemon/logs.js +56 -0
  36. package/dist/commands/daemon/uninstall.js +1 -1
  37. package/dist/commands/followups/act.js +3 -2
  38. package/dist/commands/followups/cancel.d.ts +6 -3
  39. package/dist/commands/followups/cancel.js +16 -6
  40. package/dist/commands/followups/observability.d.ts +23 -0
  41. package/dist/commands/followups/observability.js +114 -0
  42. package/dist/commands/followups/reschedule.js +1 -1
  43. package/dist/commands/followups/resolve.js +3 -3
  44. package/dist/commands/followups/show.js +2 -1
  45. package/dist/commands/followups/watch.js +9 -5
  46. package/dist/commands/harnesses/forget.js +28 -0
  47. package/dist/commands/harnesses/install.d.ts +41 -0
  48. package/dist/commands/harnesses/install.js +165 -0
  49. package/dist/commands/harnesses/installers.d.ts +45 -0
  50. package/dist/commands/harnesses/installers.js +155 -0
  51. package/dist/commands/harnesses/list.d.ts +82 -1
  52. package/dist/commands/harnesses/list.js +104 -12
  53. package/dist/commands/harnesses/models.js +10 -1
  54. package/dist/commands/harnesses/show.d.ts +15 -0
  55. package/dist/commands/harnesses/show.js +44 -3
  56. package/dist/commands/harnesses/update.js +1 -1
  57. package/dist/commands/harnesses/usage.d.ts +25 -0
  58. package/dist/commands/harnesses/usage.js +24 -2
  59. package/dist/commands/instructions/status.js +13 -1
  60. package/dist/commands/machines/dedicated/catalog.js +4 -15
  61. package/dist/commands/machines/dedicated/create.d.ts +8 -0
  62. package/dist/commands/machines/dedicated/create.js +58 -1
  63. package/dist/commands/machines/dedicated/destroy.js +18 -4
  64. package/dist/commands/machines/dedicated/list.js +9 -6
  65. package/dist/commands/machines/hosted/list.js +12 -0
  66. package/dist/commands/machines/list.js +11 -0
  67. package/dist/commands/machines/show.d.ts +1 -0
  68. package/dist/commands/machines/show.js +40 -11
  69. package/dist/commands/profiles/list.d.ts +23 -0
  70. package/dist/commands/profiles/list.js +96 -0
  71. package/dist/commands/search/skills.d.ts +11 -1
  72. package/dist/commands/search/skills.js +26 -8
  73. package/dist/commands/skills/details.d.ts +2 -0
  74. package/dist/commands/skills/details.js +24 -1
  75. package/dist/commands/skills/import-as-actions.d.ts +32 -0
  76. package/dist/commands/skills/import-as-actions.js +175 -0
  77. package/dist/commands/skills/install.d.ts +2 -0
  78. package/dist/commands/skills/install.js +24 -1
  79. package/dist/commands/skills/invocable.js +6 -2
  80. package/dist/commands/skills/local.d.ts +40 -0
  81. package/dist/commands/skills/local.js +160 -0
  82. package/dist/commands/skills/search.d.ts +11 -1
  83. package/dist/commands/skills/search.js +29 -8
  84. package/dist/commands/spaces/actions/add.js +23 -5
  85. package/dist/commands/spaces/actions/available.js +3 -0
  86. package/dist/commands/spaces/actions/list.d.ts +5 -0
  87. package/dist/commands/spaces/actions/list.js +49 -3
  88. package/dist/commands/spaces/actions/run.d.ts +28 -0
  89. package/dist/commands/spaces/actions/run.js +146 -0
  90. package/dist/commands/spaces/actions/update.js +27 -5
  91. package/dist/commands/spaces/label-summaries.d.ts +27 -0
  92. package/dist/commands/spaces/label-summaries.js +64 -0
  93. package/dist/commands/spaces/task-rollups.d.ts +5 -0
  94. package/dist/commands/spaces/task-rollups.js +15 -4
  95. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +63 -3
  96. package/dist/commands/tasks/actions/attach.js +32 -7
  97. package/dist/commands/tasks/complete.js +13 -0
  98. package/dist/commands/tasks/create.js +1 -1
  99. package/dist/commands/tasks/events/append.js +29 -6
  100. package/dist/commands/tasks/expectations/assess.d.ts +1 -0
  101. package/dist/commands/tasks/expectations/assess.js +43 -5
  102. package/dist/commands/tasks/expectations.js +77 -16
  103. package/dist/commands/tasks/follow-up.js +2 -2
  104. package/dist/commands/tasks/lifecycle/definitions.js +21 -2
  105. package/dist/commands/tasks/lifecycle/detach.d.ts +7 -0
  106. package/dist/commands/tasks/lifecycle/detach.js +43 -3
  107. package/dist/commands/tasks/lifecycle/migrate.d.ts +2 -0
  108. package/dist/commands/tasks/lifecycle/migrate.js +42 -3
  109. package/dist/commands/tasks/lifecycle/reopen.d.ts +2 -0
  110. package/dist/commands/tasks/lifecycle/reopen.js +40 -3
  111. package/dist/commands/tasks/lifecycle/transition.js +33 -2
  112. package/dist/commands/tasks/list.js +16 -9
  113. package/dist/commands/tasks/move.js +11 -13
  114. package/dist/commands/tasks/review-queue.d.ts +15 -0
  115. package/dist/commands/tasks/review-queue.js +180 -31
  116. package/dist/commands/tasks/show.d.ts +11 -0
  117. package/dist/commands/tasks/show.js +105 -12
  118. package/dist/commands/tasks/trust.js +7 -2
  119. package/dist/commands/tasks/update.js +46 -10
  120. package/dist/commands/tasks/updates/add.js +1 -1
  121. package/dist/commands/token/list.d.ts +22 -0
  122. package/dist/commands/token/list.js +68 -0
  123. package/dist/commands/token/revoke.d.ts +23 -0
  124. package/dist/commands/token/revoke.js +53 -0
  125. package/dist/lib/agent-actions.d.ts +57 -2
  126. package/dist/lib/agent-actions.js +113 -21
  127. package/dist/lib/agent-pin-mute.d.ts +10 -5
  128. package/dist/lib/agent-pin-mute.js +17 -4
  129. package/dist/lib/agent-visual-refs.d.ts +27 -0
  130. package/dist/lib/agent-visual-refs.js +127 -2
  131. package/dist/lib/agentic-stream.d.ts +6 -0
  132. package/dist/lib/agentic-stream.js +34 -3
  133. package/dist/lib/assignee-resolver.d.ts +1 -1
  134. package/dist/lib/assignee-resolver.js +8 -0
  135. package/dist/lib/bulk-task-targets.d.ts +12 -0
  136. package/dist/lib/bulk-task-targets.js +34 -1
  137. package/dist/lib/cli-installers.d.ts +130 -0
  138. package/dist/lib/cli-installers.js +145 -0
  139. package/dist/lib/command-miss.js +55 -7
  140. package/dist/lib/dedicated-lease-command.d.ts +13 -0
  141. package/dist/lib/dedicated-lease-command.js +22 -1
  142. package/dist/lib/dedicated-machines.d.ts +95 -1
  143. package/dist/lib/dedicated-machines.js +236 -2
  144. package/dist/lib/failed-lookup.d.ts +3 -0
  145. package/dist/lib/failed-lookup.js +40 -0
  146. package/dist/lib/first-party-harness-agent.js +9 -2
  147. package/dist/lib/first-party-harness-doctor.d.ts +15 -0
  148. package/dist/lib/first-party-harness-doctor.js +126 -27
  149. package/dist/lib/followups.d.ts +14 -6
  150. package/dist/lib/followups.js +31 -6
  151. package/dist/lib/harnesses.d.ts +8 -0
  152. package/dist/lib/instruction-input.d.ts +19 -1
  153. package/dist/lib/instruction-input.js +52 -1
  154. package/dist/lib/label-scope.d.ts +15 -0
  155. package/dist/lib/label-scope.js +25 -5
  156. package/dist/lib/local-skills.d.ts +98 -0
  157. package/dist/lib/local-skills.js +195 -0
  158. package/dist/lib/machines.d.ts +10 -10
  159. package/dist/lib/machines.js +23 -1
  160. package/dist/lib/search-query.d.ts +19 -0
  161. package/dist/lib/search-query.js +35 -0
  162. package/dist/lib/space-custom-actions.d.ts +72 -0
  163. package/dist/lib/space-custom-actions.js +117 -0
  164. package/dist/lib/space-resolver.d.ts +1 -21
  165. package/dist/lib/space-resolver.js +19 -10
  166. package/dist/lib/task-closure.d.ts +3 -2
  167. package/dist/lib/task-closure.js +18 -20
  168. package/dist/lib/task-lifecycle-output.js +117 -9
  169. package/dist/lib/task-ref-resolver.d.ts +1 -17
  170. package/dist/lib/task-ref-resolver.js +18 -8
  171. package/dist/lib/tasks.js +9 -3
  172. package/dist/node_modules/@skrr-ai/data-provider/index.js +5076 -4947
  173. package/oclif.manifest.json +26635 -25649
  174. package/package.json +9 -3
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_crypto_1 = require("node:crypto");
3
4
  const core_1 = require("@oclif/core");
4
5
  const data_provider_1 = require("@skrr-ai/data-provider");
5
6
  const base_command_1 = require("../../../base-command");
6
7
  const prompt_1 = require("../../../lib/prompt");
7
8
  const space_output_1 = require("../../../lib/space-output");
9
+ const space_custom_actions_1 = require("../../../lib/space-custom-actions");
8
10
  class SpacesActionsAdd extends base_command_1.BaseCommand {
9
11
  static description = 'Add a custom action to a space';
10
12
  static args = {
@@ -13,11 +15,11 @@ class SpacesActionsAdd extends base_command_1.BaseCommand {
13
15
  static flags = {
14
16
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
15
17
  'from-json': core_1.Flags.string({ description: 'JSON action body' }),
16
- id: core_1.Flags.string({ description: 'Action ID' }),
17
- label: core_1.Flags.string({ description: 'Button label' }),
18
+ id: core_1.Flags.string({ description: 'Action ID (generated when omitted)' }),
19
+ label: space_custom_actions_1.spaceCustomActionLabelFlag,
18
20
  prompt: core_1.Flags.string({ description: 'Prompt sent when the action runs' }),
19
21
  color: core_1.Flags.string({ description: 'Color hex' }),
20
- icon: core_1.Flags.string({ description: 'Lucide icon name' }),
22
+ icon: space_custom_actions_1.spaceCustomActionIconFlag,
21
23
  skill: core_1.Flags.string({ description: 'Optional skill ID' }),
22
24
  };
23
25
  async run() {
@@ -31,7 +33,10 @@ class SpacesActionsAdd extends base_command_1.BaseCommand {
31
33
  this.error(err.message, { exit: 1 });
32
34
  }
33
35
  const payload = (0, prompt_1.mergeDefined)(body, {
34
- id: flags.id,
36
+ // Generated when omitted, as `agents actions create` does. Demanding the
37
+ // caller invent an id — with only "Action id is required." to go on — was
38
+ // the one required field nothing else could supply.
39
+ id: flags.id ?? (typeof body.id === 'string' && body.id ? body.id : `act_${(0, node_crypto_1.randomUUID)()}`),
35
40
  label: flags.label,
36
41
  prompt: flags.prompt,
37
42
  color: flags.color,
@@ -41,6 +46,9 @@ class SpacesActionsAdd extends base_command_1.BaseCommand {
41
46
  for (const field of ['id', 'label', 'prompt', 'color'])
42
47
  if (!payload[field] || typeof payload[field] !== 'string')
43
48
  this.error(`Action ${field} is required.`, { exit: 1 });
49
+ const iconProblem = (0, space_custom_actions_1.spaceCustomActionIconProblem)(payload.icon);
50
+ if (iconProblem)
51
+ this.error(iconProblem, { exit: 1 });
44
52
  let result;
45
53
  try {
46
54
  result = await data_provider_1.dataService.addSpaceCustomAction({
@@ -51,10 +59,20 @@ class SpacesActionsAdd extends base_command_1.BaseCommand {
51
59
  catch (err) {
52
60
  this.handleApiError(err);
53
61
  }
62
+ // `--json` returns the action that was added, not the whole Space. The
63
+ // server answers with the full Space document — 117 lines in which the
64
+ // five-field action is buried — while `agents actions create --json`
65
+ // returns just the action. A create returns the thing it created.
66
+ const stored = (result?.customActions ?? []).find((action) => action.id === payload.id) ?? payload;
54
67
  if (flags.json)
55
- this.log(JSON.stringify((0, space_output_1.withSpaceResourceUrls)(this.cliConfig.baseURL, args.id, 'actions', result, ['id']), null, 2));
68
+ this.log(JSON.stringify((0, space_output_1.withSpaceResourceUrls)(this.cliConfig.baseURL, args.id, 'actions', stored, ['id']), null, 2));
56
69
  else
57
70
  this.log(`Added custom action ${String(payload.id)}.`);
71
+ // On stderr, so `--json` stays parseable: the action was saved, and still
72
+ // cannot run until the space has a Leader (OSK-9641).
73
+ const unrunnable = (0, space_custom_actions_1.spaceActionsNotRunnableReason)({ id: args.id, leadAgentId: result?.leadAgentId }, this.config.bin);
74
+ if (unrunnable)
75
+ this.warn(unrunnable);
58
76
  }
59
77
  }
60
78
  exports.default = SpacesActionsAdd;
@@ -51,7 +51,10 @@ class SpacesActionsAvailable extends base_command_1.BaseCommand {
51
51
  { key: 'ref', header: 'REF (agentId:actionId)' },
52
52
  ], (line) => this.log(line));
53
53
  this.log('');
54
+ // The REF is for two commands, and they need different rights: attaching
55
+ // works for any space member, running needs VIEW on the agent (OSK-9663).
54
56
  this.log('Attach to a task: skrr tasks actions attach <task-id> <agentId>:<actionId>');
57
+ this.log(`Run one in this space: skrr spaces actions run ${args.id} <agentId>:<actionId> (needs access to the agent; see what you can run with: skrr spaces actions list ${args.id} --all)`);
55
58
  }
56
59
  }
57
60
  exports.default = SpacesActionsAvailable;
@@ -4,8 +4,13 @@ export default class SpacesActionsList extends BaseCommand {
4
4
  static args: {
5
5
  id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
6
6
  };
7
+ static examples: string[];
7
8
  static flags: {
8
9
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ all: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
11
  };
10
12
  run(): Promise<void>;
13
+ /** Say, on stderr, when none of the listed space actions can run. */
14
+ private noteUnrunnable;
15
+ private listAll;
11
16
  }
@@ -4,13 +4,23 @@ 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
6
  const format_1 = require("../../../lib/format");
7
+ const space_custom_actions_1 = require("../../../lib/space-custom-actions");
7
8
  const space_output_1 = require("../../../lib/space-output");
8
9
  class SpacesActionsList extends base_command_1.BaseCommand {
9
10
  static description = 'List custom actions configured for a space';
10
11
  static args = {
11
12
  id: core_1.Args.string({ description: 'Space ID', required: true, ignoreStdin: true }),
12
13
  };
13
- static flags = { json: core_1.Flags.boolean({ description: 'Output as JSON' }) };
14
+ static examples = [
15
+ '<%= config.bin %> spaces actions list <space-id>',
16
+ '<%= config.bin %> spaces actions list <space-id> --all',
17
+ ];
18
+ static flags = {
19
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
20
+ all: core_1.Flags.boolean({
21
+ description: "Everything the space's action panel offers: its own actions and those of member agents you can view, each with the command that runs it",
22
+ }),
23
+ };
14
24
  async run() {
15
25
  this.requireAuth();
16
26
  const { args, flags } = await this.parse(SpacesActionsList);
@@ -22,12 +32,17 @@ class SpacesActionsList extends base_command_1.BaseCommand {
22
32
  this.handleApiError(err);
23
33
  }
24
34
  const actions = space.customActions ?? [];
35
+ if (flags.all)
36
+ return this.listAll(space, flags.json);
25
37
  if (flags.json)
26
38
  return void this.log(JSON.stringify((0, space_output_1.withSpaceResourceUrls)(this.cliConfig.baseURL, args.id, 'actions', { data: actions }, [
27
39
  'id',
28
40
  ]), null, 2));
29
- if (!actions.length)
30
- return void this.log('No custom actions.');
41
+ if (!actions.length) {
42
+ this.log('No custom actions.');
43
+ this.log(`Agent actions offered here: ${this.config.bin} spaces actions list ${args.id} --all`);
44
+ return;
45
+ }
31
46
  (0, format_1.renderTable)(actions.map((a) => ({
32
47
  id: a.id,
33
48
  label: a.label,
@@ -41,6 +56,37 @@ class SpacesActionsList extends base_command_1.BaseCommand {
41
56
  { key: 'skill', header: 'SKILL' },
42
57
  { key: 'id', header: 'ID' },
43
58
  ], (line) => this.log(line));
59
+ this.noteUnrunnable(space);
60
+ this.log(`Agent actions offered here too: ${this.config.bin} spaces actions list ${args.id} --all`);
61
+ }
62
+ /** Say, on stderr, when none of the listed space actions can run. */
63
+ noteUnrunnable(space) {
64
+ const reason = (0, space_custom_actions_1.spaceActionsNotRunnableReason)(space, this.config.bin);
65
+ if (reason)
66
+ this.warn(reason);
67
+ }
68
+ async listAll(space, json) {
69
+ let members;
70
+ try {
71
+ members = await data_provider_1.dataService.listSpaceMemberActions(space.id);
72
+ }
73
+ catch (err) {
74
+ this.handleApiError(err);
75
+ }
76
+ const rows = (0, space_custom_actions_1.spaceQuickActionRows)(space, members.agents, this.config.bin);
77
+ if (json)
78
+ return void this.log(JSON.stringify({ spaceId: space.id, data: rows }, null, 2));
79
+ if (!rows.length)
80
+ return void this.log('This space offers no quick actions.');
81
+ (0, format_1.renderTable)(rows, [
82
+ { key: 'source', header: 'SOURCE' },
83
+ { key: 'title', header: 'TITLE', maxWidth: 36 },
84
+ { key: 'owner', header: 'RUNS AS', maxWidth: 24 },
85
+ { key: 'type', header: 'TYPE' },
86
+ { key: 'run', header: 'RUN' },
87
+ ], (line) => this.log(line));
88
+ if (rows.some((row) => row.source === 'space'))
89
+ this.noteUnrunnable(space);
44
90
  }
45
91
  }
46
92
  exports.default = SpacesActionsList;
@@ -0,0 +1,28 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ /**
3
+ * Fire one of a space's quick actions, the way its Actions tab does.
4
+ *
5
+ * `spaces actions add` could create a space action and nothing on the CLI could
6
+ * run it (OSK-9641), and a space member handed `agentId:actionId` refs by
7
+ * `spaces actions available` had only `agents actions run`, which answers a
8
+ * member with 403 and opens a chat rather than working in the space (OSK-9663).
9
+ *
10
+ * The routing is the web runner's (`useSpaceQuickActionRunner`), not a new one:
11
+ * a prompt action runs as a task in this space, assigned to the Space Leader for
12
+ * a space's own action and to its agent for an agent's; a built-in action runs
13
+ * through the agent-action route. The task text comes from the same
14
+ * `spaceQuickActionTaskSpec` the web uses, so both surfaces hand the agent the
15
+ * same work.
16
+ */
17
+ export default class SpacesActionsRun extends BaseCommand {
18
+ static description: string;
19
+ static examples: string[];
20
+ static args: {
21
+ space: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
22
+ action: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
23
+ };
24
+ static flags: {
25
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
26
+ };
27
+ run(): Promise<void>;
28
+ }
@@ -0,0 +1,146 @@
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 space_custom_actions_1 = require("../../../lib/space-custom-actions");
7
+ const web_url_1 = require("../../../lib/web-url");
8
+ /**
9
+ * Fire one of a space's quick actions, the way its Actions tab does.
10
+ *
11
+ * `spaces actions add` could create a space action and nothing on the CLI could
12
+ * run it (OSK-9641), and a space member handed `agentId:actionId` refs by
13
+ * `spaces actions available` had only `agents actions run`, which answers a
14
+ * member with 403 and opens a chat rather than working in the space (OSK-9663).
15
+ *
16
+ * The routing is the web runner's (`useSpaceQuickActionRunner`), not a new one:
17
+ * a prompt action runs as a task in this space, assigned to the Space Leader for
18
+ * a space's own action and to its agent for an agent's; a built-in action runs
19
+ * through the agent-action route. The task text comes from the same
20
+ * `spaceQuickActionTaskSpec` the web uses, so both surfaces hand the agent the
21
+ * same work.
22
+ */
23
+ class SpacesActionsRun extends base_command_1.BaseCommand {
24
+ static description = "Run a space quick action: the space's own (by id) or a member agent's (agentId:actionId)";
25
+ static examples = [
26
+ '<%= config.bin %> spaces actions run <space-id> <action-id>',
27
+ '<%= config.bin %> spaces actions run <space-id> <agent-id>:<action-id> --json',
28
+ ];
29
+ static args = {
30
+ space: core_1.Args.string({ description: 'Space ID', required: true, ignoreStdin: true }),
31
+ action: core_1.Args.string({
32
+ description: "A space action id from 'spaces actions list', or agentId:actionId, both as 'spaces actions list --all' prints them",
33
+ required: true,
34
+ ignoreStdin: true,
35
+ }),
36
+ };
37
+ static flags = { json: core_1.Flags.boolean({ description: 'Output as JSON' }) };
38
+ async run() {
39
+ this.requireAuth();
40
+ const { args, flags } = await this.parse(SpacesActionsRun);
41
+ const bin = this.config.bin;
42
+ let space;
43
+ try {
44
+ space = await data_provider_1.dataService.getSpace(args.space);
45
+ }
46
+ catch (err) {
47
+ this.handleApiError(err);
48
+ }
49
+ const colon = args.action.indexOf(':');
50
+ const agentRef = colon > 0 && !args.action.startsWith('space-custom:')
51
+ ? { agentId: args.action.slice(0, colon), actionId: args.action.slice(colon + 1) }
52
+ : null;
53
+ let action;
54
+ let assigneeAgentId;
55
+ if (!agentRef) {
56
+ const found = (0, space_custom_actions_1.findSpaceCustomAction)(space, args.action);
57
+ if ('problem' in found)
58
+ this.error(found.problem, { exit: 4 });
59
+ const leaderProblem = (0, space_custom_actions_1.spaceActionsNotRunnableReason)(space, bin);
60
+ if (leaderProblem || !space.leadAgentId)
61
+ this.error(leaderProblem ?? '', { exit: 1 });
62
+ action = (0, data_provider_1.spaceCustomActionToAgentAction)(found.customAction, space, found.index);
63
+ assigneeAgentId = space.leadAgentId;
64
+ }
65
+ else {
66
+ let members;
67
+ try {
68
+ members = await data_provider_1.dataService.listSpaceMemberActions(args.space);
69
+ }
70
+ catch (err) {
71
+ this.handleApiError(err);
72
+ }
73
+ const member = members.agents.find(({ agent }) => agent.id === agentRef.agentId);
74
+ if (!member) {
75
+ this.error(`Agent ${agentRef.agentId} is not a member of this space that you can view, so you cannot ` +
76
+ `run its actions here. Attaching one to a task needs only the space: ` +
77
+ `\`${bin} tasks actions attach <task-id> ${args.action}\`. To run it, its owner has to share the agent with you.`, { exit: 1 });
78
+ }
79
+ const found = (member.agent.agentActions ?? []).find((a) => a.id === agentRef.actionId);
80
+ if (!found) {
81
+ this.error(`No action ${agentRef.actionId} on agent ${agentRef.agentId}. List what this space offers: \`${bin} spaces actions list ${args.space} --all\`.`, { exit: 4 });
82
+ }
83
+ if (!(0, data_provider_1.isAgentActionAvailableInSpace)(found, { spaceId: space.id, labelIds: space.labelIds })) {
84
+ this.error(`Action ${found.title} is not offered in this space (its scope is another space or a Label this space does not carry).`, { exit: 1 });
85
+ }
86
+ action = found;
87
+ assigneeAgentId = agentRef.agentId;
88
+ }
89
+ if ((0, data_provider_1.isBuiltinAgentAction)(action)) {
90
+ // A built-in is a typed platform operation owned by its agent, and runs
91
+ // through the agent-action route exactly as the web runner sends it.
92
+ let result;
93
+ try {
94
+ result = await data_provider_1.dataService.runAgentAction({
95
+ agent_id: assigneeAgentId,
96
+ action_id: action.id,
97
+ });
98
+ }
99
+ catch (err) {
100
+ this.handleApiError(err);
101
+ }
102
+ if (flags.json)
103
+ return void this.log(JSON.stringify(result, null, 2));
104
+ if (!result.ok)
105
+ this.error(result.error || result.reason || 'Action failed.', { exit: 1 });
106
+ this.log(`${action.title} ran.`);
107
+ return;
108
+ }
109
+ const outcome = (0, data_provider_1.agentActionOutcome)(action);
110
+ const spec = (0, data_provider_1.spaceQuickActionTaskSpec)(action, { id: space.id, title: space.title });
111
+ let created;
112
+ try {
113
+ created = await data_provider_1.dataService.createAndStartTask({
114
+ ...spec,
115
+ spaceId: space.id,
116
+ assigneeAgentIds: [assigneeAgentId],
117
+ });
118
+ }
119
+ catch (err) {
120
+ this.handleApiError(err, { subject: `Action ${action.title}` });
121
+ }
122
+ const taskUrl = (0, web_url_1.taskUrlFrom)(this.cliConfig.baseURL, created.task);
123
+ if (flags.json) {
124
+ this.log(JSON.stringify({ ...created, outcome, assigneeAgentId, ...(taskUrl ? { taskUrl } : {}) }, null, 2));
125
+ }
126
+ else {
127
+ const identifier = created.task.identifier ?? created.task.id;
128
+ this.log(created.started
129
+ ? `Started ${action.title} as task ${identifier}.`
130
+ : `Created task ${identifier} for ${action.title}, but it did not start: ${created.startError ?? 'no reason given'}.`);
131
+ if (taskUrl)
132
+ this.log(`Task: ${taskUrl}`);
133
+ if (created.conversationId)
134
+ this.log(`Conversation: ${created.conversationId}`);
135
+ if (created.started && outcome === 'ephemeral') {
136
+ // The web hides an ephemeral action's task when the run finishes, from
137
+ // the tab that fired it. The CLI does not wait for the run, so say what
138
+ // will be different rather than let the task's staying look like a bug.
139
+ this.log(`This action is ephemeral. The web app hides its task when the run finishes; from the CLI it stays until you hide it: \`${bin} tasks move ${created.task.id} --status hidden\`.`);
140
+ }
141
+ }
142
+ if (!created.started)
143
+ this.exit(1);
144
+ }
145
+ }
146
+ exports.default = SpacesActionsRun;
@@ -5,6 +5,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const base_command_1 = require("../../../base-command");
6
6
  const prompt_1 = require("../../../lib/prompt");
7
7
  const space_output_1 = require("../../../lib/space-output");
8
+ const space_custom_actions_1 = require("../../../lib/space-custom-actions");
8
9
  class SpacesActionsUpdate extends base_command_1.BaseCommand {
9
10
  static description = 'Update a custom action in a space';
10
11
  static args = {
@@ -14,10 +15,10 @@ class SpacesActionsUpdate extends base_command_1.BaseCommand {
14
15
  static flags = {
15
16
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
16
17
  'from-json': core_1.Flags.string({ description: 'JSON action patch' }),
17
- label: core_1.Flags.string({ description: 'Button label' }),
18
+ label: space_custom_actions_1.spaceCustomActionLabelFlag,
18
19
  prompt: core_1.Flags.string({ description: 'Prompt sent when the action runs' }),
19
20
  color: core_1.Flags.string({ description: 'Color hex' }),
20
- icon: core_1.Flags.string({ description: 'Lucide icon name' }),
21
+ icon: space_custom_actions_1.spaceCustomActionIconFlag,
21
22
  skill: core_1.Flags.string({ description: 'Optional skill ID' }),
22
23
  };
23
24
  async run() {
@@ -30,21 +31,39 @@ class SpacesActionsUpdate extends base_command_1.BaseCommand {
30
31
  catch (err) {
31
32
  this.error(err.message, { exit: 1 });
32
33
  }
33
- const payload = (0, prompt_1.mergeDefined)(body, {
34
+ const patch = (0, prompt_1.mergeDefined)(body, {
34
35
  label: flags.label,
35
36
  prompt: flags.prompt,
36
37
  color: flags.color,
37
38
  icon: flags.icon,
38
39
  skillId: flags.skill,
39
40
  });
40
- if (!Object.keys(payload).length)
41
+ if (!Object.keys(patch).length)
41
42
  this.error('Nothing to update.', { exit: 1 });
43
+ const iconProblem = (0, space_custom_actions_1.spaceCustomActionIconProblem)(patch.icon);
44
+ if (iconProblem)
45
+ this.error(iconProblem, { exit: 1 });
42
46
  let result;
47
+ let leadAgentId;
43
48
  try {
49
+ // The server replaces the WHOLE element (`$set: {'customActions.$': action}`)
50
+ // and validates a complete action — `id`, `label`, `prompt`, `color` — whose
51
+ // `id` must equal the path's. This command sent only the changed flags, so
52
+ // every call failed that validation: `--label` alone, `--prompt` alone, all
53
+ // of them together, 400 "Invalid request data" every time (OSK-9646). The
54
+ // web editor never hit it because it always sends the full action.
55
+ //
56
+ // So the patch is applied over the stored action here and sent whole.
57
+ const space = await data_provider_1.dataService.getSpace(args.space);
58
+ leadAgentId = space.leadAgentId;
59
+ const current = (space.customActions ?? []).find((action) => action.id === args.id);
60
+ if (!current) {
61
+ this.error(`No custom action ${args.id} in space ${args.space}. List them with \`spaces actions list ${args.space}\`.`, { exit: 1 });
62
+ }
44
63
  result = await data_provider_1.dataService.updateSpaceCustomAction({
45
64
  spaceId: args.space,
46
65
  actionId: args.id,
47
- action: payload,
66
+ action: { ...current, ...patch, id: args.id },
48
67
  });
49
68
  }
50
69
  catch (err) {
@@ -54,6 +73,9 @@ class SpacesActionsUpdate extends base_command_1.BaseCommand {
54
73
  this.log(JSON.stringify((0, space_output_1.withSpaceResourceUrls)(this.cliConfig.baseURL, args.space, 'actions', result, ['id']), null, 2));
55
74
  else
56
75
  this.log(`Updated custom action ${args.id}.`);
76
+ const unrunnable = (0, space_custom_actions_1.spaceActionsNotRunnableReason)({ id: args.space, leadAgentId }, this.config.bin);
77
+ if (unrunnable)
78
+ this.warn(unrunnable);
57
79
  }
58
80
  }
59
81
  exports.default = SpacesActionsUpdate;
@@ -0,0 +1,27 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * `skrr spaces label-summaries` — the label DEFINITIONS carried by every Space
4
+ * you can view, in one request.
5
+ *
6
+ * The third of the sidebar's batch reads, beside `spaces member-summaries` and
7
+ * `spaces task-rollups`, and the one that was never bound. `Space.labelIds`
8
+ * already says which Space carries which label, so what a caller holding a list
9
+ * of Spaces is missing is only the name and colour to resolve those ids
10
+ * against — and `GET /api/labels` takes exactly ONE (scope, scopeId) pair, so
11
+ * resolving them otherwise costs a request per row.
12
+ *
13
+ * Deliberately a flat list, matching the endpoint: one map, not one map per row.
14
+ *
15
+ * A label whose row is not returned is one the caller genuinely cannot read —
16
+ * another user's private label attached to a shared Space. It is reported as
17
+ * unresolved rather than hidden, because "this Space has a label you cannot
18
+ * see" and "this Space has no labels" are different facts.
19
+ */
20
+ export default class SpacesLabelSummaries extends BaseCommand {
21
+ static description: string;
22
+ static examples: string[];
23
+ static flags: {
24
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ };
26
+ run(): Promise<void>;
27
+ }
@@ -0,0 +1,64 @@
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 spaces label-summaries` — the label DEFINITIONS carried by every Space
8
+ * you can view, in one request.
9
+ *
10
+ * The third of the sidebar's batch reads, beside `spaces member-summaries` and
11
+ * `spaces task-rollups`, and the one that was never bound. `Space.labelIds`
12
+ * already says which Space carries which label, so what a caller holding a list
13
+ * of Spaces is missing is only the name and colour to resolve those ids
14
+ * against — and `GET /api/labels` takes exactly ONE (scope, scopeId) pair, so
15
+ * resolving them otherwise costs a request per row.
16
+ *
17
+ * Deliberately a flat list, matching the endpoint: one map, not one map per row.
18
+ *
19
+ * A label whose row is not returned is one the caller genuinely cannot read —
20
+ * another user's private label attached to a shared Space. It is reported as
21
+ * unresolved rather than hidden, because "this Space has a label you cannot
22
+ * see" and "this Space has no labels" are different facts.
23
+ */
24
+ class SpacesLabelSummaries extends base_command_1.BaseCommand {
25
+ static description = 'Show the label definitions used across every space you can view';
26
+ static examples = [
27
+ '<%= config.bin %> spaces label-summaries',
28
+ '<%= config.bin %> spaces label-summaries --json',
29
+ ];
30
+ static flags = {
31
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
32
+ };
33
+ async run() {
34
+ this.requireAuth();
35
+ const { flags } = await this.parse(SpacesLabelSummaries);
36
+ let response;
37
+ try {
38
+ response = await data_provider_1.dataService.listSpaceLabelSummaries();
39
+ }
40
+ catch (err) {
41
+ this.handleApiError(err);
42
+ return;
43
+ }
44
+ if (flags.json) {
45
+ this.log(JSON.stringify(response, null, 2));
46
+ return;
47
+ }
48
+ const labels = response.labels || [];
49
+ if (labels.length === 0) {
50
+ this.log('No labels on any space you can view.');
51
+ return;
52
+ }
53
+ const clip = (text, width) => text.length > width ? `${text.slice(0, width - 3)}...` : text;
54
+ this.log(`${'LABEL'.padEnd(28)} ${'SCOPE'.padEnd(10)} ${'COLOR'.padEnd(9)} ${'APPLIES TO'.padEnd(24)} ID`);
55
+ for (const label of labels) {
56
+ // `applicableTo` is what the label may be attached to, which is not the
57
+ // same as its scope — a workspace-scoped label can still be task-only.
58
+ const appliesTo = (label.applicableTo || []).join(', ') || '-';
59
+ this.log(`${clip(label.name, 28).padEnd(28)} ${String(label.scope ?? '-').padEnd(10)} ` +
60
+ `${String(label.color ?? '-').padEnd(9)} ${clip(appliesTo, 24).padEnd(24)} ${label.id}`);
61
+ }
62
+ }
63
+ }
64
+ exports.default = SpacesLabelSummaries;
@@ -3,6 +3,11 @@ import { BaseCommand } from '../../base-command';
3
3
  * `skrr spaces task-rollups` — task-status counts for every Space you can view,
4
4
  * in one request: the same rollup the Spaces sidebar row reads, counted by the
5
5
  * project-rollup rules (`done` is done only; `open` excludes cancelled).
6
+ *
7
+ * The SIGNAL column is the derived work band (`spaces/derive.ts`) — what the
8
+ * board is actually doing, as opposed to the status somebody declared on it.
9
+ * Sorting puts the boards that want a person first, which is the reason to run
10
+ * this from a terminal at all.
6
11
  */
7
12
  export default class SpacesTaskRollups extends BaseCommand {
8
13
  static description: string;
@@ -7,6 +7,11 @@ const base_command_1 = require("../../base-command");
7
7
  * `skrr spaces task-rollups` — task-status counts for every Space you can view,
8
8
  * in one request: the same rollup the Spaces sidebar row reads, counted by the
9
9
  * project-rollup rules (`done` is done only; `open` excludes cancelled).
10
+ *
11
+ * The SIGNAL column is the derived work band (`spaces/derive.ts`) — what the
12
+ * board is actually doing, as opposed to the status somebody declared on it.
13
+ * Sorting puts the boards that want a person first, which is the reason to run
14
+ * this from a terminal at all.
10
15
  */
11
16
  class SpacesTaskRollups extends base_command_1.BaseCommand {
12
17
  static description = 'Show task-status counts for every space you can view';
@@ -46,7 +51,11 @@ class SpacesTaskRollups extends base_command_1.BaseCommand {
46
51
  // A partial walk is not the whole picture; say so before the numbers.
47
52
  this.log(`Degraded: ${(response.warnings || []).join('; ') || 'some spaces were not counted'}`);
48
53
  }
49
- const rows = [...(response.rollups || [])].sort((a, b) => b.tasks.open - a.tasks.open);
54
+ // Most-urgent first: a parked agent, then a blocked board, then a stalled
55
+ // one, then the rest by open count. The band order is the shared one, so
56
+ // this list and the web sidebar rank the same boards the same way.
57
+ const bandRank = (rollup) => data_provider_1.SPACE_ACTIVITY_BAND_ORDER.indexOf((0, data_provider_1.spaceWorkBand)(rollup));
58
+ const rows = [...(response.rollups || [])].sort((a, b) => bandRank(a.tasks) - bandRank(b.tasks) || b.tasks.open - a.tasks.open);
50
59
  if (rows.length === 0) {
51
60
  this.log('No spaces with tasks.');
52
61
  return;
@@ -54,11 +63,13 @@ class SpacesTaskRollups extends base_command_1.BaseCommand {
54
63
  const label = (spaceId) => {
55
64
  const title = titles.get(spaceId);
56
65
  const text = title ? `${title} (${spaceId.slice(0, 8)})` : spaceId;
57
- return text.length > 48 ? `${text.slice(0, 45)}...` : text;
66
+ return text.length > 44 ? `${text.slice(0, 41)}...` : text;
58
67
  };
59
- this.log(`${'SPACE'.padEnd(48)} ${'OPEN'.padStart(5)} ${'DONE'.padStart(5)} ${'BLOCKED'.padStart(7)} ${'TOTAL'.padStart(5)}`);
68
+ this.log(`${'SPACE'.padEnd(44)} ${'SIGNAL'.padEnd(15)} ${'OPEN'.padStart(5)} ${'DONE'.padStart(5)} ${'BLOCKED'.padStart(7)} ${'TOTAL'.padStart(5)}`);
60
69
  for (const { spaceId, tasks } of rows) {
61
- this.log(`${label(spaceId).padEnd(48)} ${String(tasks.open).padStart(5)} ${String(tasks.done).padStart(5)} ` +
70
+ const band = (0, data_provider_1.spaceWorkBand)(tasks);
71
+ this.log(`${label(spaceId).padEnd(44)} ${(data_provider_1.SPACE_ACTIVITY_BAND_LABELS[band] ?? band).padEnd(15)} ` +
72
+ `${String(tasks.open).padStart(5)} ${String(tasks.done).padStart(5)} ` +
62
73
  `${String(tasks.blocked).padStart(7)} ${String(tasks.total).padStart(5)}`);
63
74
  }
64
75
  }