@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
@@ -0,0 +1,22 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ /**
3
+ * Edit one of the caller's own categories. Wraps `PATCH /api/agents/categories/:value`.
4
+ *
5
+ * `value` is the identity, not a field: agents point at it, so it is the ARG and
6
+ * cannot be changed here. Renaming means `--label`.
7
+ */
8
+ export default class AgentsCategoriesUpdate extends BaseCommand {
9
+ static description: string;
10
+ static examples: string[];
11
+ static args: {
12
+ value: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
13
+ };
14
+ static flags: {
15
+ label: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
16
+ description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
+ order: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
18
+ active: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
19
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
+ };
21
+ run(): Promise<void>;
22
+ }
@@ -0,0 +1,59 @@
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
+ * Edit one of the caller's own categories. Wraps `PATCH /api/agents/categories/:value`.
8
+ *
9
+ * `value` is the identity, not a field: agents point at it, so it is the ARG and
10
+ * cannot be changed here. Renaming means `--label`.
11
+ */
12
+ class AgentsCategoriesUpdate extends base_command_1.BaseCommand {
13
+ static description = 'Update a custom agent category';
14
+ static examples = [
15
+ '<%= config.bin %> agents categories update ops --label "Operations & on-call"',
16
+ '<%= config.bin %> agents categories update ops --no-active',
17
+ ];
18
+ static args = {
19
+ value: core_1.Args.string({ description: 'Category value', required: true, ignoreStdin: true }),
20
+ };
21
+ static flags = {
22
+ label: core_1.Flags.string({ description: 'New display name' }),
23
+ description: core_1.Flags.string({ description: 'New description' }),
24
+ order: core_1.Flags.integer({ description: 'New sort position' }),
25
+ active: core_1.Flags.boolean({
26
+ description: 'Whether the category is offered when choosing one',
27
+ allowNo: true,
28
+ }),
29
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
30
+ };
31
+ async run() {
32
+ this.requireAuth();
33
+ const { args, flags } = await this.parse(AgentsCategoriesUpdate);
34
+ const patch = {
35
+ ...(flags.label === undefined ? {} : { label: flags.label }),
36
+ ...(flags.description === undefined ? {} : { description: flags.description }),
37
+ ...(flags.order === undefined ? {} : { order: flags.order }),
38
+ ...(flags.active === undefined ? {} : { isActive: flags.active }),
39
+ };
40
+ if (Object.keys(patch).length === 0) {
41
+ this.error('Nothing to update. Pass at least one of --label, --description, --order, --active.', {
42
+ exit: 1,
43
+ });
44
+ }
45
+ let updated;
46
+ try {
47
+ updated = await data_provider_1.dataService.updateUserCategory(args.value, patch);
48
+ }
49
+ catch (err) {
50
+ this.handleApiError(err);
51
+ }
52
+ if (flags.json) {
53
+ this.log(JSON.stringify(updated, null, 2));
54
+ return;
55
+ }
56
+ this.log(`Updated category ${args.value}`);
57
+ }
58
+ }
59
+ exports.default = AgentsCategoriesUpdate;
@@ -24,6 +24,18 @@ export declare const DETACH_EXIT_CODE = 130;
24
24
  * answers true.
25
25
  */
26
26
  export declare const STREAM_LOST_EXIT_CODE = 75;
27
+ /**
28
+ * Exit code for a streamed run that reached its terminal state: 1 when it
29
+ * failed, 0 otherwise.
30
+ *
31
+ * The streaming modes share this line. `--jsonl` used to print `run.result
32
+ * {status: "failed"}` and exit 0 while the human mode exited 1 for the same run
33
+ * — and `--jsonl` is the mode a script branches on (OSK-9779). Empty text is not
34
+ * a failure here, unlike `--no-stream`: a turn that only ran tools is a success.
35
+ */
36
+ export declare function streamedResultExitCode(result: {
37
+ status?: string;
38
+ }): number;
27
39
  /**
28
40
  * What to say when the user pressed Ctrl-C and the run did not stop.
29
41
  *
@@ -124,6 +136,8 @@ export default class AgentsChat extends BaseCommand {
124
136
  jsonl: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
125
137
  json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
126
138
  'approve-tools': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
139
+ 'local-skill': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
140
+ daemon: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
127
141
  task: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
128
142
  };
129
143
  /**
@@ -138,5 +152,12 @@ export default class AgentsChat extends BaseCommand {
138
152
  * mid-run costs a session.
139
153
  */
140
154
  private static readonly TASK_REF_IN_PROMPT;
155
+ /**
156
+ * `--local-skill` names → the references the server resolves, from the daemon
157
+ * that will run the turn. Any name that does not resolve stops the command:
158
+ * the server fails a turn whose picked skill did not load, so sending it
159
+ * would only move the same error later (OSK-9478).
160
+ */
161
+ private resolveLocalSkills;
141
162
  run(): Promise<void>;
142
163
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.STREAM_LOST_EXIT_CODE = exports.DETACH_EXIT_CODE = void 0;
4
+ exports.streamedResultExitCode = streamedResultExitCode;
4
5
  exports.interruptedDetachMessage = interruptedDetachMessage;
5
6
  exports.reconcileTerminalFromMessages = reconcileTerminalFromMessages;
6
7
  exports.inspectTurnCommand = inspectTurnCommand;
@@ -13,6 +14,7 @@ const data_provider_1 = require("@skrr-ai/data-provider");
13
14
  const base_command_1 = require("../../base-command");
14
15
  const agentic_stream_1 = require("../../lib/agentic-stream");
15
16
  const web_url_1 = require("../../lib/web-url");
17
+ const local_skills_1 = require("../../lib/local-skills");
16
18
  /**
17
19
  * Exit code for a run the USER stopped watching, by pressing Ctrl-C.
18
20
  *
@@ -37,6 +39,18 @@ exports.DETACH_EXIT_CODE = 130;
37
39
  * answers true.
38
40
  */
39
41
  exports.STREAM_LOST_EXIT_CODE = 75;
42
+ /**
43
+ * Exit code for a streamed run that reached its terminal state: 1 when it
44
+ * failed, 0 otherwise.
45
+ *
46
+ * The streaming modes share this line. `--jsonl` used to print `run.result
47
+ * {status: "failed"}` and exit 0 while the human mode exited 1 for the same run
48
+ * — and `--jsonl` is the mode a script branches on (OSK-9779). Empty text is not
49
+ * a failure here, unlike `--no-stream`: a turn that only ran tools is a success.
50
+ */
51
+ function streamedResultExitCode(result) {
52
+ return result.status === 'failed' ? 1 : 0;
53
+ }
40
54
  /**
41
55
  * What to say when the user pressed Ctrl-C and the run did not stop.
42
56
  *
@@ -84,18 +98,17 @@ function reconcileTerminalFromMessages(messages, responseMessageId) {
84
98
  [...messages].reverse().find((m) => m && m.isCreatedByUser === false);
85
99
  if (!row)
86
100
  return null;
87
- const agentic = row.metadata?.agentic;
88
- const recordedError = typeof agentic?.error === 'string' ? agentic.error : undefined;
89
- const text = typeof row.text === 'string' ? row.text : '';
90
- if (row.error === true) {
101
+ const failure = (0, data_provider_1.resolveMessageFailure)(row);
102
+ if (failure) {
91
103
  return {
92
104
  status: 'failed',
93
- ...(text ? { text } : {}),
105
+ ...(failure.answer ? { text: failure.answer } : {}),
94
106
  // The reason exists on the row; it simply never reached the surface. Say
95
107
  // it, rather than the transport error that masked it (OSK-7595).
96
- error: recordedError ?? 'The run failed. No reason was recorded on the message.',
108
+ error: failure.reason ?? 'The run failed. No reason was recorded on the message.',
97
109
  };
98
110
  }
111
+ const text = typeof row.text === 'string' ? row.text : '';
99
112
  // `unfinished: false` is the persister's terminal marker; an empty body with
100
113
  // it set is a turn that ended having produced nothing, which is still
101
114
  // terminal and still better reported than waited on.
@@ -183,6 +196,7 @@ class AgentsChat extends base_command_1.BaseCommand {
183
196
  '<%= config.bin %> agents chat <agent-id> --prompt "Deploy the fix" --approve-tools',
184
197
  '<%= config.bin %> agents chat <agent-id> --prompt "Summarize" --jsonl',
185
198
  '<%= config.bin %> agents chat <agent-id> --prompt "Summarize" --no-stream --json',
199
+ '<%= config.bin %> agents chat <agent-id> --prompt "Review this diff" --local-skill code-review',
186
200
  ];
187
201
  static args = {
188
202
  agentId: core_1.Args.string({ description: 'Agent ID', required: true, ignoreStdin: true }),
@@ -222,6 +236,16 @@ class AgentsChat extends base_command_1.BaseCommand {
222
236
  'approve-tools': core_1.Flags.boolean({
223
237
  description: 'Prompt interactively before approving tool calls',
224
238
  }),
239
+ 'local-skill': core_1.Flags.string({
240
+ description: 'Invoke a skill on your machine on this turn, as `skrr skills local` lists it: its ' +
241
+ 'name, or <root>/<name> when two roots share one. The turn runs on that machine. ' +
242
+ 'Repeatable.',
243
+ multiple: true,
244
+ }),
245
+ daemon: core_1.Flags.string({
246
+ description: 'The machine whose skills --local-skill names. Defaults to your only connected daemon.',
247
+ dependsOn: ['local-skill'],
248
+ }),
225
249
  task: core_1.Flags.string({
226
250
  description: 'Bind this turn to a task (UUID or OSK-####). Injects the canonical task id, ' +
227
251
  'identifier, space and completion instructions into the turn. This is a CHAT ' +
@@ -241,6 +265,49 @@ class AgentsChat extends base_command_1.BaseCommand {
241
265
  * mid-run costs a session.
242
266
  */
243
267
  static TASK_REF_IN_PROMPT = /\b(?:OSK-\d+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b/;
268
+ /**
269
+ * `--local-skill` names → the references the server resolves, from the daemon
270
+ * that will run the turn. Any name that does not resolve stops the command:
271
+ * the server fails a turn whose picked skill did not load, so sending it
272
+ * would only move the same error later (OSK-9478).
273
+ */
274
+ async resolveLocalSkills(requested, daemonFlag) {
275
+ if (!requested?.length)
276
+ return null;
277
+ let daemonId = daemonFlag;
278
+ if (!daemonId) {
279
+ let daemons;
280
+ try {
281
+ daemons = await data_provider_1.dataService.getDaemons();
282
+ }
283
+ catch (err) {
284
+ this.handleApiError(err);
285
+ }
286
+ const choice = (0, local_skills_1.chooseDaemon)(daemons.active ?? []);
287
+ if (!('daemonId' in choice)) {
288
+ const listed = choice.candidates.map((d) => ` --daemon ${d.daemonId}${d.deviceName ? ` (${d.deviceName})` : ''}`);
289
+ this.error([choice.problem, ...listed].join('\n'), { exit: 2 });
290
+ }
291
+ daemonId = choice.daemonId;
292
+ }
293
+ let inventory;
294
+ try {
295
+ inventory = await data_provider_1.dataService.getDaemonSkills(daemonId);
296
+ }
297
+ catch (err) {
298
+ this.handleApiError(err);
299
+ }
300
+ if (!inventory.online) {
301
+ this.error(`${daemonId} is not connected, so no skill on it can load. Start it and retry.`, {
302
+ exit: 2,
303
+ });
304
+ }
305
+ const { refs, problems } = (0, local_skills_1.resolveLocalSkillRefs)(inventory.skills ?? [], requested);
306
+ if (problems.length > 0) {
307
+ this.error(problems.join('\n'), { exit: 2 });
308
+ }
309
+ return { daemonId, refs };
310
+ }
244
311
  async run() {
245
312
  this.requireAuth();
246
313
  const { args, flags } = await this.parse(AgentsChat);
@@ -258,6 +325,10 @@ class AgentsChat extends base_command_1.BaseCommand {
258
325
  'response and streams no events. Use --quick --json for a machine-readable ' +
259
326
  'one-shot, or drop --quick for a real streamed turn.', { exit: 2 });
260
327
  }
328
+ if (flags.quick && flags['local-skill']?.length) {
329
+ this.error('--local-skill has no meaning with --quick: the persona-only summarizer runs no ' +
330
+ 'runtime, so no skill on your machine can load. Drop --quick for a real turn.', { exit: 2 });
331
+ }
261
332
  if (flags['approve-tools'] && !process.stdin.isTTY) {
262
333
  this.error('--approve-tools requires an interactive terminal.', { exit: 2 });
263
334
  }
@@ -371,13 +442,28 @@ class AgentsChat extends base_command_1.BaseCommand {
371
442
  const contextParts = [taskContextBlock, flags.context ? `Context: ${flags.context}` : null]
372
443
  .filter(Boolean)
373
444
  .join('\n\n');
445
+ const localSkills = await this.resolveLocalSkills(flags['local-skill'], flags.daemon);
446
+ const prompt = localSkills
447
+ ? (0, local_skills_1.withSkillInvocations)(flags.prompt, localSkills.refs)
448
+ : flags.prompt;
374
449
  let started;
375
450
  try {
376
451
  started = await data_provider_1.dataService.startAgenticChat({
377
452
  agentId: args.agentId,
378
- text: contextParts ? `${contextParts}\n\n${flags.prompt}` : flags.prompt,
453
+ text: contextParts ? `${contextParts}\n\n${prompt}` : prompt,
379
454
  conversationId: threadConversationId,
380
455
  workspaceId: process.env.OVERSKY_WORKSPACE_ID,
456
+ // The server resolves each ref against the session's daemon, so the
457
+ // turn is asked to run on the machine that listed them. An agent whose
458
+ // execution policy places it elsewhere keeps that placement, and the
459
+ // run fails saying why rather than running without the skill.
460
+ ...(localSkills
461
+ ? {
462
+ skillRefs: localSkills.refs,
463
+ executionEnvironment: 'local',
464
+ preferredDaemonId: localSkills.daemonId,
465
+ }
466
+ : {}),
381
467
  });
382
468
  }
383
469
  catch (err) {
@@ -573,6 +659,7 @@ class AgentsChat extends base_command_1.BaseCommand {
573
659
  // makes shell consumers able to find the final text without replaying
574
660
  // the event reducer.
575
661
  (0, agentic_stream_1.writeJsonLine)(process.stdout, { type: 'run.result', ...result });
662
+ process.exitCode = streamedResultExitCode(result);
576
663
  }
577
664
  else if (quiet && flags.json) {
578
665
  // A real executed turn — the metadata says so, unlike `--quick`.
@@ -104,6 +104,16 @@ export default class AgentsCreate extends BaseCommand {
104
104
  'hide-sequential-outputs': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
105
105
  'is-collaborative': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
106
106
  'recursion-limit': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
107
+ avatar: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
108
+ 'conversation-starter': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
109
+ 'todo-working-hours': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
110
+ 'reasoning-tool-escape': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
111
+ 'commitment-responsibility': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
112
+ 'commitment-responsibility-ceiling': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
113
+ 'max-turns': import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
114
+ 'tool-resources': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
115
+ 'install-channel': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
116
+ 'auto-minor-updates': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
107
117
  };
108
118
  run(): Promise<void>;
109
119
  }
@@ -6,6 +6,7 @@ exports.unappliedPayloadKeys = unappliedPayloadKeys;
6
6
  exports.backgroundLoopLines = backgroundLoopLines;
7
7
  const core_1 = require("@oclif/core");
8
8
  const data_provider_1 = require("@skrr-ai/data-provider");
9
+ const agent_visual_refs_1 = require("../../lib/agent-visual-refs");
9
10
  const base_command_1 = require("../../base-command");
10
11
  const execution_target_1 = require("../../lib/execution-target");
11
12
  const prompt_1 = require("../../lib/prompt");
@@ -157,7 +158,10 @@ class AgentsCreate extends base_command_1.BaseCommand {
157
158
  instructions: core_1.Flags.string({
158
159
  description: 'Initial raw custom instructions (creates one inline block; use `agents instructions` to compose reusable blocks later)',
159
160
  }),
160
- category: core_1.Flags.string({ description: 'Agent category' }),
161
+ category: core_1.Flags.string({
162
+ description: 'Agent category. `skrr agents categories` lists what this account accepts, and ' +
163
+ '`skrr agents categories create` adds one.',
164
+ }),
161
165
  target: core_1.Flags.string({
162
166
  description: 'Required execution target. Use a Harness id, Hosted Machine session, or Agent Worker. ' +
163
167
  'Use hosted-machine, sbs_..., agent-worker, or a connected Harness id. ' +
@@ -192,7 +196,7 @@ class AgentsCreate extends base_command_1.BaseCommand {
192
196
  'network-agent-ids': core_1.Flags.string({ description: 'Network agent IDs JSON array' }),
193
197
  'network-include-public': core_1.Flags.boolean({ description: 'Include public agents in network' }),
194
198
  'character-3d-id': core_1.Flags.string({ description: '3D character ID' }),
195
- 'scene-background': core_1.Flags.string({ description: 'Scene background' }),
199
+ 'scene-background': core_1.Flags.string({ description: agent_visual_refs_1.SCENE_BACKGROUND_FLAG_HELP }),
196
200
  'tone-mode': core_1.Flags.string({ description: 'Tone mode' }),
197
201
  'tone-id': core_1.Flags.string({ description: 'Tone ID' }),
198
202
  'tone-notes': core_1.Flags.string({ description: 'Per-agent tone notes' }),
@@ -209,6 +213,45 @@ class AgentsCreate extends base_command_1.BaseCommand {
209
213
  'hide-sequential-outputs': core_1.Flags.boolean({ description: 'Hide sequential outputs' }),
210
214
  'is-collaborative': core_1.Flags.boolean({ description: 'Enable collaboration' }),
211
215
  'recursion-limit': core_1.Flags.integer({ description: 'Agent recursion limit' }),
216
+ avatar: core_1.Flags.string({
217
+ description: "The agent's face, as a reference rather than a file: default, preset:<id> " +
218
+ '(`skrr agents avatar presets`), asset:<id> (`skrr agents avatar library`), or ' +
219
+ 'image:<filepath>@<source>. To upload a new image use `skrr agents avatar upload`.',
220
+ }),
221
+ 'conversation-starter': core_1.Flags.string({
222
+ description: 'Suggested opening prompt shown on the agent (repeatable; replaces the list)',
223
+ multiple: true,
224
+ }),
225
+ 'todo-working-hours': core_1.Flags.string({
226
+ description: 'When this agent schedules its own work: HH:MM-HH:MM[@<IANA timezone>], e.g. ' +
227
+ '09:00-18:00@America/Los_Angeles',
228
+ }),
229
+ 'reasoning-tool-escape': core_1.Flags.string({
230
+ description: 'Tool a reasoning-only turn may still use (repeatable; replaces the list). ' +
231
+ 'These are ESCAPES, not a fenced tool surface.',
232
+ options: [...agent_config_1.REASONING_TOOL_ESCAPES],
233
+ multiple: true,
234
+ }),
235
+ 'commitment-responsibility': core_1.Flags.string({
236
+ description: "Default work authority for this agent's commitments",
237
+ options: [...agent_config_1.COMMITMENT_RESPONSIBILITY_LEVELS],
238
+ }),
239
+ 'commitment-responsibility-ceiling': core_1.Flags.string({
240
+ description: 'Ceiling a commitment may not exceed, whatever it asks for',
241
+ options: [...agent_config_1.COMMITMENT_RESPONSIBILITY_LEVELS],
242
+ }),
243
+ 'max-turns': core_1.Flags.integer({ description: 'Maximum turns in one agent run (1-500)' }),
244
+ 'tool-resources': core_1.Flags.string({
245
+ description: 'Tool resources JSON object (file_search / context / image_edit bindings)',
246
+ }),
247
+ 'install-channel': core_1.Flags.string({
248
+ description: 'Release policy: which channel installs of this agent follow',
249
+ options: [...agent_config_1.RELEASE_INSTALL_CHANNELS],
250
+ }),
251
+ 'auto-minor-updates': core_1.Flags.boolean({
252
+ description: 'Release policy: allow installs to take minor updates automatically',
253
+ allowNo: true,
254
+ }),
212
255
  };
213
256
  async run() {
214
257
  this.requireAuth();
@@ -275,7 +318,16 @@ class AgentsCreate extends base_command_1.BaseCommand {
275
318
  // server seeds the full portfolio exactly as it always has.
276
319
  relationshipLoops: flags['no-relationship-loops'] ? false : undefined,
277
320
  });
278
- payload = (0, agent_config_1.mergeAgentConfigFlags)(payload, flags);
321
+ // `mergeAgentConfigFlags` parses the typed flags (avatar, scene background,
322
+ // working hours, every JSON flag). A parse failure is the caller's input, so
323
+ // it is reported as a CLI error with the accepted forms — not as an unhandled
324
+ // throw, and not as a 400 from the server naming a zod path.
325
+ try {
326
+ payload = (0, agent_config_1.mergeAgentConfigFlags)(payload, flags);
327
+ }
328
+ catch (err) {
329
+ this.error(err.message, { exit: 1 });
330
+ }
279
331
  // agentCreateSchema (packages/api/src/agents/validation.ts) requires
280
332
  // provider and model, and a nameless agent is unusable (see
281
333
  // agentCreateMissingFields). We validate client-side so users get a clearer
@@ -330,6 +382,15 @@ class AgentsCreate extends base_command_1.BaseCommand {
330
382
  if (appliedDefaults.length > 0) {
331
383
  this.log(`Defaults applied: ${appliedDefaults.join(', ')}`);
332
384
  }
385
+ // The face is a default too, and the one people most often notice later:
386
+ // eight agents created in a row all came out faceless, nothing said a policy
387
+ // had decided that, and the natural conclusion was that the random default
388
+ // did not work. When `--avatar` was not given, say what the agent got and
389
+ // what decided it.
390
+ if (!flags.avatar) {
391
+ this.log(`Avatar: ${(0, agent_visual_refs_1.agentAvatarLine)(a.avatar)}`);
392
+ this.log(' Decided by your default-avatar policy — `skrr agents avatar default` shows or changes it.');
393
+ }
333
394
  for (const line of backgroundLoopLines(agentId, flags['no-relationship-loops'] === true)) {
334
395
  this.log(line);
335
396
  }
@@ -0,0 +1,27 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * The agent a harness gets when nobody has configured one.
4
+ *
5
+ * Wraps `POST /api/agents/default`, the path a `skrr code` session takes on an
6
+ * unconfigured account. It is IDEMPOTENT — it returns the existing default
7
+ * rather than minting a second one — which is what makes it safe in a
8
+ * first-run script where `agents create` would not be.
9
+ *
10
+ * Deliberately a separate command from `agents create`: this one asks the server
11
+ * to CHOOSE (provider, model, placement, name), and `create` is where the caller
12
+ * chooses. Collapsing them would make `create` sometimes-not-create.
13
+ *
14
+ * `lib/first-party-harness-agent.ts` calls the same endpoint through its own
15
+ * private helper and keeps doing so: that path takes an `AbortSignal` and treats
16
+ * an abort as distinct from a refusal, which `dataService.ensureDefaultAgent`
17
+ * cannot express. Two call sites, one endpoint, for a stated reason — not drift.
18
+ */
19
+ export default class AgentsEnsureDefault extends BaseCommand {
20
+ static description: string;
21
+ static examples: string[];
22
+ static flags: {
23
+ harness: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
25
+ };
26
+ run(): Promise<void>;
27
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const auth_core_1 = require("@skrr-ai/auth-core");
5
+ const data_provider_1 = require("@skrr-ai/data-provider");
6
+ const base_command_1 = require("../../base-command");
7
+ const web_url_1 = require("../../lib/web-url");
8
+ /**
9
+ * The agent a harness gets when nobody has configured one.
10
+ *
11
+ * Wraps `POST /api/agents/default`, the path a `skrr code` session takes on an
12
+ * unconfigured account. It is IDEMPOTENT — it returns the existing default
13
+ * rather than minting a second one — which is what makes it safe in a
14
+ * first-run script where `agents create` would not be.
15
+ *
16
+ * Deliberately a separate command from `agents create`: this one asks the server
17
+ * to CHOOSE (provider, model, placement, name), and `create` is where the caller
18
+ * chooses. Collapsing them would make `create` sometimes-not-create.
19
+ *
20
+ * `lib/first-party-harness-agent.ts` calls the same endpoint through its own
21
+ * private helper and keeps doing so: that path takes an `AbortSignal` and treats
22
+ * an abort as distinct from a refusal, which `dataService.ensureDefaultAgent`
23
+ * cannot express. Two call sites, one endpoint, for a stated reason — not drift.
24
+ */
25
+ class AgentsEnsureDefault extends base_command_1.BaseCommand {
26
+ static description = "Return this account's default agent for a harness, creating it if there isn't one";
27
+ static examples = [
28
+ '<%= config.bin %> agents ensure-default',
29
+ '<%= config.bin %> agents ensure-default --harness <harness-id> --json',
30
+ ];
31
+ static flags = {
32
+ harness: core_1.Flags.string({
33
+ // Only a harness with a managed-inference capability can own a default
34
+ // agent, and today exactly one does. Defaulted rather than required
35
+ // because the bare call is otherwise refused with a message that quotes
36
+ // the literal string "undefined" — accurate about the body, useless about
37
+ // the fix. Read from FIRST_PARTY_HARNESS, never written as a literal.
38
+ description: `Harness the default belongs to (default: ${auth_core_1.FIRST_PARTY_HARNESS.provider})`,
39
+ default: auth_core_1.FIRST_PARTY_HARNESS.provider,
40
+ }),
41
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
42
+ };
43
+ async run() {
44
+ this.requireAuth();
45
+ const { flags } = await this.parse(AgentsEnsureDefault);
46
+ let result;
47
+ try {
48
+ result = await data_provider_1.dataService.ensureDefaultAgent({ harness: flags.harness });
49
+ }
50
+ catch (err) {
51
+ this.handleApiError(err);
52
+ }
53
+ const agent = result.agent;
54
+ if (flags.json) {
55
+ this.log(JSON.stringify({ created: result.created, agent: (0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, agent) }, null, 2));
56
+ return;
57
+ }
58
+ const agentId = String(agent.id ?? agent._id ?? '?');
59
+ this.log(result.created
60
+ ? `Created default agent ${agentId} — ${agent.name ?? '(no name)'}`
61
+ : `Default agent already exists: ${agentId} — ${agent.name ?? '(no name)'}`);
62
+ this.log(`URL: ${(0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, agent).url ?? '-'}`);
63
+ }
64
+ }
65
+ exports.default = AgentsEnsureDefault;
@@ -7,6 +7,21 @@ import { BaseCommand } from '../../base-command';
7
7
  * arrives populated instead of scalar would otherwise print `[object Object]`
8
8
  * (OSK-2044), and a missing one would print the literal `undefined`.
9
9
  */
10
+ /**
11
+ * Pinned agents first, as the web sidebar orders them — the rest in the order
12
+ * the server returned.
13
+ *
14
+ * `skrr agents pin` says it pins an agent "to the top of your list", and this
15
+ * list never read pins: an agent sat at row 17 of 200 pinned or not, and nothing
16
+ * in `agents list` or `agents show` said it was pinned at all. The only way to
17
+ * see the effect of the command was `agents preferences show`, which omits the
18
+ * field entirely until the first pin.
19
+ */
20
+ export declare function orderPinnedFirst<T extends Record<string, unknown>>(items: readonly T[], preferences: Readonly<Record<string, {
21
+ isPinned?: boolean;
22
+ } | undefined>>): Array<T & {
23
+ pinned: boolean;
24
+ }>;
10
25
  export declare function agentRow(a: Record<string, unknown>): {
11
26
  id: string;
12
27
  name: string;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.orderPinnedFirst = orderPinnedFirst;
3
4
  exports.agentRow = agentRow;
4
5
  exports.noAgentsEmptyMessage = noAgentsEmptyMessage;
5
6
  const core_1 = require("@oclif/core");
@@ -15,6 +16,25 @@ const web_url_1 = require("../../lib/web-url");
15
16
  * arrives populated instead of scalar would otherwise print `[object Object]`
16
17
  * (OSK-2044), and a missing one would print the literal `undefined`.
17
18
  */
19
+ /**
20
+ * Pinned agents first, as the web sidebar orders them — the rest in the order
21
+ * the server returned.
22
+ *
23
+ * `skrr agents pin` says it pins an agent "to the top of your list", and this
24
+ * list never read pins: an agent sat at row 17 of 200 pinned or not, and nothing
25
+ * in `agents list` or `agents show` said it was pinned at all. The only way to
26
+ * see the effect of the command was `agents preferences show`, which omits the
27
+ * field entirely until the first pin.
28
+ */
29
+ function orderPinnedFirst(items, preferences) {
30
+ return items
31
+ .map((item, index) => {
32
+ const id = String(item.id ?? item._id ?? '');
33
+ return { item: { ...item, pinned: Boolean(preferences[id]?.isPinned) }, index };
34
+ })
35
+ .sort((a, b) => Number(b.item.pinned) - Number(a.item.pinned) || a.index - b.index)
36
+ .map(({ item }) => item);
37
+ }
18
38
  function agentRow(a) {
19
39
  return {
20
40
  id: (0, format_1.formatCell)(a.id ?? a._id),
@@ -76,11 +96,21 @@ class AgentsList extends base_command_1.BaseCommand {
76
96
  this.log(noAgentsEmptyMessage(this.config.bin));
77
97
  return;
78
98
  }
79
- const rows = items.map((item) => ({
99
+ // Best-effort: a list that cannot read pins still lists, unordered by them.
100
+ let preferences = {};
101
+ try {
102
+ preferences = (await data_provider_1.dataService.getAllAgentPreferences())?.agentPreferences ?? {};
103
+ }
104
+ catch {
105
+ preferences = {};
106
+ }
107
+ const rows = orderPinnedFirst(items, preferences).map((item) => ({
108
+ pinned: item.pinned ? 'pinned' : '',
80
109
  ...agentRow(item),
81
110
  url: (0, web_url_1.agentUrlFrom)(this.cliConfig.baseURL, item) ?? '-',
82
111
  }));
83
112
  (0, format_1.renderTable)(rows, [
113
+ { key: 'pinned', header: 'PINNED' },
84
114
  { key: 'id', header: 'ID' },
85
115
  { key: 'name', header: 'NAME', maxWidth: 30 },
86
116
  { key: 'description', header: 'DESCRIPTION', maxWidth: 60 },
@@ -0,0 +1,16 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ /**
3
+ * Per-USER preference, not agent config: it changes your view of the agent and
4
+ * nobody else's. Idempotent over a toggle endpoint — see `lib/agent-pin-mute.ts`.
5
+ */
6
+ export default class AgentsMute extends BaseCommand {
7
+ static description: string;
8
+ static examples: string[];
9
+ static args: {
10
+ id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
11
+ };
12
+ static flags: {
13
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ };
15
+ run(): Promise<void>;
16
+ }