@skrr-ai/cli 0.1.40 → 0.1.41

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 (114) hide show
  1. package/dist/base-command.d.ts +9 -0
  2. package/dist/base-command.js +18 -3
  3. package/dist/commands/agent-shares/list-for.js +4 -11
  4. package/dist/commands/agent-shares/received.js +4 -11
  5. package/dist/commands/agent-shares/sent.js +4 -11
  6. package/dist/commands/agent-shares/with.js +3 -10
  7. package/dist/commands/agents/activity.js +1 -1
  8. package/dist/commands/agents/api-actions/add.js +6 -0
  9. package/dist/commands/agents/chat.js +6 -1
  10. package/dist/commands/agents/create.js +6 -1
  11. package/dist/commands/agents/manager/ensure.d.ts +18 -0
  12. package/dist/commands/agents/manager/ensure.js +56 -0
  13. package/dist/commands/agents/show.js +4 -0
  14. package/dist/commands/agents/tools/auth.d.ts +6 -0
  15. package/dist/commands/agents/tools/auth.js +27 -1
  16. package/dist/commands/agents/tools/index.js +11 -1
  17. package/dist/commands/agents/update.js +6 -1
  18. package/dist/commands/code/install.d.ts +4 -2
  19. package/dist/commands/code/install.js +12 -10
  20. package/dist/commands/convos/list.js +1 -3
  21. package/dist/commands/convos/show.js +4 -11
  22. package/dist/commands/daemon/index.js +3 -3
  23. package/dist/commands/daemon/install.js +4 -4
  24. package/dist/commands/daemon/login.js +1 -1
  25. package/dist/commands/daemon/logs.d.ts +3 -1
  26. package/dist/commands/daemon/logs.js +16 -1
  27. package/dist/commands/daemon/start.js +3 -3
  28. package/dist/commands/daemon/status.d.ts +9 -0
  29. package/dist/commands/daemon/status.js +22 -0
  30. package/dist/commands/dm/messages.js +1 -11
  31. package/dist/commands/followups/cancel.js +1 -1
  32. package/dist/commands/followups/resolve.js +1 -1
  33. package/dist/commands/followups/show.js +16 -0
  34. package/dist/commands/harnesses/forget.js +20 -3
  35. package/dist/commands/harnesses/install.js +18 -6
  36. package/dist/commands/harnesses/installers.d.ts +1 -1
  37. package/dist/commands/harnesses/installers.js +36 -12
  38. package/dist/commands/harnesses/list.d.ts +74 -2
  39. package/dist/commands/harnesses/list.js +231 -15
  40. package/dist/commands/harnesses/ping.d.ts +2 -0
  41. package/dist/commands/harnesses/ping.js +21 -0
  42. package/dist/commands/harnesses/show.d.ts +22 -0
  43. package/dist/commands/harnesses/show.js +116 -17
  44. package/dist/commands/harnesses/update.d.ts +8 -0
  45. package/dist/commands/harnesses/update.js +25 -1
  46. package/dist/commands/harnesses/usage.d.ts +2 -0
  47. package/dist/commands/harnesses/usage.js +7 -2
  48. package/dist/commands/instructions/status.js +13 -0
  49. package/dist/commands/instructions/update-target.d.ts +1 -0
  50. package/dist/commands/instructions/update-target.js +11 -3
  51. package/dist/commands/login.js +5 -5
  52. package/dist/commands/machines/list.js +8 -9
  53. package/dist/commands/machines/show.js +46 -17
  54. package/dist/commands/messages/show.js +3 -10
  55. package/dist/commands/shares/get.js +2 -9
  56. package/dist/commands/shares/list.js +1 -9
  57. package/dist/commands/shortcuts/show.js +4 -11
  58. package/dist/commands/skills/local.js +6 -0
  59. package/dist/commands/spaces/actions/run.js +3 -4
  60. package/dist/commands/spaces/briefs/get.js +2 -9
  61. package/dist/commands/spaces/briefs/list.js +1 -9
  62. package/dist/commands/spaces/conversations.js +1 -9
  63. package/dist/commands/spaces/heartbeats/list.js +1 -9
  64. package/dist/commands/spaces/heartbeats/status.js +2 -9
  65. package/dist/commands/tasks/activity.js +1 -10
  66. package/dist/commands/tasks/approvals/list.js +1 -9
  67. package/dist/commands/tasks/attachments/list.js +1 -9
  68. package/dist/commands/tasks/comments/list.js +1 -9
  69. package/dist/commands/tasks/dri-status.js +2 -9
  70. package/dist/commands/tasks/events/append.js +9 -7
  71. package/dist/commands/tasks/execution-timeline.js +1 -9
  72. package/dist/commands/tasks/monitor.js +1 -9
  73. package/dist/commands/tasks/result/submit.js +9 -0
  74. package/dist/commands/tasks/runs.js +1 -9
  75. package/dist/commands/tasks/show.js +5 -12
  76. package/dist/commands/token/list.d.ts +8 -0
  77. package/dist/commands/token/list.js +51 -6
  78. package/dist/help.js +8 -12
  79. package/dist/lib/agent-home-workspace.d.ts +19 -0
  80. package/dist/lib/agent-home-workspace.js +39 -0
  81. package/dist/lib/agent-resolver.js +2 -2
  82. package/dist/lib/agentic-stream.d.ts +22 -1
  83. package/dist/lib/agentic-stream.js +48 -7
  84. package/dist/lib/cli-installers.d.ts +84 -2
  85. package/dist/lib/cli-installers.js +146 -13
  86. package/dist/lib/command-miss.d.ts +22 -0
  87. package/dist/lib/command-miss.js +78 -0
  88. package/dist/lib/daemon-setup.js +2 -2
  89. package/dist/lib/daemon-target.d.ts +14 -0
  90. package/dist/lib/daemon-target.js +32 -0
  91. package/dist/lib/daemonBroker.js +1 -1
  92. package/dist/lib/daemonHandoff.js +1 -1
  93. package/dist/lib/exec-runtime-binary.js +2 -2
  94. package/dist/lib/followups.d.ts +10 -0
  95. package/dist/lib/followups.js +14 -1
  96. package/dist/lib/format.d.ts +11 -0
  97. package/dist/lib/format.js +21 -0
  98. package/dist/lib/harness-labels.d.ts +39 -0
  99. package/dist/lib/harness-labels.js +60 -0
  100. package/dist/lib/harnesses.d.ts +6 -0
  101. package/dist/lib/instruction-input.d.ts +13 -0
  102. package/dist/lib/instruction-input.js +20 -1
  103. package/dist/lib/local-skills.d.ts +17 -1
  104. package/dist/lib/local-skills.js +20 -2
  105. package/dist/lib/login.js +5 -5
  106. package/dist/lib/machines.d.ts +6 -0
  107. package/dist/lib/machines.js +68 -2
  108. package/dist/lib/runtime-tool-support.d.ts +34 -0
  109. package/dist/lib/runtime-tool-support.js +77 -0
  110. package/dist/lib/share-rows.d.ts +17 -0
  111. package/dist/lib/share-rows.js +35 -0
  112. package/dist/node_modules/@skrr-ai/data-provider/index.js +5029 -5007
  113. package/oclif.manifest.json +2689 -2584
  114. package/package.json +6 -3
@@ -338,6 +338,15 @@ export interface ParsedGlobals {
338
338
  workspace?: string;
339
339
  }
340
340
  export declare function parseGlobalFlags(argv: readonly string[]): ParsedGlobals;
341
+ /**
342
+ * The typed `code` and message an API refusal carried, read the way
343
+ * `handleApiError` reads them, for a command that answers one code itself
344
+ * before falling back to the uniform translation.
345
+ */
346
+ export declare function apiRefusal(err: unknown): {
347
+ code?: string;
348
+ message?: string;
349
+ };
341
350
  /**
342
351
  * Prefix a failure message with the resource it is about.
343
352
  *
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Flags = exports.BaseCommand = exports.resolveProfileFromArgv = void 0;
4
4
  exports.assigneePayloadNeedsResolution = assigneePayloadNeedsResolution;
5
5
  exports.parseGlobalFlags = parseGlobalFlags;
6
+ exports.apiRefusal = apiRefusal;
6
7
  exports.withSubject = withSubject;
7
8
  exports.describeHarnessUnavailable = describeHarnessUnavailable;
8
9
  exports.describeGitHubUnavailable = describeGitHubUnavailable;
@@ -309,7 +310,7 @@ class BaseCommand extends core_1.Command {
309
310
  // to log in again. Reachable in the ordinary way — a cold machine
310
311
  // running several skrr commands at once has every process brokering,
311
312
  // because none of them has a token yet.
312
- process.stderr.write('[skrr] The local skrr runtime is being rate-limited while brokering logins. ' +
313
+ process.stderr.write('[skrr] The skrr background service on this computer is being rate-limited while brokering logins. ' +
313
314
  'This is transient — retry in a few minutes, or run `skrr login` to sign in directly.\n');
314
315
  }
315
316
  else if (autoResult.outcome.reason === 'base_url_mismatch' &&
@@ -317,7 +318,7 @@ class BaseCommand extends core_1.Command {
317
318
  // The user is about to see "Not signed in" — give them the
318
319
  // exact fix. One stderr line so it doesn't pollute --json
319
320
  // consumers on stdout.
320
- process.stderr.write(`[skrr] Local skrr runtime is logged in to ${autoResult.outcome.daemonServerUrl}, ` +
321
+ process.stderr.write(`[skrr] The skrr background service on this computer is logged in to ${autoResult.outcome.daemonServerUrl}, ` +
321
322
  `but skrr is configured for ${this.cliConfig.baseURL}. ` +
322
323
  `Run \`skrr login --base-url ${autoResult.outcome.daemonServerUrl}\` to use the daemon.\n`);
323
324
  }
@@ -1355,6 +1356,20 @@ function stringProp(obj, key) {
1355
1356
  const value = obj?.[key];
1356
1357
  return typeof value === 'string' && value.trim() ? value.trim() : undefined;
1357
1358
  }
1359
+ /**
1360
+ * The typed `code` and message an API refusal carried, read the way
1361
+ * `handleApiError` reads them, for a command that answers one code itself
1362
+ * before falling back to the uniform translation.
1363
+ */
1364
+ function apiRefusal(err) {
1365
+ if (!(err instanceof Error))
1366
+ return {};
1367
+ const body = parseErrorBody(err.body);
1368
+ return {
1369
+ code: stringProp(body, 'code') || stringProp(body, 'errorType'),
1370
+ message: stringProp(body, 'message') || stringProp(body, 'error'),
1371
+ };
1372
+ }
1358
1373
  /**
1359
1374
  * Prefix a failure message with the resource it is about.
1360
1375
  *
@@ -1622,7 +1637,7 @@ function describeDaemonScopedCredential(bin, scope = 'daemon', source) {
1622
1637
  ? `The stored credential has ${scope === 'daemon-install' ? 'daemon-install' : 'daemon'} scope`
1623
1638
  : `This command received a ${scopeLabel} credential`;
1624
1639
  return (`${subject}, which cannot access user API commands. ` +
1625
- `Run \`${bin} login\` to create a CLI credential. For the local runtime itself, use \`${bin} daemon login\`.`);
1640
+ `Run \`${bin} login\` to create a CLI credential. For the background service on this computer, use \`${bin} daemon login\`.`);
1626
1641
  }
1627
1642
  /**
1628
1643
  * Did the server MEAN this 5xx, or did it fall over?
@@ -4,6 +4,7 @@ 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 share_rows_1 = require("../../lib/share-rows");
7
8
  class AgentSharesListFor extends base_command_1.BaseCommand {
8
9
  static description = 'List all users an agent has been shared with';
9
10
  static examples = [
@@ -37,10 +38,10 @@ class AgentSharesListFor extends base_command_1.BaseCommand {
37
38
  return;
38
39
  }
39
40
  const rows = items.map((s) => ({
40
- shareId: String(s.id ?? s._id ?? '-'),
41
- recipient: String(s.recipientId ?? s.recipient ?? s.to ?? '-'),
41
+ shareId: (0, share_rows_1.shareIdOf)(s),
42
+ recipient: (0, share_rows_1.sharePartyLabel)(s.recipient ?? s.recipientId ?? s.to),
42
43
  status: String(s.status ?? '-'),
43
- sharedAt: formatTime(s.createdAt ?? s.sharedAt),
44
+ sharedAt: (0, format_1.localTime)(s.createdAt ?? s.sharedAt),
44
45
  }));
45
46
  (0, format_1.renderTable)(rows, [
46
47
  { key: 'shareId', header: 'SHARE ID' },
@@ -56,11 +57,3 @@ class AgentSharesListFor extends base_command_1.BaseCommand {
56
57
  }
57
58
  }
58
59
  exports.default = AgentSharesListFor;
59
- function formatTime(value) {
60
- try {
61
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
62
- }
63
- catch {
64
- return String(value ?? '-');
65
- }
66
- }
@@ -4,6 +4,7 @@ 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 share_rows_1 = require("../../lib/share-rows");
7
8
  class AgentSharesReceived extends base_command_1.BaseCommand {
8
9
  static description = 'List agent shares received by the current user';
9
10
  static examples = [
@@ -44,12 +45,12 @@ class AgentSharesReceived extends base_command_1.BaseCommand {
44
45
  return;
45
46
  }
46
47
  const rows = items.map((s) => ({
47
- shareId: String(s.id ?? s._id ?? '-'),
48
+ shareId: (0, share_rows_1.shareIdOf)(s),
48
49
  agentId: String(s.agentId ?? '-'),
49
50
  agentName: String(s.agentName ?? s.agent?.name ?? '-'),
50
- from: String(s.senderId ?? s.from ?? s.owner ?? '-'),
51
+ from: (0, share_rows_1.sharePartyLabel)(s.owner ?? s.senderId ?? s.from),
51
52
  status: String(s.status ?? '-'),
52
- sharedAt: formatTime(s.createdAt ?? s.sharedAt),
53
+ sharedAt: (0, format_1.localTime)(s.createdAt ?? s.sharedAt),
53
54
  }));
54
55
  (0, format_1.renderTable)(rows, [
55
56
  { key: 'shareId', header: 'SHARE ID' },
@@ -67,11 +68,3 @@ class AgentSharesReceived extends base_command_1.BaseCommand {
67
68
  }
68
69
  }
69
70
  exports.default = AgentSharesReceived;
70
- function formatTime(value) {
71
- try {
72
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
73
- }
74
- catch {
75
- return String(value ?? '-');
76
- }
77
- }
@@ -4,6 +4,7 @@ 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 share_rows_1 = require("../../lib/share-rows");
7
8
  class AgentSharesSent extends base_command_1.BaseCommand {
8
9
  static description = 'List agent shares sent by the current user';
9
10
  static examples = [
@@ -41,12 +42,12 @@ class AgentSharesSent extends base_command_1.BaseCommand {
41
42
  return;
42
43
  }
43
44
  const rows = items.map((s) => ({
44
- shareId: String(s.id ?? s._id ?? '-'),
45
+ shareId: (0, share_rows_1.shareIdOf)(s),
45
46
  agentId: String(s.agentId ?? '-'),
46
47
  agentName: String(s.agentName ?? s.agent?.name ?? '-'),
47
- to: String(s.recipientId ?? s.to ?? s.recipient ?? '-'),
48
+ to: (0, share_rows_1.sharePartyLabel)(s.recipient ?? s.recipientId ?? s.to),
48
49
  status: String(s.status ?? '-'),
49
- sharedAt: formatTime(s.createdAt ?? s.sharedAt),
50
+ sharedAt: (0, format_1.localTime)(s.createdAt ?? s.sharedAt),
50
51
  }));
51
52
  (0, format_1.renderTable)(rows, [
52
53
  { key: 'shareId', header: 'SHARE ID' },
@@ -64,11 +65,3 @@ class AgentSharesSent extends base_command_1.BaseCommand {
64
65
  }
65
66
  }
66
67
  exports.default = AgentSharesSent;
67
- function formatTime(value) {
68
- try {
69
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
70
- }
71
- catch {
72
- return String(value ?? '-');
73
- }
74
- }
@@ -4,6 +4,7 @@ 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 share_rows_1 = require("../../lib/share-rows");
7
8
  class AgentSharesWith extends base_command_1.BaseCommand {
8
9
  static description = 'Show all agent shares with a specific user';
9
10
  static examples = [
@@ -39,11 +40,11 @@ class AgentSharesWith extends base_command_1.BaseCommand {
39
40
  return;
40
41
  }
41
42
  const toRows = (items) => items.map((s) => ({
42
- shareId: String(s.id ?? s._id ?? '-'),
43
+ shareId: (0, share_rows_1.shareIdOf)(s),
43
44
  agentId: String(s.agentId ?? '-'),
44
45
  agentName: String(s.agentName ?? s.agent?.name ?? '-'),
45
46
  status: String(s.status ?? '-'),
46
- sharedAt: formatTime(s.createdAt ?? s.sharedAt),
47
+ sharedAt: (0, format_1.localTime)(s.createdAt ?? s.sharedAt),
47
48
  }));
48
49
  const columns = [
49
50
  { key: 'shareId', header: 'SHARE ID' },
@@ -69,11 +70,3 @@ class AgentSharesWith extends base_command_1.BaseCommand {
69
70
  }
70
71
  }
71
72
  exports.default = AgentSharesWith;
72
- function formatTime(value) {
73
- try {
74
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
75
- }
76
- catch {
77
- return String(value ?? '-');
78
- }
79
- }
@@ -162,7 +162,7 @@ class AgentsActivity extends base_command_1.BaseCommand {
162
162
  }
163
163
  else {
164
164
  (0, format_1.renderTable)(entries.map((entry) => ({
165
- when: entry.at ? new Date(entry.at).toISOString().slice(0, 19).replace('T', ' ') : '-',
165
+ when: (0, format_1.localTime)(entry.at),
166
166
  kind: entry.kind,
167
167
  title: (0, format_1.truncate)(entry.title, 50),
168
168
  detail: (0, format_1.truncate)(entry.detail, 40),
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const core_1 = require("@oclif/core");
4
4
  const promises_1 = require("node:fs/promises");
5
5
  const data_provider_1 = require("@skrr-ai/data-provider");
6
+ const runtime_tool_support_1 = require("../../../lib/runtime-tool-support");
6
7
  const base_command_1 = require("../../../base-command");
7
8
  /**
8
9
  * Attach (or re-attach) an OpenAPI document to an agent as a tool surface.
@@ -199,6 +200,11 @@ class AgentsApiActionsAdd extends base_command_1.BaseCommand {
199
200
  }
200
201
  this.log(`${flags['action-id'] ? 'Updated' : 'Added'} an OpenAPI action on agent ${args.agentId} — ` +
201
202
  `${functions.length} operation(s) on ${domain}`);
203
+ const actionId = result[1]?.action_id;
204
+ if (flags.auth === data_provider_1.AuthTypeEnum.OAuth && actionId) {
205
+ const redirectUrl = new URL(`/api/actions/${encodeURIComponent(actionId)}/oauth/callback`, this.cliConfig.baseURL).toString();
206
+ this.log((0, runtime_tool_support_1.oauthActionNotice)(redirectUrl));
207
+ }
202
208
  this.printAgentUrl(args.agentId);
203
209
  }
204
210
  }
@@ -12,6 +12,7 @@ const node_fs_1 = require("node:fs");
12
12
  const core_1 = require("@oclif/core");
13
13
  const data_provider_1 = require("@skrr-ai/data-provider");
14
14
  const base_command_1 = require("../../base-command");
15
+ const agent_home_workspace_1 = require("../../lib/agent-home-workspace");
15
16
  const agentic_stream_1 = require("../../lib/agentic-stream");
16
17
  const web_url_1 = require("../../lib/web-url");
17
18
  const local_skills_1 = require("../../lib/local-skills");
@@ -302,7 +303,10 @@ class AgentsChat extends base_command_1.BaseCommand {
302
303
  exit: 2,
303
304
  });
304
305
  }
305
- const { refs, problems } = (0, local_skills_1.resolveLocalSkillRefs)(inventory.skills ?? [], requested);
306
+ const { refs, problems } = (0, local_skills_1.resolveLocalSkillRefs)(inventory.skills ?? [], requested, {
307
+ snapshot: inventory.cwdResolved !== true,
308
+ daemonId,
309
+ });
306
310
  if (problems.length > 0) {
307
311
  this.error(problems.join('\n'), { exit: 2 });
308
312
  }
@@ -446,6 +450,7 @@ class AgentsChat extends base_command_1.BaseCommand {
446
450
  const prompt = localSkills
447
451
  ? (0, local_skills_1.withSkillInvocations)(flags.prompt, localSkills.refs)
448
452
  : flags.prompt;
453
+ await (0, agent_home_workspace_1.applyAgentHomeWorkspaceDefault)(args.agentId, (agentId) => data_provider_1.dataService.getAgentById({ agent_id: agentId }));
449
454
  let started;
450
455
  try {
451
456
  started = await data_provider_1.dataService.startAgenticChat({
@@ -8,6 +8,7 @@ exports.backgroundLoopLines = backgroundLoopLines;
8
8
  const core_1 = require("@oclif/core");
9
9
  const data_provider_1 = require("@skrr-ai/data-provider");
10
10
  const agent_visual_refs_1 = require("../../lib/agent-visual-refs");
11
+ const runtime_tool_support_1 = require("../../lib/runtime-tool-support");
11
12
  const base_command_1 = require("../../base-command");
12
13
  const execution_target_1 = require("../../lib/execution-target");
13
14
  const prompt_1 = require("../../lib/prompt");
@@ -201,7 +202,10 @@ class AgentsCreate extends base_command_1.BaseCommand {
201
202
  description: 'Default Claude permission mode for sessions',
202
203
  options: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
203
204
  }),
204
- tools: core_1.Flags.string({ description: 'Tools JSON array' }),
205
+ tools: core_1.Flags.string({
206
+ description: 'Tools JSON array of plugin keys, e.g. \'["calculator"]\'. `skrr agents tools` lists the keys, ' +
207
+ 'and which of them an agent turn can call.',
208
+ }),
205
209
  'model-parameters': core_1.Flags.string({ description: 'Model parameters JSON object' }),
206
210
  'agent-ids': core_1.Flags.string({ description: 'Delegated agent IDs JSON array' }),
207
211
  'network-mode': core_1.Flags.string({ description: 'Agent network mode' }),
@@ -382,6 +386,7 @@ class AgentsCreate extends base_command_1.BaseCommand {
382
386
  if (unapplied.length > 0) {
383
387
  this.warn(unappliedPayloadKeysWarning(unapplied));
384
388
  }
389
+ await (0, runtime_tool_support_1.warnPluginsNotLoaded)(payload.tools, (message) => this.warn(message));
385
390
  if (flags.json) {
386
391
  this.log(JSON.stringify((0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, created), null, 2));
387
392
  return;
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ /**
3
+ * Create or repair this account's Agent Manager (the HR Agent).
4
+ *
5
+ * Wraps `POST /api/agents/manager/ensure`. New accounts get an HR Agent at
6
+ * signup; accounts that predate it had no way to get one (OSK-9745), and a
7
+ * signup whose provisioning failed part-way was never finished (OSK-9785).
8
+ * IDEMPOTENT: run it again and it reports the existing agent, or what it had
9
+ * to repair.
10
+ */
11
+ export default class AgentsManagerEnsure extends BaseCommand {
12
+ static description: string;
13
+ static examples: string[];
14
+ static flags: {
15
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ };
17
+ run(): Promise<void>;
18
+ }
@@ -0,0 +1,56 @@
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 web_url_1 = require("../../../lib/web-url");
7
+ /**
8
+ * Create or repair this account's Agent Manager (the HR Agent).
9
+ *
10
+ * Wraps `POST /api/agents/manager/ensure`. New accounts get an HR Agent at
11
+ * signup; accounts that predate it had no way to get one (OSK-9745), and a
12
+ * signup whose provisioning failed part-way was never finished (OSK-9785).
13
+ * IDEMPOTENT: run it again and it reports the existing agent, or what it had
14
+ * to repair.
15
+ */
16
+ class AgentsManagerEnsure extends base_command_1.BaseCommand {
17
+ static description = "Create your Agent Manager (HR Agent) if you don't have one, or repair it if it is incomplete";
18
+ static examples = [
19
+ '<%= config.bin %> agents manager ensure',
20
+ '<%= config.bin %> agents manager ensure --workspace <workspace-id> --json',
21
+ ];
22
+ static flags = {
23
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
24
+ };
25
+ async run() {
26
+ this.requireAuth();
27
+ const { flags } = await this.parse(AgentsManagerEnsure);
28
+ let result;
29
+ try {
30
+ result = await data_provider_1.dataService.ensureAgentManager();
31
+ }
32
+ catch (err) {
33
+ this.handleApiError(err);
34
+ }
35
+ const agent = (0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, {
36
+ ...result.agent,
37
+ });
38
+ if (flags.json) {
39
+ this.log(JSON.stringify({ ...result, agent }, null, 2));
40
+ return;
41
+ }
42
+ const label = `${result.agent.id} — ${result.agent.name}`;
43
+ if (result.created) {
44
+ this.log(`Created your Agent Manager: ${label}`);
45
+ }
46
+ else if (result.repaired.length > 0) {
47
+ this.log(`Repaired your Agent Manager (${result.repaired.join(', ')}): ${label}`);
48
+ }
49
+ else {
50
+ this.log(`You already have an Agent Manager: ${label}`);
51
+ }
52
+ this.log(`Workspace: ${result.workspaceId}`);
53
+ this.log(`URL: ${agent.url ?? '-'}`);
54
+ }
55
+ }
56
+ exports.default = AgentsManagerEnsure;
@@ -179,6 +179,10 @@ class AgentsShow extends base_command_1.BaseCommand {
179
179
  }
180
180
  const tools = Array.isArray(a.tools) ? a.tools : [];
181
181
  this.log(`Tools: ${tools.length === 0 ? '(none)' : tools.join(', ')}`);
182
+ if (tools.length > 0) {
183
+ // Stored, not loaded: the runtime has none of these yet (OSK-9750, OSK-9754).
184
+ this.log(' (saved on the agent; the agent runtime does not load these yet)');
185
+ }
182
186
  if (a.description) {
183
187
  this.log('');
184
188
  this.log('Description:');
@@ -1,4 +1,10 @@
1
1
  import { BaseCommand } from '../../../base-command';
2
+ /**
3
+ * A credential's help text for a terminal. Plugin manifests write it as HTML
4
+ * with the signup link in an anchor; stripping the tags alone would keep
5
+ * "see Our Docs" and drop the URL, which is the part worth printing.
6
+ */
7
+ export declare function credentialHelpText(description: string): string;
2
8
  /**
3
9
  * Whether this account has credentials for one tool.
4
10
  *
@@ -1,8 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.credentialHelpText = credentialHelpText;
3
4
  const core_1 = require("@oclif/core");
4
5
  const data_provider_1 = require("@skrr-ai/data-provider");
5
6
  const base_command_1 = require("../../../base-command");
7
+ const html_text_1 = require("../../../lib/html-text");
8
+ /**
9
+ * A credential's help text for a terminal. Plugin manifests write it as HTML
10
+ * with the signup link in an anchor; stripping the tags alone would keep
11
+ * "see Our Docs" and drop the URL, which is the part worth printing.
12
+ */
13
+ function credentialHelpText(description) {
14
+ return (0, html_text_1.htmlToDisplayText)(description.replace(/<a\s[^>]*href=['"]([^'"]+)['"][^>]*>(.*?)<\/a>/gi, '$2 ($1)'));
15
+ }
6
16
  /**
7
17
  * Whether this account has credentials for one tool.
8
18
  *
@@ -33,9 +43,25 @@ class AgentsToolsAuth extends base_command_1.BaseCommand {
33
43
  this.log(JSON.stringify(result, null, 2));
34
44
  return;
35
45
  }
46
+ const missing = result.missing ?? [];
36
47
  this.log(result.authenticated
37
48
  ? `${args.toolId}: authenticated`
38
- : `${args.toolId}: not authenticated${result.message ? ` — ${result.message}` : ''}`);
49
+ : `${args.toolId}: not authenticated${missing.length === 0 && result.message ? ` — ${result.message}` : ''}`);
50
+ // The answer's next question is "what do I supply, and where do I get it"
51
+ // (OSK-9550); the manifest carries both, so print them.
52
+ if (missing.length > 0) {
53
+ this.log('Missing credentials:');
54
+ for (const credential of missing) {
55
+ this.log(` ${credential.authField} ${credential.label ?? ''}`.trimEnd());
56
+ if (credential.description) {
57
+ this.log(` ${credentialHelpText(credential.description)}`);
58
+ }
59
+ }
60
+ this.log('Add them where you add this tool to an agent in the web app.');
61
+ }
62
+ if (result.agentRuntime === false) {
63
+ this.log(`Agent turns cannot call ${args.toolId}: it saves output through a web request an agent turn does not have.`);
64
+ }
39
65
  }
40
66
  }
41
67
  exports.default = AgentsToolsAuth;
@@ -2,6 +2,7 @@
2
2
  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
+ const runtime_tool_support_1 = require("../../../lib/runtime-tool-support");
5
6
  const base_command_1 = require("../../../base-command");
6
7
  const format_1 = require("../../../lib/format");
7
8
  /**
@@ -63,15 +64,24 @@ class AgentsToolsList extends base_command_1.BaseCommand {
63
64
  pluginKey: tool.pluginKey,
64
65
  name: tool.name,
65
66
  auth: authState(tool),
67
+ agent: (0, runtime_tool_support_1.agentRuntimeLabel)(tool),
66
68
  description: String(tool.description ?? ''),
67
69
  })), [
68
70
  { key: 'pluginKey', header: 'PLUGIN KEY', verbatim: true },
69
71
  { key: 'name', header: 'NAME', maxWidth: 28 },
70
72
  { key: 'auth', header: 'AUTH' },
73
+ { key: 'agent', header: 'AGENT' },
71
74
  { key: 'description', header: 'DESCRIPTION', maxWidth: 52 },
72
75
  ], (line) => this.log(line));
73
76
  this.log('');
74
- this.log('PLUGIN KEY is what --tools stores, e.g. --tools \'["web_search"]\'.');
77
+ // The example must be a key this list printed (OSK-9600: it was web_search),
78
+ // preferably one that works without credentials.
79
+ const example = rows.find((tool) => !tool.authConfig?.length) ?? rows[0];
80
+ this.log(`PLUGIN KEY is what --tools stores, e.g. --tools '["${example.pluginKey}"]'.`);
81
+ this.log(runtime_tool_support_1.AGENT_COLUMN_FOOTNOTE);
82
+ if (rows.some((tool) => tool.authConfig?.length && !tool.authenticated)) {
83
+ this.log('`skrr agents tools auth <plugin-key>` names the credentials a tool still needs.');
84
+ }
75
85
  }
76
86
  }
77
87
  exports.default = AgentsToolsList;
@@ -4,6 +4,7 @@ const core_1 = require("@oclif/core");
4
4
  const data_provider_1 = require("@skrr-ai/data-provider");
5
5
  const agent_visual_refs_1 = require("../../lib/agent-visual-refs");
6
6
  const create_1 = require("./create");
7
+ const runtime_tool_support_1 = require("../../lib/runtime-tool-support");
7
8
  const base_command_1 = require("../../base-command");
8
9
  const execution_target_1 = require("../../lib/execution-target");
9
10
  const prompt_1 = require("../../lib/prompt");
@@ -51,7 +52,10 @@ class AgentsUpdate extends base_command_1.BaseCommand {
51
52
  description: 'Default Claude permission mode for sessions',
52
53
  options: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
53
54
  }),
54
- tools: core_1.Flags.string({ description: 'Tools JSON array' }),
55
+ tools: core_1.Flags.string({
56
+ description: 'Tools JSON array of plugin keys, e.g. \'["calculator"]\'. `skrr agents tools` lists the keys, ' +
57
+ 'and which of them an agent turn can call.',
58
+ }),
55
59
  'model-parameters': core_1.Flags.string({ description: 'Model parameters JSON object' }),
56
60
  'agent-ids': core_1.Flags.string({ description: 'Delegated agent IDs JSON array' }),
57
61
  'network-mode': core_1.Flags.string({ description: 'Agent network mode' }),
@@ -195,6 +199,7 @@ class AgentsUpdate extends base_command_1.BaseCommand {
195
199
  if (unapplied.length > 0) {
196
200
  this.warn((0, create_1.unappliedPayloadKeysWarning)(unapplied));
197
201
  }
202
+ await (0, runtime_tool_support_1.warnPluginsNotLoaded)(payload.tools, (message) => this.warn(message));
198
203
  if (flags.json) {
199
204
  this.log(JSON.stringify((0, web_url_1.withAgentUrl)(this.cliConfig.baseURL, updated), null, 2));
200
205
  return;
@@ -38,8 +38,10 @@ export default class CodeInstall extends BaseCommand {
38
38
  *
39
39
  * Refuses rather than guessing when several are active. Picking one would mean
40
40
  * installing a hundred megabytes onto a machine the user was not thinking
41
- * about, and the list this reads is the same one `skrr list-daemons` prints —
42
- * so the error can name the exact values that work.
41
+ * about. The candidates are CONNECTED daemons by the id the installer routes
42
+ * take (`listConnectedDaemons`), so the error names values that work — the
43
+ * Daemon resource list `skrr list-daemons` prints is a different id space
44
+ * (OSK-9993).
43
45
  *
44
46
  * A Dedicated Runtime's own machine is refused here, before any request. The
45
47
  * daemon and the API refuse it too; saying so locally is what keeps the answer
@@ -34,7 +34,7 @@ class CodeInstall extends base_command_1.BaseCommand {
34
34
  static description = `Install the ${auth_core_1.FIRST_PARTY_HARNESS.displayName} engine on this machine, through the daemon`;
35
35
  static examples = [
36
36
  '<%= config.bin %> code install',
37
- '<%= config.bin %> code install --daemon d_6a323ae4...',
37
+ '<%= config.bin %> code install --daemon <daemon-id>',
38
38
  '<%= config.bin %> code install --json',
39
39
  ];
40
40
  static flags = {
@@ -90,7 +90,7 @@ class CodeInstall extends base_command_1.BaseCommand {
90
90
  this.failWithCliError({
91
91
  message: `The daemon on ${(0, daemon_ref_1.formatDaemonRef)(daemonId)} accepted the request and returned no ` +
92
92
  'install job, and does not say why. Nothing has been shown to start. ' +
93
- `Check what it offers with \`${this.config.bin} list-daemons\` for the machine, and ` +
93
+ `Check what it offers with \`${this.config.bin} harnesses installers --daemon ${daemonId}\`, and ` +
94
94
  `\`${this.config.bin} code doctor\` here once you expect it to have landed.`,
95
95
  code: 'INSTALL_NOT_TRACKED',
96
96
  exit: 1,
@@ -132,7 +132,7 @@ class CodeInstall extends base_command_1.BaseCommand {
132
132
  return await (0, daemon_target_1.resolveDaemonTarget)({
133
133
  explicit,
134
134
  local: (0, daemon_target_1.localMachine)({ baseURL: this.cliConfig?.baseURL }),
135
- listActiveDaemons: () => (0, daemon_target_1.listActiveDaemons)(this.resolvedCredential),
135
+ listActiveDaemons: () => (0, daemon_target_1.listConnectedDaemons)(this.resolvedCredential),
136
136
  });
137
137
  }
138
138
  catch (err) {
@@ -144,8 +144,10 @@ class CodeInstall extends base_command_1.BaseCommand {
144
144
  *
145
145
  * Refuses rather than guessing when several are active. Picking one would mean
146
146
  * installing a hundred megabytes onto a machine the user was not thinking
147
- * about, and the list this reads is the same one `skrr list-daemons` prints —
148
- * so the error can name the exact values that work.
147
+ * about. The candidates are CONNECTED daemons by the id the installer routes
148
+ * take (`listConnectedDaemons`), so the error names values that work — the
149
+ * Daemon resource list `skrr list-daemons` prints is a different id space
150
+ * (OSK-9993).
149
151
  *
150
152
  * A Dedicated Runtime's own machine is refused here, before any request. The
151
153
  * daemon and the API refuse it too; saying so locally is what keeps the answer
@@ -169,8 +171,8 @@ class CodeInstall extends base_command_1.BaseCommand {
169
171
  }
170
172
  if (target.kind === 'none') {
171
173
  this.failWithCliError({
172
- message: 'No active daemon is registered for this account, so nothing can perform the install. ' +
173
- `Start the local runtime with \`${this.config.bin} daemon start\`, then run this again.`,
174
+ message: 'No daemon is connected for this account, so nothing can perform the install. ' +
175
+ `Start the background service on this computer with \`${this.config.bin} daemon start\`, then run this again.`,
174
176
  code: 'NO_DAEMON',
175
177
  exit: 1,
176
178
  retryable: false,
@@ -179,11 +181,11 @@ class CodeInstall extends base_command_1.BaseCommand {
179
181
  const { daemons } = target;
180
182
  const choices = daemons
181
183
  .slice(0, 10)
182
- .map((d) => ` ${(0, daemon_ref_1.formatDaemonRef)(d.id)} ${d.name || '—'}`)
184
+ .map((d) => ` ${d.id} ${d.name || '—'}`)
183
185
  .join('\n');
184
186
  this.failWithCliError({
185
- message: `${daemons.length} active daemons — say which machine should install the engine:\n${choices}\n` +
186
- `Pass one with --daemon, or see them all with \`${this.config.bin} list-daemons\`.`,
187
+ message: `${daemons.length} connected daemons — say which machine should install the engine:\n${choices}\n` +
188
+ `Pass one with --daemon, or see each daemon id in the DAEMON ID column of \`${this.config.bin} harnesses list\`.`,
187
189
  code: 'AMBIGUOUS_DAEMON',
188
190
  exit: 1,
189
191
  retryable: false,
@@ -110,9 +110,7 @@ class ConvosList extends base_command_1.BaseCommand {
110
110
  // The owning agent is the field callers most often had to reach for --json
111
111
  // to see (and the one `--agent` filters on), so surface it in the table too.
112
112
  agent: String(c.agent_id ?? c.agentId ?? '-'),
113
- updated: c.updatedAt
114
- ? new Date(String(c.updatedAt)).toISOString().slice(0, 19).replace('T', ' ')
115
- : '-',
113
+ updated: (0, format_1.localTime)(c.updatedAt),
116
114
  }));
117
115
  (0, format_1.renderTable)(rows, [
118
116
  { key: 'id', header: 'ID' },
@@ -5,6 +5,7 @@ const core_1 = require("@oclif/core");
5
5
  const data_provider_1 = require("@skrr-ai/data-provider");
6
6
  const base_command_1 = require("../../base-command");
7
7
  const web_url_1 = require("../../lib/web-url");
8
+ const format_1 = require("../../lib/format");
8
9
  class ConvosShow extends base_command_1.BaseCommand {
9
10
  static description = 'Show details for a single conversation';
10
11
  static examples = [
@@ -38,10 +39,10 @@ class ConvosShow extends base_command_1.BaseCommand {
38
39
  this.log(`Model: ${c.model ?? '-'}`);
39
40
  this.log(`User: ${c.user ?? '-'}`);
40
41
  if (c.createdAt) {
41
- this.log(`Created: ${formatTime(c.createdAt)}`);
42
+ this.log(`Created: ${(0, format_1.localTime)(c.createdAt)}`);
42
43
  }
43
44
  if (c.updatedAt) {
44
- this.log(`Updated: ${formatTime(c.updatedAt)}`);
45
+ this.log(`Updated: ${(0, format_1.localTime)(c.updatedAt)}`);
45
46
  }
46
47
  if (c.agent_id || c.agentId) {
47
48
  this.log(`Agent: ${typeof c.agentName === 'string' && c.agentName ? `${c.agentName} (${c.agent_id ?? c.agentId})` : (c.agent_id ?? c.agentId)}`);
@@ -102,17 +103,9 @@ function formatHandoverParty(entry, baseURL) {
102
103
  if (entry.by)
103
104
  lines.push(` By: ${entry.by}`);
104
105
  if (entry.at)
105
- lines.push(` At: ${formatTime(entry.at)}`);
106
+ lines.push(` At: ${(0, format_1.localTime)(entry.at)}`);
106
107
  // The reason last, because it is the sentence rather than a field.
107
108
  if (entry.reason)
108
109
  lines.push(` Reason: ${entry.reason}`);
109
110
  return lines;
110
111
  }
111
- function formatTime(value) {
112
- try {
113
- return new Date(String(value)).toISOString().slice(0, 19).replace('T', ' ');
114
- }
115
- catch {
116
- return String(value);
117
- }
118
- }