@skrr-ai/cli 0.1.36 → 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 (266) hide show
  1. package/README.md +17 -4
  2. package/bin/dev-fallback.js +167 -4
  3. package/dist/base-command.js +46 -2
  4. package/dist/commands/agents/actions/create.d.ts +5 -0
  5. package/dist/commands/agents/actions/create.js +42 -5
  6. package/dist/commands/agents/actions/delete.d.ts +1 -0
  7. package/dist/commands/agents/actions/delete.js +7 -0
  8. package/dist/commands/agents/actions/update.d.ts +5 -0
  9. package/dist/commands/agents/actions/update.js +27 -1
  10. package/dist/commands/agents/api-actions/add.d.ts +41 -0
  11. package/dist/commands/agents/api-actions/add.js +205 -0
  12. package/dist/commands/agents/api-actions/index.d.ts +39 -0
  13. package/dist/commands/agents/api-actions/index.js +103 -0
  14. package/dist/commands/agents/api-actions/remove.d.ts +14 -0
  15. package/dist/commands/agents/api-actions/remove.js +36 -0
  16. package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
  17. package/dist/commands/agents/avatar/default/apply.js +56 -0
  18. package/dist/commands/agents/avatar/default/index.d.ts +29 -0
  19. package/dist/commands/agents/avatar/default/index.js +61 -0
  20. package/dist/commands/agents/avatar/default/set.d.ts +24 -0
  21. package/dist/commands/agents/avatar/default/set.js +120 -0
  22. package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
  23. package/dist/commands/agents/avatar/library/delete.js +47 -0
  24. package/dist/commands/agents/avatar/library/index.d.ts +16 -0
  25. package/dist/commands/agents/avatar/library/index.js +56 -0
  26. package/dist/commands/agents/avatar/presets.d.ts +19 -0
  27. package/dist/commands/agents/avatar/presets.js +56 -0
  28. package/dist/commands/agents/avatar/upload.js +7 -1
  29. package/dist/commands/agents/categories/create.d.ts +14 -0
  30. package/dist/commands/agents/categories/create.js +46 -0
  31. package/dist/commands/agents/categories/delete.d.ts +13 -0
  32. package/dist/commands/agents/categories/delete.js +41 -0
  33. package/dist/commands/agents/categories/index.d.ts +36 -0
  34. package/dist/commands/agents/categories/index.js +135 -0
  35. package/dist/commands/agents/categories/update.d.ts +22 -0
  36. package/dist/commands/agents/categories/update.js +59 -0
  37. package/dist/commands/agents/chat.d.ts +21 -0
  38. package/dist/commands/agents/chat.js +94 -7
  39. package/dist/commands/agents/create.d.ts +10 -0
  40. package/dist/commands/agents/create.js +64 -3
  41. package/dist/commands/agents/ensure-default.d.ts +27 -0
  42. package/dist/commands/agents/ensure-default.js +65 -0
  43. package/dist/commands/agents/list.d.ts +15 -0
  44. package/dist/commands/agents/list.js +31 -1
  45. package/dist/commands/agents/mute.d.ts +16 -0
  46. package/dist/commands/agents/mute.js +38 -0
  47. package/dist/commands/agents/pin.d.ts +16 -0
  48. package/dist/commands/agents/pin.js +38 -0
  49. package/dist/commands/agents/scene-background/upload.d.ts +30 -0
  50. package/dist/commands/agents/scene-background/upload.js +97 -0
  51. package/dist/commands/agents/show.js +13 -0
  52. package/dist/commands/agents/tools/auth.d.ts +19 -0
  53. package/dist/commands/agents/tools/auth.js +41 -0
  54. package/dist/commands/agents/tools/calls.d.ts +36 -0
  55. package/dist/commands/agents/tools/calls.js +117 -0
  56. package/dist/commands/agents/tools/index.d.ts +20 -0
  57. package/dist/commands/agents/tools/index.js +77 -0
  58. package/dist/commands/agents/unmute.d.ts +16 -0
  59. package/dist/commands/agents/unmute.js +38 -0
  60. package/dist/commands/agents/unpin.d.ts +16 -0
  61. package/dist/commands/agents/unpin.js +38 -0
  62. package/dist/commands/agents/update.d.ts +12 -0
  63. package/dist/commands/agents/update.js +74 -3
  64. package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
  65. package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
  66. package/dist/commands/convos/messages.d.ts +13 -0
  67. package/dist/commands/convos/messages.js +40 -16
  68. package/dist/commands/daemon/index.js +8 -1
  69. package/dist/commands/daemon/logs.d.ts +26 -0
  70. package/dist/commands/daemon/logs.js +56 -0
  71. package/dist/commands/daemon/uninstall.js +1 -1
  72. package/dist/commands/followups/act.d.ts +22 -0
  73. package/dist/commands/followups/act.js +103 -0
  74. package/dist/commands/followups/cancel.d.ts +20 -0
  75. package/dist/commands/followups/cancel.js +50 -0
  76. package/dist/commands/followups/checkin.d.ts +27 -0
  77. package/dist/commands/followups/checkin.js +107 -0
  78. package/dist/commands/followups/list.d.ts +24 -0
  79. package/dist/commands/followups/list.js +90 -0
  80. package/dist/commands/followups/observability.d.ts +23 -0
  81. package/dist/commands/followups/observability.js +114 -0
  82. package/dist/commands/followups/remind.d.ts +26 -0
  83. package/dist/commands/followups/remind.js +106 -0
  84. package/dist/commands/followups/reschedule.d.ts +15 -0
  85. package/dist/commands/followups/reschedule.js +48 -0
  86. package/dist/commands/followups/resolve.d.ts +23 -0
  87. package/dist/commands/followups/resolve.js +54 -0
  88. package/dist/commands/followups/show.d.ts +12 -0
  89. package/dist/commands/followups/show.js +46 -0
  90. package/dist/commands/followups/watch.d.ts +51 -0
  91. package/dist/commands/followups/watch.js +211 -0
  92. package/dist/commands/goals/labels/add.js +19 -2
  93. package/dist/commands/goals/labels/remove.js +22 -2
  94. package/dist/commands/harnesses/forget.js +28 -0
  95. package/dist/commands/harnesses/install.d.ts +41 -0
  96. package/dist/commands/harnesses/install.js +165 -0
  97. package/dist/commands/harnesses/installers.d.ts +45 -0
  98. package/dist/commands/harnesses/installers.js +155 -0
  99. package/dist/commands/harnesses/list.d.ts +82 -1
  100. package/dist/commands/harnesses/list.js +104 -12
  101. package/dist/commands/harnesses/models.js +10 -1
  102. package/dist/commands/harnesses/show.d.ts +15 -0
  103. package/dist/commands/harnesses/show.js +44 -3
  104. package/dist/commands/harnesses/update.js +1 -1
  105. package/dist/commands/harnesses/usage.d.ts +25 -0
  106. package/dist/commands/harnesses/usage.js +24 -2
  107. package/dist/commands/instructions/status.js +13 -1
  108. package/dist/commands/labels/list.d.ts +24 -1
  109. package/dist/commands/labels/list.js +62 -19
  110. package/dist/commands/machines/dedicated/catalog.js +4 -15
  111. package/dist/commands/machines/dedicated/create.d.ts +8 -0
  112. package/dist/commands/machines/dedicated/create.js +58 -1
  113. package/dist/commands/machines/dedicated/destroy.js +18 -4
  114. package/dist/commands/machines/dedicated/list.js +9 -6
  115. package/dist/commands/machines/hosted/list.js +12 -0
  116. package/dist/commands/machines/list.js +11 -0
  117. package/dist/commands/machines/show.d.ts +1 -0
  118. package/dist/commands/machines/show.js +40 -11
  119. package/dist/commands/memory/governance/index.d.ts +21 -0
  120. package/dist/commands/memory/governance/index.js +64 -0
  121. package/dist/commands/memory/governance/set.d.ts +24 -0
  122. package/dist/commands/memory/governance/set.js +95 -0
  123. package/dist/commands/memory/provenance.d.ts +18 -0
  124. package/dist/commands/memory/provenance.js +66 -0
  125. package/dist/commands/profiles/list.d.ts +23 -0
  126. package/dist/commands/profiles/list.js +96 -0
  127. package/dist/commands/search/skills.d.ts +11 -1
  128. package/dist/commands/search/skills.js +26 -8
  129. package/dist/commands/skills/details.d.ts +2 -0
  130. package/dist/commands/skills/details.js +24 -1
  131. package/dist/commands/skills/import-as-actions.d.ts +32 -0
  132. package/dist/commands/skills/import-as-actions.js +175 -0
  133. package/dist/commands/skills/install.d.ts +2 -0
  134. package/dist/commands/skills/install.js +24 -1
  135. package/dist/commands/skills/invocable.js +6 -2
  136. package/dist/commands/skills/local.d.ts +40 -0
  137. package/dist/commands/skills/local.js +160 -0
  138. package/dist/commands/skills/search.d.ts +11 -1
  139. package/dist/commands/skills/search.js +29 -8
  140. package/dist/commands/spaces/actions/add.js +23 -5
  141. package/dist/commands/spaces/actions/available.js +3 -0
  142. package/dist/commands/spaces/actions/list.d.ts +5 -0
  143. package/dist/commands/spaces/actions/list.js +49 -3
  144. package/dist/commands/spaces/actions/run.d.ts +28 -0
  145. package/dist/commands/spaces/actions/run.js +146 -0
  146. package/dist/commands/spaces/actions/update.js +27 -5
  147. package/dist/commands/spaces/create.d.ts +3 -0
  148. package/dist/commands/spaces/create.js +32 -2
  149. package/dist/commands/spaces/label-summaries.d.ts +27 -0
  150. package/dist/commands/spaces/label-summaries.js +64 -0
  151. package/dist/commands/spaces/labels/add.js +19 -2
  152. package/dist/commands/spaces/labels/remove.js +22 -2
  153. package/dist/commands/spaces/show.js +2 -0
  154. package/dist/commands/spaces/task-rollups.d.ts +5 -0
  155. package/dist/commands/spaces/task-rollups.js +15 -4
  156. package/dist/commands/spaces/update.d.ts +5 -0
  157. package/dist/commands/spaces/update.js +41 -4
  158. package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
  159. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +105 -0
  160. package/dist/commands/tasks/actions/attach.js +32 -7
  161. package/dist/commands/tasks/complete.d.ts +1 -0
  162. package/dist/commands/tasks/complete.js +21 -1
  163. package/dist/commands/tasks/create.d.ts +3 -0
  164. package/dist/commands/tasks/create.js +34 -2
  165. package/dist/commands/tasks/events/append.js +29 -6
  166. package/dist/commands/tasks/expectations/assess.d.ts +12 -0
  167. package/dist/commands/tasks/expectations/assess.js +123 -14
  168. package/dist/commands/tasks/expectations.js +95 -17
  169. package/dist/commands/tasks/follow-up.js +2 -2
  170. package/dist/commands/tasks/labels/attach.js +20 -3
  171. package/dist/commands/tasks/labels/detach.js +21 -3
  172. package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
  173. package/dist/commands/tasks/lifecycle/attach.js +47 -0
  174. package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
  175. package/dist/commands/tasks/lifecycle/definitions.js +59 -0
  176. package/dist/commands/tasks/lifecycle/detach.d.ts +19 -0
  177. package/dist/commands/tasks/lifecycle/detach.js +72 -0
  178. package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
  179. package/dist/commands/tasks/lifecycle/history.js +38 -0
  180. package/dist/commands/tasks/lifecycle/migrate.d.ts +14 -0
  181. package/dist/commands/tasks/lifecycle/migrate.js +68 -0
  182. package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
  183. package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
  184. package/dist/commands/tasks/lifecycle/reopen.d.ts +15 -0
  185. package/dist/commands/tasks/lifecycle/reopen.js +71 -0
  186. package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
  187. package/dist/commands/tasks/lifecycle/show.js +27 -0
  188. package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
  189. package/dist/commands/tasks/lifecycle/start.js +30 -0
  190. package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
  191. package/dist/commands/tasks/lifecycle/transition.js +109 -0
  192. package/dist/commands/tasks/list.js +16 -9
  193. package/dist/commands/tasks/move.d.ts +1 -0
  194. package/dist/commands/tasks/move.js +29 -0
  195. package/dist/commands/tasks/result/submit.js +11 -1
  196. package/dist/commands/tasks/review-queue.d.ts +44 -0
  197. package/dist/commands/tasks/review-queue.js +314 -0
  198. package/dist/commands/tasks/show.d.ts +11 -0
  199. package/dist/commands/tasks/show.js +139 -4
  200. package/dist/commands/tasks/trust.js +7 -2
  201. package/dist/commands/tasks/update.d.ts +1 -0
  202. package/dist/commands/tasks/update.js +83 -0
  203. package/dist/commands/tasks/updates/add.js +1 -1
  204. package/dist/commands/token/list.d.ts +22 -0
  205. package/dist/commands/token/list.js +68 -0
  206. package/dist/commands/token/revoke.d.ts +23 -0
  207. package/dist/commands/token/revoke.js +53 -0
  208. package/dist/lib/agent-actions.d.ts +92 -11
  209. package/dist/lib/agent-actions.js +171 -25
  210. package/dist/lib/agent-config.d.ts +11 -0
  211. package/dist/lib/agent-config.js +85 -3
  212. package/dist/lib/agent-pin-mute.d.ts +29 -0
  213. package/dist/lib/agent-pin-mute.js +30 -0
  214. package/dist/lib/agent-visual-refs.d.ts +33 -0
  215. package/dist/lib/agent-visual-refs.js +267 -0
  216. package/dist/lib/agentic-stream.d.ts +6 -0
  217. package/dist/lib/agentic-stream.js +34 -3
  218. package/dist/lib/assignee-resolver.d.ts +1 -1
  219. package/dist/lib/assignee-resolver.js +8 -0
  220. package/dist/lib/bulk-task-targets.d.ts +12 -0
  221. package/dist/lib/bulk-task-targets.js +34 -1
  222. package/dist/lib/cli-installers.d.ts +130 -0
  223. package/dist/lib/cli-installers.js +145 -0
  224. package/dist/lib/command-miss.js +55 -7
  225. package/dist/lib/dedicated-lease-command.d.ts +13 -0
  226. package/dist/lib/dedicated-lease-command.js +22 -1
  227. package/dist/lib/dedicated-machines.d.ts +95 -1
  228. package/dist/lib/dedicated-machines.js +236 -2
  229. package/dist/lib/failed-lookup.d.ts +3 -0
  230. package/dist/lib/failed-lookup.js +40 -0
  231. package/dist/lib/first-party-harness-agent.js +16 -2
  232. package/dist/lib/first-party-harness-doctor.d.ts +15 -0
  233. package/dist/lib/first-party-harness-doctor.js +126 -27
  234. package/dist/lib/followups.d.ts +115 -0
  235. package/dist/lib/followups.js +127 -0
  236. package/dist/lib/harnesses.d.ts +8 -0
  237. package/dist/lib/instruction-input.d.ts +19 -1
  238. package/dist/lib/instruction-input.js +52 -1
  239. package/dist/lib/label-ref.d.ts +95 -0
  240. package/dist/lib/label-ref.js +163 -0
  241. package/dist/lib/label-scope.d.ts +17 -2
  242. package/dist/lib/label-scope.js +27 -7
  243. package/dist/lib/local-skills.d.ts +98 -0
  244. package/dist/lib/local-skills.js +195 -0
  245. package/dist/lib/machines.d.ts +10 -10
  246. package/dist/lib/machines.js +23 -1
  247. package/dist/lib/search-query.d.ts +19 -0
  248. package/dist/lib/search-query.js +35 -0
  249. package/dist/lib/space-custom-actions.d.ts +72 -0
  250. package/dist/lib/space-custom-actions.js +117 -0
  251. package/dist/lib/space-resolver.d.ts +1 -21
  252. package/dist/lib/space-resolver.js +19 -10
  253. package/dist/lib/task-closure.d.ts +33 -0
  254. package/dist/lib/task-closure.js +104 -0
  255. package/dist/lib/task-lifecycle-output.d.ts +14 -0
  256. package/dist/lib/task-lifecycle-output.js +209 -0
  257. package/dist/lib/task-ref-resolver.d.ts +1 -17
  258. package/dist/lib/task-ref-resolver.js +18 -8
  259. package/dist/lib/tasks.d.ts +3 -0
  260. package/dist/lib/tasks.js +40 -3
  261. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
  262. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
  263. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  264. package/dist/node_modules/@skrr-ai/data-provider/index.js +5559 -4897
  265. package/oclif.manifest.json +33890 -28690
  266. package/package.json +24 -6
@@ -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 local_skills_1 = require("../../lib/local-skills");
6
7
  class SkillsDetails extends base_command_1.BaseCommand {
7
8
  static description = 'Show full details for a skill';
8
9
  static examples = [
@@ -15,15 +16,37 @@ class SkillsDetails extends base_command_1.BaseCommand {
15
16
  static flags = {
16
17
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
17
18
  };
19
+ /** A store 404 for a name that may be a skill on the caller's machine. */
20
+ async failOnStoreMiss(err, id) {
21
+ if (err?.status === 404) {
22
+ this.failWithCliError({
23
+ message: (0, local_skills_1.describeStoreSkillMiss)(id, await (0, local_skills_1.findLocalSkillsNamed)(id), 'details'),
24
+ code: 'NOT_FOUND',
25
+ status: 404,
26
+ exit: 1,
27
+ retryable: false,
28
+ });
29
+ }
30
+ this.handleApiError(err);
31
+ }
18
32
  async run() {
19
33
  this.requireAuth();
20
34
  const { args, flags } = await this.parse(SkillsDetails);
35
+ // A path is never a store id: say so before asking the store (OSK-9412).
36
+ if ((0, local_skills_1.looksLikeSkillPath)(args.id)) {
37
+ this.failWithCliError({
38
+ message: (0, local_skills_1.describeStoreSkillMiss)(args.id, [], 'details'),
39
+ code: 'STORE_SKILL_ID_EXPECTED',
40
+ exit: 2,
41
+ retryable: false,
42
+ });
43
+ }
21
44
  let skill;
22
45
  try {
23
46
  skill = await data_provider_1.dataService.getSkill(args.id);
24
47
  }
25
48
  catch (err) {
26
- this.handleApiError(err);
49
+ await this.failOnStoreMiss(err, args.id);
27
50
  }
28
51
  if (flags.json) {
29
52
  this.log(JSON.stringify(skill, null, 2));
@@ -0,0 +1,32 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * Import a machine's local skills into an agent, each as a quick action.
4
+ *
5
+ * `skrr skills local` listed these skills and nothing in the CLI could act on
6
+ * them: the server route and the web dialog existed, and a headless operator or
7
+ * a locally-running coding agent had no way in (OSK-9659).
8
+ *
9
+ * The whole selection goes in ONE request, as the route requires — the agent's
10
+ * action library is one document field, and one request per skill is the
11
+ * lost-update race the route was built to avoid. Each skill comes back with its
12
+ * own status, because partial success is the normal result.
13
+ */
14
+ export default class SkillsImportAsActions extends BaseCommand {
15
+ static description: string;
16
+ static examples: string[];
17
+ static strict: boolean;
18
+ static args: {
19
+ skills: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
20
+ };
21
+ static flags: {
22
+ agent: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ daemon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ scope: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ label: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
27
+ outcome: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
28
+ 'attach-to-space': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
29
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
30
+ };
31
+ run(): Promise<void>;
32
+ }
@@ -0,0 +1,175 @@
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 agent_actions_1 = require("../../lib/agent-actions");
7
+ const format_1 = require("../../lib/format");
8
+ const local_skills_1 = require("../../lib/local-skills");
9
+ /**
10
+ * Import a machine's local skills into an agent, each as a quick action.
11
+ *
12
+ * `skrr skills local` listed these skills and nothing in the CLI could act on
13
+ * them: the server route and the web dialog existed, and a headless operator or
14
+ * a locally-running coding agent had no way in (OSK-9659).
15
+ *
16
+ * The whole selection goes in ONE request, as the route requires — the agent's
17
+ * action library is one document field, and one request per skill is the
18
+ * lost-update race the route was built to avoid. Each skill comes back with its
19
+ * own status, because partial success is the normal result.
20
+ */
21
+ class SkillsImportAsActions extends base_command_1.BaseCommand {
22
+ static description = "Import skills from a machine into an agent, each as a quick action (discover them with 'skills local')";
23
+ static examples = [
24
+ '<%= config.bin %> skills import-as-actions dogfood db-performance --agent <agent-id>',
25
+ '<%= config.bin %> skills import-as-actions dogfood --agent <agent-id> --space <space-id> --outcome durable',
26
+ '<%= config.bin %> skills import-as-actions dogfood --agent <agent-id> --label dogfood',
27
+ ];
28
+ static strict = false;
29
+ static args = {
30
+ skills: core_1.Args.string({
31
+ description: 'Skill name(s) as `skills local` lists them. Repeatable, 1-20.',
32
+ required: false,
33
+ ignoreStdin: true,
34
+ }),
35
+ };
36
+ static flags = {
37
+ agent: core_1.Flags.string({
38
+ description: 'Agent that will own the actions (needs EDIT)',
39
+ required: true,
40
+ }),
41
+ daemon: core_1.Flags.string({
42
+ description: 'Which machine to import from. Defaults to your only connected daemon.',
43
+ }),
44
+ scope: core_1.Flags.string({
45
+ description: 'Where the actions are offered. Implied by --space / --label.',
46
+ options: [...agent_actions_1.AGENT_ACTION_SCOPE_CHOICES],
47
+ }),
48
+ space: core_1.Flags.string({ description: 'Offer only in this space (implies --scope space)' }),
49
+ label: core_1.Flags.string({
50
+ description: 'Offer in every space carrying this Label — id or name (repeatable, any-of; implies --scope label)',
51
+ multiple: true,
52
+ }),
53
+ outcome: core_1.Flags.string({
54
+ description: "What a run leaves behind: 'durable' keeps its task on the board",
55
+ options: [...agent_actions_1.AGENT_ACTION_OUTCOME_CHOICES],
56
+ }),
57
+ 'attach-to-space': core_1.Flags.string({
58
+ description: "Also add each imported skill to this space's skill library (needs EDIT)",
59
+ }),
60
+ json: core_1.Flags.boolean({ description: 'Output the per-skill results as JSON' }),
61
+ };
62
+ async run() {
63
+ this.requireAuth();
64
+ const { argv, flags } = await this.parse(SkillsImportAsActions);
65
+ const names = [...new Set(argv.map((name) => name.trim()).filter(Boolean))];
66
+ if (names.length === 0) {
67
+ this.error('Name at least one skill. List them with: skills local', { exit: 1 });
68
+ }
69
+ if (names.length > 20) {
70
+ this.error(`At most 20 skills per import (got ${names.length}).`, { exit: 1 });
71
+ }
72
+ let daemonId = flags.daemon;
73
+ if (!daemonId) {
74
+ let daemons;
75
+ try {
76
+ daemons = await data_provider_1.dataService.getDaemons();
77
+ }
78
+ catch (err) {
79
+ this.handleApiError(err);
80
+ return;
81
+ }
82
+ const choice = (0, local_skills_1.chooseDaemon)(daemons.active ?? []);
83
+ if (!('daemonId' in choice)) {
84
+ const listed = choice.candidates.map((d) => ` --daemon ${d.daemonId}${d.deviceName ? ` (${d.deviceName})` : ''}`);
85
+ this.error([choice.problem, ...listed].join('\n'), { exit: 2 });
86
+ }
87
+ daemonId = choice.daemonId;
88
+ }
89
+ // Resolve each name against the machine's own listing. The listing's
90
+ // `pathHash` round-trips to the route so a skill renamed or replaced since
91
+ // it was listed is refused rather than silently importing something else,
92
+ // and an unknown name fails here with the list, not as a per-skill error.
93
+ let listing;
94
+ let version;
95
+ try {
96
+ const response = await data_provider_1.dataService.getDaemonSkills(daemonId);
97
+ listing = response.skills ?? [];
98
+ version = response.version;
99
+ }
100
+ catch (err) {
101
+ this.handleApiError(err);
102
+ return;
103
+ }
104
+ const byName = new Map(listing.map((skill) => [String(skill.name), skill]));
105
+ const unknown = names.filter((name) => !byName.has(name));
106
+ if (unknown.length > 0) {
107
+ const tooOld = (0, local_skills_1.daemonPredates)(version, local_skills_1.SKILL_CONVENTION_DISCOVERY_SINCE);
108
+ this.error(tooOld
109
+ ? `This daemon (${version}) cannot see skills in the conventions — discovery arrived in ${local_skills_1.SKILL_CONVENTION_DISCOVERY_SINCE}. Update it, run \`${this.config.bin} daemon restart\`, then try again.`
110
+ : `Not on ${daemonId}: ${unknown.join(', ')}. List what is there with: ${this.config.bin} skills local --daemon ${daemonId}`, { exit: 1 });
111
+ }
112
+ let scopeParams = {};
113
+ try {
114
+ const scope = await (0, agent_actions_1.resolveAgentActionScopeFlags)(flags);
115
+ if (scope?.kind === 'space')
116
+ scopeParams = { scope: 'space', spaceId: scope.spaceId };
117
+ else if (scope?.kind === 'label')
118
+ scopeParams = { scope: 'label', labelIds: scope.labelIds };
119
+ else if (scope?.kind === 'general')
120
+ scopeParams = { scope: 'general' };
121
+ }
122
+ catch (err) {
123
+ this.error(err.message, { exit: 1 });
124
+ }
125
+ let result;
126
+ try {
127
+ result = await data_provider_1.dataService.importDaemonSkillsAsActions({
128
+ daemonId,
129
+ targetAgentId: flags.agent,
130
+ skills: names.map((name) => {
131
+ const pathHash = byName.get(name)?.pathHash;
132
+ return pathHash ? { name, pathHash: String(pathHash) } : { name };
133
+ }),
134
+ ...scopeParams,
135
+ ...(flags.outcome ? { outcome: flags.outcome } : {}),
136
+ ...(flags['attach-to-space'] ? { attachToSpaceId: flags['attach-to-space'] } : {}),
137
+ });
138
+ }
139
+ catch (err) {
140
+ this.handleApiError(err);
141
+ return;
142
+ }
143
+ const failed = result.results.filter((r) => r.status === 'failed');
144
+ if (flags.json) {
145
+ this.log(JSON.stringify(result, null, 2));
146
+ }
147
+ else {
148
+ (0, format_1.renderTable)(result.results.map((r) => ({
149
+ skill: r.name,
150
+ import: r.status,
151
+ action: r.actionCreated
152
+ ? 'created'
153
+ : (r.actionSkippedReason ??
154
+ r.actionError ??
155
+ (r.status === 'failed' ? '-' : 'not added')),
156
+ detail: r.error ?? '',
157
+ })), [
158
+ { key: 'skill', header: 'SKILL' },
159
+ { key: 'import', header: 'IMPORT' },
160
+ { key: 'action', header: 'ACTION' },
161
+ { key: 'detail', header: 'DETAIL' },
162
+ ], (line) => this.log(line));
163
+ this.log(`${result.actionsCreated} action(s) created on ${result.targetAgentId}; ` +
164
+ `${failed.length} skill(s) failed.`);
165
+ if (result.actionsError) {
166
+ this.log(`The skills imported, but their actions could not be added: ${result.actionsError.message}`);
167
+ }
168
+ }
169
+ // Partial success is normal and reported above; exit non-zero only when
170
+ // something the caller asked for did not happen.
171
+ if (failed.length > 0 || result.actionsError)
172
+ this.exit(1);
173
+ }
174
+ }
175
+ exports.default = SkillsImportAsActions;
@@ -10,5 +10,7 @@ export default class SkillsInstall extends BaseCommand {
10
10
  agent: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
11
  service: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
12
12
  };
13
+ /** A store 404 for a name that may be a skill on the caller's machine. */
14
+ private failOnStoreMiss;
13
15
  run(): Promise<void>;
14
16
  }
@@ -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 local_skills_1 = require("../../lib/local-skills");
6
7
  class SkillsInstall extends base_command_1.BaseCommand {
7
8
  static description = 'Install a skill from the store to a service (agent)';
8
9
  static examples = [
@@ -25,6 +26,19 @@ class SkillsInstall extends base_command_1.BaseCommand {
25
26
  hidden: true,
26
27
  }),
27
28
  };
29
+ /** A store 404 for a name that may be a skill on the caller's machine. */
30
+ async failOnStoreMiss(err, id) {
31
+ if (err?.status === 404) {
32
+ this.failWithCliError({
33
+ message: (0, local_skills_1.describeStoreSkillMiss)(id, await (0, local_skills_1.findLocalSkillsNamed)(id), 'install'),
34
+ code: 'NOT_FOUND',
35
+ status: 404,
36
+ exit: 1,
37
+ retryable: false,
38
+ });
39
+ }
40
+ this.handleApiError(err);
41
+ }
28
42
  async run() {
29
43
  this.requireAuth();
30
44
  const { args, flags } = await this.parse(SkillsInstall);
@@ -33,6 +47,15 @@ class SkillsInstall extends base_command_1.BaseCommand {
33
47
  process.stderr.write('[skrr] --service is deprecated for `skills install`; use --agent instead.\n');
34
48
  }
35
49
  const targetAgentId = flags.agent ?? flags.service ?? null;
50
+ // A path is never a store id: say so before asking the store (OSK-9412).
51
+ if ((0, local_skills_1.looksLikeSkillPath)(args.id)) {
52
+ this.failWithCliError({
53
+ message: (0, local_skills_1.describeStoreSkillMiss)(args.id, [], 'install'),
54
+ code: 'STORE_SKILL_ID_EXPECTED',
55
+ exit: 2,
56
+ retryable: false,
57
+ });
58
+ }
36
59
  let result;
37
60
  try {
38
61
  result = await data_provider_1.dataService.installSkill({
@@ -41,7 +64,7 @@ class SkillsInstall extends base_command_1.BaseCommand {
41
64
  });
42
65
  }
43
66
  catch (err) {
44
- this.handleApiError(err);
67
+ await this.failOnStoreMiss(err, args.id);
45
68
  }
46
69
  if (flags.json) {
47
70
  this.log(JSON.stringify(result, null, 2));
@@ -15,7 +15,7 @@ const format_1 = require("../../lib/format");
15
15
  * The latter is what a chat user actually sees.
16
16
  */
17
17
  class SkillsInvocable extends base_command_1.BaseCommand {
18
- static description = 'List skills callable via /skill-name (attached + accessible globals; broader than `agents skills list`)';
18
+ static description = 'List library skills callable via /skill-name (attached + accessible globals). Skills on your machine: `skrr skills local`';
19
19
  static examples = [
20
20
  '<%= config.bin %> skills invocable',
21
21
  '<%= config.bin %> skills invocable --agent <agent-id>',
@@ -51,7 +51,11 @@ class SkillsInvocable extends base_command_1.BaseCommand {
51
51
  const scope = flags.agent ? `agent ${flags.agent}` : 'your global scope';
52
52
  const attached = items.filter((s) => s.agentId != null).length;
53
53
  const globals = items.length - attached;
54
- this.log(`Invocable set for ${scope}: ${items.length} total (${attached} attached + ${globals} accessible globals).`);
54
+ this.log(`Invocable library skills for ${scope}: ${items.length} total (${attached} attached + ${globals} accessible globals).`);
55
+ // Two kinds of skill answer to `/name`, and this counts only one. Said on
56
+ // every run, not just at zero: a non-empty library list read as "all my
57
+ // skills" hides the other kind just as well (OSK-9478).
58
+ this.log('Skills in your machine’s .claude/skills and sibling roots are listed by `skrr skills local`.');
55
59
  if (items.length === 0)
56
60
  return;
57
61
  const rows = items.map((s) => ({
@@ -0,0 +1,40 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * The skills that are ON THIS MACHINE.
4
+ *
5
+ * Every other command under `skills` is about the STORE or a cloud scope —
6
+ * `browse`, `library`, `install`, `invocable`. Not one of them reads the
7
+ * filesystem, and the topic's own description ("Browse and install skills from
8
+ * the skill store") names the store, so the one topic named after the thing was
9
+ * about something else entirely. A machine with 79 discovered skills across
10
+ * seven roots could not show one line of them through `skrr`, and
11
+ * `skills invocable` — the command whose description promises breadth —
12
+ * answered `0 total` beside them.
13
+ *
14
+ * The inventory already existed and was already published: the daemon walks its
15
+ * roots at registration (`reportableSkills`), the row lands in
16
+ * `daemon:active:*`, and `GET /api/daemons/:id/skills` serves it. This reads
17
+ * that. Nothing new is collected.
18
+ *
19
+ * It is also the repo's own rule rather than a preference: "the CLI is how a
20
+ * headless operator and a locally-running coding agent touch the platform, so
21
+ * an endpoint the API exposes must be reachable from `skrr`."
22
+ *
23
+ * WHAT THIS IS NOT: the list a `/`-menu selection resolves against. That walk
24
+ * happens at session start from the SESSION's effective cwd, which may be a
25
+ * worktree or an ephemeral workspace; this one is the daemon's own cwd. They
26
+ * usually agree and are not required to, so the header says which machine and
27
+ * directory the answer is about rather than implying it is the only one.
28
+ */
29
+ export default class SkillsLocal extends BaseCommand {
30
+ static description: string;
31
+ static examples: string[];
32
+ static flags: {
33
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
34
+ quiet: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
35
+ daemon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
36
+ root: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
37
+ triggers: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
38
+ };
39
+ run(): Promise<void>;
40
+ }
@@ -0,0 +1,160 @@
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 format_1 = require("../../lib/format");
7
+ const local_skills_1 = require("../../lib/local-skills");
8
+ /**
9
+ * The skills that are ON THIS MACHINE.
10
+ *
11
+ * Every other command under `skills` is about the STORE or a cloud scope —
12
+ * `browse`, `library`, `install`, `invocable`. Not one of them reads the
13
+ * filesystem, and the topic's own description ("Browse and install skills from
14
+ * the skill store") names the store, so the one topic named after the thing was
15
+ * about something else entirely. A machine with 79 discovered skills across
16
+ * seven roots could not show one line of them through `skrr`, and
17
+ * `skills invocable` — the command whose description promises breadth —
18
+ * answered `0 total` beside them.
19
+ *
20
+ * The inventory already existed and was already published: the daemon walks its
21
+ * roots at registration (`reportableSkills`), the row lands in
22
+ * `daemon:active:*`, and `GET /api/daemons/:id/skills` serves it. This reads
23
+ * that. Nothing new is collected.
24
+ *
25
+ * It is also the repo's own rule rather than a preference: "the CLI is how a
26
+ * headless operator and a locally-running coding agent touch the platform, so
27
+ * an endpoint the API exposes must be reachable from `skrr`."
28
+ *
29
+ * WHAT THIS IS NOT: the list a `/`-menu selection resolves against. That walk
30
+ * happens at session start from the SESSION's effective cwd, which may be a
31
+ * worktree or an ephemeral workspace; this one is the daemon's own cwd. They
32
+ * usually agree and are not required to, so the header says which machine and
33
+ * directory the answer is about rather than implying it is the only one.
34
+ */
35
+ class SkillsLocal extends base_command_1.BaseCommand {
36
+ static description = 'List the skills discovered on a machine, from its daemon';
37
+ static examples = [
38
+ '<%= config.bin %> skills local',
39
+ '<%= config.bin %> skills local --daemon <daemon-id>',
40
+ '<%= config.bin %> skills local --root .claude/skills',
41
+ '<%= config.bin %> skills local --json',
42
+ ];
43
+ static flags = {
44
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
45
+ quiet: core_1.Flags.boolean({ description: 'Suppress non-essential output' }),
46
+ daemon: core_1.Flags.string({
47
+ description: 'Which machine to ask. Defaults to your only connected daemon.',
48
+ }),
49
+ root: core_1.Flags.string({
50
+ description: 'Only skills found under this convention root, e.g. .claude/skills',
51
+ }),
52
+ triggers: core_1.Flags.string({
53
+ description: 'Only skills with this trigger',
54
+ options: ['user', 'model'],
55
+ }),
56
+ };
57
+ async run() {
58
+ this.requireAuth();
59
+ const { flags } = await this.parse(SkillsLocal);
60
+ let daemonId = flags.daemon;
61
+ if (!daemonId) {
62
+ // Resolve rather than guess. Naming the ambiguity beats picking one of
63
+ // several machines and reporting its skills as "the" answer.
64
+ let daemons;
65
+ try {
66
+ daemons = await data_provider_1.dataService.getDaemons();
67
+ }
68
+ catch (err) {
69
+ this.handleApiError(err);
70
+ return;
71
+ }
72
+ const choice = (0, local_skills_1.chooseDaemon)(daemons.active ?? []);
73
+ if (!('daemonId' in choice)) {
74
+ // A usage error, on stderr: printed to stdout it was the whole output of
75
+ // `--json`, which a caller then failed to parse.
76
+ const listed = choice.candidates.map((d) => ` --daemon ${d.daemonId}${d.deviceName ? ` (${d.deviceName})` : ''}`);
77
+ this.error([choice.problem, ...listed].join('\n'), { exit: 2 });
78
+ }
79
+ daemonId = choice.daemonId;
80
+ }
81
+ let response;
82
+ try {
83
+ response = await data_provider_1.dataService.getDaemonSkills(daemonId);
84
+ }
85
+ catch (err) {
86
+ this.handleApiError(err);
87
+ return;
88
+ }
89
+ let skills = response.skills ?? [];
90
+ if (flags.root)
91
+ skills = skills.filter((s) => s.source === flags.root);
92
+ if (flags.triggers) {
93
+ const want = flags.triggers;
94
+ // A skill with no declared triggers is invocable both ways — that is the
95
+ // walker's own default when frontmatter is silent, not an absence.
96
+ skills = skills.filter((s) => want === 'user' ? (0, local_skills_1.isUserInvocable)(s) : !s.triggers || s.triggers.includes(want));
97
+ }
98
+ if (flags.json) {
99
+ this.log(JSON.stringify({
100
+ daemonId,
101
+ online: response.online,
102
+ version: response.version ?? null,
103
+ // An empty `data` from a daemon too old to look is not "no skills".
104
+ discoversConventions: response.version
105
+ ? !(0, local_skills_1.daemonPredates)(response.version, local_skills_1.SKILL_CONVENTION_DISCOVERY_SINCE)
106
+ : null,
107
+ data: skills,
108
+ }, null, 2));
109
+ return;
110
+ }
111
+ if (flags.quiet)
112
+ return;
113
+ if (skills.length === 0) {
114
+ // Three different states, and a bare "none" would collapse them.
115
+ if (!response.online) {
116
+ this.log(`${daemonId} is not connected, so its inventory may be out of date. None listed.`);
117
+ }
118
+ else if ((0, local_skills_1.daemonPredates)(response.version, local_skills_1.SKILL_CONVENTION_DISCOVERY_SINCE)) {
119
+ // Checked before the filter and "add a SKILL.md" branches: from a daemon
120
+ // this old, an empty list says nothing about what is on the machine, and
121
+ // telling the user to add files it cannot see sent them in a circle
122
+ // (OSK-9630 — 20 SKILL.md files on disk, "No skills discovered").
123
+ this.log(`No skills listed — but this daemon (${response.version}) cannot see them. ` +
124
+ `Discovery from .claude/skills, .agents/skills, .devin/skills, .windsurf/skills and ` +
125
+ `~/.claude/skills arrived in ${local_skills_1.SKILL_CONVENTION_DISCOVERY_SINCE}. Update the daemon ` +
126
+ `(one that came with the desktop app updates with the app), then run ` +
127
+ `\`${this.config.bin} daemon restart\`.`);
128
+ }
129
+ else if (flags.root || flags.triggers) {
130
+ this.log('No skills match that filter on this machine.');
131
+ }
132
+ else {
133
+ this.log('No skills discovered on this machine. Put a SKILL.md in one of the conventions ' +
134
+ '(.claude/skills, .agents/skills, .devin/skills, .windsurf/skills) and reconnect.');
135
+ }
136
+ return;
137
+ }
138
+ const rows = skills.map((s) => ({
139
+ name: String(s.name),
140
+ // Where it came from. Two skills of the same name in different roots are
141
+ // otherwise indistinguishable, which is the same gap the `/` menu had.
142
+ root: String(s.source ?? '-'),
143
+ scope: String(s.scope ?? '-'),
144
+ // `user` belongs in the `/` menu; `model` is the agent's to reach for.
145
+ triggers: (s.triggers ?? ['user', 'model']).join('+'),
146
+ description: String(s.description ?? ''),
147
+ }));
148
+ this.log(`${skills.length} skill${skills.length === 1 ? '' : 's'} on ${daemonId}` +
149
+ (response.deviceName ? ` (${response.deviceName})` : '') +
150
+ (response.online ? '' : ' — NOT CONNECTED, this inventory may be stale'));
151
+ (0, format_1.renderTable)(rows, [
152
+ { key: 'name', header: 'NAME' },
153
+ { key: 'root', header: 'ROOT' },
154
+ { key: 'scope', header: 'SCOPE' },
155
+ { key: 'triggers', header: 'TRIGGERS' },
156
+ { key: 'description', header: 'DESCRIPTION', maxWidth: 52 },
157
+ ], (line) => this.log(line));
158
+ }
159
+ }
160
+ exports.default = SkillsLocal;
@@ -2,9 +2,19 @@ import { BaseCommand } from '../../base-command';
2
2
  export default class SkillsSearch extends BaseCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
+ /**
6
+ * `skills search` and `search skills` are the SAME search, and both spellings
7
+ * stay. Neither said so, their one-liners differed, and only one carried short
8
+ * flags — so a reader picked one at random with no way to tell whether they had
9
+ * picked a deprecated spelling. Duplication that is deliberate should say so;
10
+ * duplication that is silent reads as a mistake either way.
11
+ */
12
+ static args: {
13
+ query: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
14
+ };
5
15
  static flags: {
6
16
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
- query: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ query: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
18
  category: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
19
  limit: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
10
20
  };
@@ -4,26 +4,47 @@ 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 search_query_1 = require("../../lib/search-query");
7
8
  class SkillsSearch extends base_command_1.BaseCommand {
8
- static description = 'Search skills in the store by keyword';
9
+ static description = 'Search skills in the skrr store by keyword (same as `search skills`)';
9
10
  static examples = [
10
- '<%= config.bin %> skills search --query "summarize"',
11
- '<%= config.bin %> skills search --query "image" --category creative',
12
- '<%= config.bin %> skills search --query "data" --limit 10 --json',
11
+ '<%= config.bin %> skills search summarize',
12
+ '<%= config.bin %> skills search image --category creative',
13
+ '<%= config.bin %> skills search data --limit 10 --json',
14
+ '<%= config.bin %> skills search --query summarize',
13
15
  ];
16
+ /**
17
+ * `skills search` and `search skills` are the SAME search, and both spellings
18
+ * stay. Neither said so, their one-liners differed, and only one carried short
19
+ * flags — so a reader picked one at random with no way to tell whether they had
20
+ * picked a deprecated spelling. Duplication that is deliberate should say so;
21
+ * duplication that is silent reads as a mistake either way.
22
+ */
23
+ static args = {
24
+ query: core_1.Args.string({
25
+ description: 'Search term (same value as --query; pass either, not both)',
26
+ required: false,
27
+ ignoreStdin: true,
28
+ }),
29
+ };
14
30
  static flags = {
15
31
  json: core_1.Flags.boolean({ description: 'Output as JSON' }),
16
- query: core_1.Flags.string({ description: 'Search query', required: true }),
32
+ // No longer `required` — the positional satisfies it, and keeping the flag
33
+ // means every existing script and doc line stays valid. Same rule
34
+ // `messages list` adopted after `command messages:list:<id> not found`
35
+ // read like the command did not exist.
36
+ query: core_1.Flags.string({ char: 'q', description: 'Search query' }),
17
37
  category: core_1.Flags.string({ description: 'Filter by category' }),
18
38
  limit: core_1.Flags.integer({ description: 'Maximum number of results', default: 20 }),
19
39
  };
20
40
  async run() {
21
41
  this.requireAuth();
22
- const { flags } = await this.parse(SkillsSearch);
42
+ const { args, flags } = await this.parse(SkillsSearch);
43
+ const query = (0, search_query_1.resolveSearchQuery)(this, args.query, flags.query, 'skills search');
23
44
  let response;
24
45
  try {
25
46
  response = await data_provider_1.dataService.getStoreSkills({
26
- q: flags.query,
47
+ q: query,
27
48
  category: flags.category,
28
49
  limit: flags.limit,
29
50
  });
@@ -38,7 +59,7 @@ class SkillsSearch extends base_command_1.BaseCommand {
38
59
  const r = response;
39
60
  const items = Array.isArray(r) ? r : (r?.data ?? []);
40
61
  if (items.length === 0) {
41
- this.log(`No skills found matching '${flags.query}'.`);
62
+ this.log(`No skills found matching '${query}'.`);
42
63
  return;
43
64
  }
44
65
  const rows = items.map((s) => ({