@skrr-ai/cli 0.1.36 → 0.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +17 -4
  2. package/dist/commands/agents/actions/create.d.ts +5 -0
  3. package/dist/commands/agents/actions/create.js +26 -0
  4. package/dist/commands/agents/actions/update.d.ts +5 -0
  5. package/dist/commands/agents/actions/update.js +24 -0
  6. package/dist/commands/agents/api-actions/add.d.ts +41 -0
  7. package/dist/commands/agents/api-actions/add.js +202 -0
  8. package/dist/commands/agents/api-actions/index.d.ts +28 -0
  9. package/dist/commands/agents/api-actions/index.js +77 -0
  10. package/dist/commands/agents/api-actions/remove.d.ts +14 -0
  11. package/dist/commands/agents/api-actions/remove.js +36 -0
  12. package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
  13. package/dist/commands/agents/avatar/default/apply.js +56 -0
  14. package/dist/commands/agents/avatar/default/index.d.ts +18 -0
  15. package/dist/commands/agents/avatar/default/index.js +44 -0
  16. package/dist/commands/agents/avatar/default/set.d.ts +23 -0
  17. package/dist/commands/agents/avatar/default/set.js +95 -0
  18. package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
  19. package/dist/commands/agents/avatar/library/delete.js +47 -0
  20. package/dist/commands/agents/avatar/library/index.d.ts +16 -0
  21. package/dist/commands/agents/avatar/library/index.js +56 -0
  22. package/dist/commands/agents/avatar/presets.d.ts +19 -0
  23. package/dist/commands/agents/avatar/presets.js +56 -0
  24. package/dist/commands/agents/categories/create.d.ts +14 -0
  25. package/dist/commands/agents/categories/create.js +46 -0
  26. package/dist/commands/agents/categories/delete.d.ts +13 -0
  27. package/dist/commands/agents/categories/delete.js +33 -0
  28. package/dist/commands/agents/categories/index.d.ts +20 -0
  29. package/dist/commands/agents/categories/index.js +82 -0
  30. package/dist/commands/agents/categories/update.d.ts +22 -0
  31. package/dist/commands/agents/categories/update.js +59 -0
  32. package/dist/commands/agents/create.d.ts +10 -0
  33. package/dist/commands/agents/create.js +57 -3
  34. package/dist/commands/agents/ensure-default.d.ts +27 -0
  35. package/dist/commands/agents/ensure-default.js +65 -0
  36. package/dist/commands/agents/mute.d.ts +16 -0
  37. package/dist/commands/agents/mute.js +38 -0
  38. package/dist/commands/agents/pin.d.ts +16 -0
  39. package/dist/commands/agents/pin.js +38 -0
  40. package/dist/commands/agents/tools/auth.d.ts +19 -0
  41. package/dist/commands/agents/tools/auth.js +41 -0
  42. package/dist/commands/agents/tools/calls.d.ts +18 -0
  43. package/dist/commands/agents/tools/calls.js +54 -0
  44. package/dist/commands/agents/tools/index.d.ts +20 -0
  45. package/dist/commands/agents/tools/index.js +77 -0
  46. package/dist/commands/agents/unmute.d.ts +16 -0
  47. package/dist/commands/agents/unmute.js +38 -0
  48. package/dist/commands/agents/unpin.d.ts +16 -0
  49. package/dist/commands/agents/unpin.js +38 -0
  50. package/dist/commands/agents/update.d.ts +12 -0
  51. package/dist/commands/agents/update.js +64 -3
  52. package/dist/commands/followups/act.d.ts +22 -0
  53. package/dist/commands/followups/act.js +102 -0
  54. package/dist/commands/followups/cancel.d.ts +17 -0
  55. package/dist/commands/followups/cancel.js +40 -0
  56. package/dist/commands/followups/checkin.d.ts +27 -0
  57. package/dist/commands/followups/checkin.js +107 -0
  58. package/dist/commands/followups/list.d.ts +24 -0
  59. package/dist/commands/followups/list.js +90 -0
  60. package/dist/commands/followups/remind.d.ts +26 -0
  61. package/dist/commands/followups/remind.js +106 -0
  62. package/dist/commands/followups/reschedule.d.ts +15 -0
  63. package/dist/commands/followups/reschedule.js +48 -0
  64. package/dist/commands/followups/resolve.d.ts +23 -0
  65. package/dist/commands/followups/resolve.js +54 -0
  66. package/dist/commands/followups/show.d.ts +12 -0
  67. package/dist/commands/followups/show.js +45 -0
  68. package/dist/commands/followups/watch.d.ts +51 -0
  69. package/dist/commands/followups/watch.js +207 -0
  70. package/dist/commands/goals/labels/add.js +19 -2
  71. package/dist/commands/goals/labels/remove.js +22 -2
  72. package/dist/commands/labels/list.d.ts +24 -1
  73. package/dist/commands/labels/list.js +62 -19
  74. package/dist/commands/memory/governance/index.d.ts +21 -0
  75. package/dist/commands/memory/governance/index.js +64 -0
  76. package/dist/commands/memory/governance/set.d.ts +24 -0
  77. package/dist/commands/memory/governance/set.js +95 -0
  78. package/dist/commands/memory/provenance.d.ts +18 -0
  79. package/dist/commands/memory/provenance.js +66 -0
  80. package/dist/commands/spaces/create.d.ts +3 -0
  81. package/dist/commands/spaces/create.js +32 -2
  82. package/dist/commands/spaces/labels/add.js +19 -2
  83. package/dist/commands/spaces/labels/remove.js +22 -2
  84. package/dist/commands/spaces/show.js +2 -0
  85. package/dist/commands/spaces/update.d.ts +5 -0
  86. package/dist/commands/spaces/update.js +41 -4
  87. package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
  88. package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +45 -0
  89. package/dist/commands/tasks/complete.d.ts +1 -0
  90. package/dist/commands/tasks/complete.js +8 -1
  91. package/dist/commands/tasks/create.d.ts +3 -0
  92. package/dist/commands/tasks/create.js +34 -2
  93. package/dist/commands/tasks/expectations/assess.d.ts +11 -0
  94. package/dist/commands/tasks/expectations/assess.js +85 -14
  95. package/dist/commands/tasks/expectations.js +19 -2
  96. package/dist/commands/tasks/labels/attach.js +20 -3
  97. package/dist/commands/tasks/labels/detach.js +21 -3
  98. package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
  99. package/dist/commands/tasks/lifecycle/attach.js +47 -0
  100. package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
  101. package/dist/commands/tasks/lifecycle/definitions.js +40 -0
  102. package/dist/commands/tasks/lifecycle/detach.d.ts +12 -0
  103. package/dist/commands/tasks/lifecycle/detach.js +32 -0
  104. package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
  105. package/dist/commands/tasks/lifecycle/history.js +38 -0
  106. package/dist/commands/tasks/lifecycle/migrate.d.ts +12 -0
  107. package/dist/commands/tasks/lifecycle/migrate.js +29 -0
  108. package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
  109. package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
  110. package/dist/commands/tasks/lifecycle/reopen.d.ts +13 -0
  111. package/dist/commands/tasks/lifecycle/reopen.js +34 -0
  112. package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
  113. package/dist/commands/tasks/lifecycle/show.js +27 -0
  114. package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
  115. package/dist/commands/tasks/lifecycle/start.js +30 -0
  116. package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
  117. package/dist/commands/tasks/lifecycle/transition.js +78 -0
  118. package/dist/commands/tasks/move.d.ts +1 -0
  119. package/dist/commands/tasks/move.js +31 -0
  120. package/dist/commands/tasks/result/submit.js +11 -1
  121. package/dist/commands/tasks/review-queue.d.ts +29 -0
  122. package/dist/commands/tasks/review-queue.js +165 -0
  123. package/dist/commands/tasks/show.js +42 -0
  124. package/dist/commands/tasks/update.d.ts +1 -0
  125. package/dist/commands/tasks/update.js +47 -0
  126. package/dist/lib/agent-actions.d.ts +36 -10
  127. package/dist/lib/agent-actions.js +63 -9
  128. package/dist/lib/agent-config.d.ts +11 -0
  129. package/dist/lib/agent-config.js +85 -3
  130. package/dist/lib/agent-pin-mute.d.ts +24 -0
  131. package/dist/lib/agent-pin-mute.js +17 -0
  132. package/dist/lib/agent-visual-refs.d.ts +6 -0
  133. package/dist/lib/agent-visual-refs.js +142 -0
  134. package/dist/lib/first-party-harness-agent.js +7 -0
  135. package/dist/lib/followups.d.ts +107 -0
  136. package/dist/lib/followups.js +102 -0
  137. package/dist/lib/label-ref.d.ts +95 -0
  138. package/dist/lib/label-ref.js +163 -0
  139. package/dist/lib/label-scope.d.ts +2 -2
  140. package/dist/lib/label-scope.js +3 -3
  141. package/dist/lib/task-closure.d.ts +32 -0
  142. package/dist/lib/task-closure.js +106 -0
  143. package/dist/lib/task-lifecycle-output.d.ts +14 -0
  144. package/dist/lib/task-lifecycle-output.js +101 -0
  145. package/dist/lib/tasks.d.ts +3 -0
  146. package/dist/lib/tasks.js +31 -0
  147. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
  148. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
  149. package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
  150. package/dist/node_modules/@skrr-ai/data-provider/index.js +5079 -4546
  151. package/oclif.manifest.json +20216 -16002
  152. package/package.json +16 -4
package/README.md CHANGED
@@ -839,8 +839,10 @@ cat space.json | sky spaces create --from-json -
839
839
  sky spaces create --from-json template.json --title "Override title"
840
840
  ```
841
841
 
842
- Flags: `--title`, `--description`, `--status`, `--color`, `--lead-agent`,
843
- `--target-date`, `--group-chat`, `--from-json <file|->`, `--json`.
842
+ Flags: `--title`, `--description`, `--status`, `--color`, `--icon`,
843
+ `--icon-color`, `--lead-agent`, `--team`, `--target-date`, `--goal`,
844
+ `--label`, `--group-chat`, `--parent`, `--no-inherit-access`,
845
+ `--from-json <file|->`, `--json`.
844
846
 
845
847
  ### `sky spaces update <id>`
846
848
 
@@ -852,8 +854,19 @@ sky spaces update <space-id> --status active --color "#4f46e5"
852
854
  sky spaces update <space-id> --from-json patch.json
853
855
  ```
854
856
 
855
- Flags: `--title`, `--description`, `--status`, `--color`, `--lead-agent`,
856
- `--target-date`, `--from-json <file|->`, `--json`.
857
+ Flags: `--title`, `--description`, `--status`, `--color`, `--icon`,
858
+ `--icon-color`, `--lead-agent`, `--target-date`, `--goal`,
859
+ `--no-inherit-access`, `--estimate-scale`, `--estimate-migration`,
860
+ `--default-estimate`, `--no-use-default-estimate`, `--default-expect`,
861
+ `--delivery-mode`, `--integration-branch`, `--auto-merge-tier`,
862
+ `--worktree-isolation`, `--no-auto-start-on-backlog-exit`,
863
+ `--triage-external-intake`, `--default-task-template`,
864
+ `--from-json <file|->`, `--json`.
865
+
866
+ Nullable fields accept `none` (or `null`) to clear: `--icon none` restores
867
+ the default folder, `--icon-color none` the neutral icon color,
868
+ `--lead-agent none` removes the Leader, `--target-date none` clears the
869
+ date, and `--default-task-template none` removes the default template.
857
870
 
858
871
  ### `sky spaces delete <id>`
859
872
 
@@ -18,6 +18,11 @@ export default class AgentsActionsCreate extends BaseCommand {
18
18
  embeds: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
19
  order: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
20
  enabled: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
+ scope: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ 'space-title': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ label: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ outcome: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
21
26
  };
22
27
  run(): Promise<void>;
23
28
  }
@@ -39,6 +39,20 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
39
39
  embeds: core_1.Flags.string({ description: 'Embedded built-in actions JSON array' }),
40
40
  order: core_1.Flags.integer({ description: 'Display order (defaults to end of list)' }),
41
41
  enabled: core_1.Flags.boolean({ description: 'Create enabled or disabled', allowNo: true }),
42
+ scope: core_1.Flags.string({
43
+ description: 'Where the action is offered. Implied by --space / --label; pass "general" to offer it everywhere.',
44
+ options: [...agent_actions_1.AGENT_ACTION_SCOPE_CHOICES],
45
+ }),
46
+ space: core_1.Flags.string({ description: 'Offer only in this space (implies --scope space)' }),
47
+ 'space-title': core_1.Flags.string({ description: 'Denormalized space title for the scope chip' }),
48
+ label: core_1.Flags.string({
49
+ description: 'Offer in every space carrying this label (repeatable, any-of; implies --scope label)',
50
+ multiple: true,
51
+ }),
52
+ outcome: core_1.Flags.string({
53
+ description: "What a run leaves behind: 'ephemeral' hides the run's task once it answers, 'durable' keeps it on the board. Default ephemeral.",
54
+ options: [...agent_actions_1.AGENT_ACTION_OUTCOME_CHOICES],
55
+ }),
42
56
  };
43
57
  async run() {
44
58
  this.requireAuth();
@@ -54,6 +68,10 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
54
68
  config: (0, agent_actions_1.parseJsonObjectFlag)(flags.config, '--config'),
55
69
  order: flags.order,
56
70
  enabled: flags.enabled,
71
+ // Flags win over --from-json, and a JSON body may still carry these
72
+ // directly. Both paths land on the same two fields below.
73
+ scope: (0, agent_actions_1.resolveAgentActionScopeFlags)(flags),
74
+ outcome: flags.outcome,
57
75
  });
58
76
  }
59
77
  catch (err) {
@@ -69,12 +87,18 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
69
87
  const kind = body.kind === 'builtin' ? 'builtin' : 'prompt';
70
88
  const order = typeof body.order === 'number' ? body.order : (0, agent_actions_1.nextActionOrder)(actions);
71
89
  const enabled = typeof body.enabled === 'boolean' ? body.enabled : true;
90
+ const scope = body.scope;
91
+ const outcome = body.outcome === 'durable' || body.outcome === 'ephemeral'
92
+ ? body.outcome
93
+ : undefined;
72
94
  if (kind === 'builtin') {
73
95
  const builtinType = body.builtinType;
74
96
  if (!agent_actions_1.BUILTIN_ACTION_TYPES.includes(builtinType)) {
75
97
  this.error(`--builtin-type is required for built-in actions.`, { exit: 1 });
76
98
  }
77
99
  created = (0, agent_actions_1.makeBuiltinAction)({
100
+ scope,
101
+ outcome,
78
102
  title,
79
103
  description: typeof body.description === 'string' ? body.description : undefined,
80
104
  builtinType: builtinType,
@@ -104,6 +128,8 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
104
128
  this.error(err.message, { exit: 1 });
105
129
  }
106
130
  created = (0, agent_actions_1.makePromptAction)({
131
+ scope,
132
+ outcome,
107
133
  title,
108
134
  description: typeof body.description === 'string' ? body.description : undefined,
109
135
  prompt,
@@ -17,6 +17,11 @@ export default class AgentsActionsUpdate extends BaseCommand {
17
17
  'replace-config': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
18
18
  order: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
19
19
  enabled: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
20
+ scope: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
21
+ space: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
22
+ 'space-title': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ label: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ outcome: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
25
  };
21
26
  run(): Promise<void>;
22
27
  }
@@ -35,6 +35,20 @@ class AgentsActionsUpdate extends base_command_1.BaseCommand {
35
35
  }),
36
36
  order: core_1.Flags.integer({ description: 'Display order' }),
37
37
  enabled: core_1.Flags.boolean({ description: 'Enable or disable the action', allowNo: true }),
38
+ scope: core_1.Flags.string({
39
+ description: 'Where the action is offered. Implied by --space / --label; pass "general" to offer it everywhere.',
40
+ options: [...agent_actions_1.AGENT_ACTION_SCOPE_CHOICES],
41
+ }),
42
+ space: core_1.Flags.string({ description: 'Offer only in this space (implies --scope space)' }),
43
+ 'space-title': core_1.Flags.string({ description: 'Denormalized space title for the scope chip' }),
44
+ label: core_1.Flags.string({
45
+ description: 'Offer in every space carrying this label (repeatable, any-of; implies --scope label)',
46
+ multiple: true,
47
+ }),
48
+ outcome: core_1.Flags.string({
49
+ description: "What a run leaves behind: 'ephemeral' hides the run's task once it answers, 'durable' keeps it on the board.",
50
+ options: [...agent_actions_1.AGENT_ACTION_OUTCOME_CHOICES],
51
+ }),
38
52
  };
39
53
  async run() {
40
54
  this.requireAuth();
@@ -49,6 +63,8 @@ class AgentsActionsUpdate extends base_command_1.BaseCommand {
49
63
  config: (0, agent_actions_1.parseJsonObjectFlag)(flags.config, '--config'),
50
64
  order: flags.order,
51
65
  enabled: flags.enabled,
66
+ scope: (0, agent_actions_1.resolveAgentActionScopeFlags)(flags),
67
+ outcome: flags.outcome,
52
68
  });
53
69
  }
54
70
  catch (err) {
@@ -76,6 +92,14 @@ class AgentsActionsUpdate extends base_command_1.BaseCommand {
76
92
  next.order = patch.order;
77
93
  if (typeof patch.enabled === 'boolean')
78
94
  next.enabled = patch.enabled;
95
+ // A scope is replaced wholesale, never merged: `{kind:'space'}` and
96
+ // `{kind:'label'}` carry disjoint fields, so a shallow merge would leave
97
+ // a `labelIds` behind on a space scope and produce a shape the write gate
98
+ // rejects. Absent means "leave the existing scope alone".
99
+ if (patch.scope !== undefined)
100
+ next.scope = patch.scope;
101
+ if (patch.outcome !== undefined)
102
+ next.outcome = patch.outcome;
79
103
  if (current.kind === 'builtin') {
80
104
  const builtin = next;
81
105
  if (patch.builtinType !== undefined) {
@@ -0,0 +1,41 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ /**
3
+ * Attach (or re-attach) an OpenAPI document to an agent as a tool surface.
4
+ *
5
+ * The derivation is the SAME code the web builder runs —
6
+ * `validateAndParseOpenAPISpec` then `openapiToFunction`, both from
7
+ * `@skrr-ai/data-provider`. That matters more than it looks: the server stores
8
+ * `functions` verbatim and never re-reads the spec, so a CLI that derived them
9
+ * its own way would produce actions subtly unlike the ones the web produces from
10
+ * the same document, and the difference would only show up at call time.
11
+ *
12
+ * The spec is validated LOCALLY before anything is sent, because the endpoint's
13
+ * failure for a malformed document is `400 No functions provided` — true, and
14
+ * useless for finding the line that is wrong.
15
+ */
16
+ export default class AgentsApiActionsAdd extends BaseCommand {
17
+ static description: string;
18
+ static examples: string[];
19
+ static args: {
20
+ agentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
21
+ };
22
+ static flags: {
23
+ spec: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
24
+ 'action-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ auth: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
26
+ 'api-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
27
+ 'authorization-type': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
28
+ 'custom-auth-header': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
29
+ 'oauth-client-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
30
+ 'oauth-client-secret': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
31
+ 'oauth-authorization-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
32
+ 'oauth-client-url': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
33
+ 'oauth-scope': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
34
+ 'oauth-token-exchange-method': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
35
+ 'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
36
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
37
+ };
38
+ private readSpec;
39
+ private buildAuth;
40
+ run(): Promise<void>;
41
+ }
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const core_1 = require("@oclif/core");
4
+ const promises_1 = require("node:fs/promises");
5
+ const data_provider_1 = require("@skrr-ai/data-provider");
6
+ const base_command_1 = require("../../../base-command");
7
+ /**
8
+ * Attach (or re-attach) an OpenAPI document to an agent as a tool surface.
9
+ *
10
+ * The derivation is the SAME code the web builder runs —
11
+ * `validateAndParseOpenAPISpec` then `openapiToFunction`, both from
12
+ * `@skrr-ai/data-provider`. That matters more than it looks: the server stores
13
+ * `functions` verbatim and never re-reads the spec, so a CLI that derived them
14
+ * its own way would produce actions subtly unlike the ones the web produces from
15
+ * the same document, and the difference would only show up at call time.
16
+ *
17
+ * The spec is validated LOCALLY before anything is sent, because the endpoint's
18
+ * failure for a malformed document is `400 No functions provided` — true, and
19
+ * useless for finding the line that is wrong.
20
+ */
21
+ class AgentsApiActionsAdd extends base_command_1.BaseCommand {
22
+ static description = 'Attach an OpenAPI spec to an agent as a callable Action';
23
+ static examples = [
24
+ '<%= config.bin %> agents api-actions add <agent-id> --spec ./weather.yaml',
25
+ 'cat weather.json | <%= config.bin %> agents api-actions add <agent-id> --spec -',
26
+ '<%= config.bin %> agents api-actions add <agent-id> --spec ./api.yaml --auth service_http --api-key $KEY',
27
+ '<%= config.bin %> agents api-actions add <agent-id> --spec ./api.yaml --action-id <existing> # replace in place',
28
+ ];
29
+ static args = {
30
+ agentId: core_1.Args.string({ description: 'Agent ID', required: true, ignoreStdin: true }),
31
+ };
32
+ static flags = {
33
+ spec: core_1.Flags.string({
34
+ description: 'OpenAPI document — path to a JSON/YAML file, or "-" for stdin',
35
+ required: true,
36
+ }),
37
+ 'action-id': core_1.Flags.string({
38
+ description: 'Replace this existing action instead of creating a new one',
39
+ }),
40
+ auth: core_1.Flags.string({
41
+ description: 'How the API authenticates',
42
+ options: [data_provider_1.AuthTypeEnum.None, data_provider_1.AuthTypeEnum.ServiceHttp, data_provider_1.AuthTypeEnum.OAuth],
43
+ default: data_provider_1.AuthTypeEnum.None,
44
+ }),
45
+ 'api-key': core_1.Flags.string({ description: '--auth service_http: the key or token' }),
46
+ 'authorization-type': core_1.Flags.string({
47
+ description: '--auth service_http: how the key is presented',
48
+ options: [
49
+ data_provider_1.AuthorizationTypeEnum.Bearer,
50
+ data_provider_1.AuthorizationTypeEnum.Basic,
51
+ data_provider_1.AuthorizationTypeEnum.Custom,
52
+ ],
53
+ }),
54
+ 'custom-auth-header': core_1.Flags.string({
55
+ description: '--authorization-type custom: the header name',
56
+ }),
57
+ 'oauth-client-id': core_1.Flags.string({ description: '--auth oauth: client id' }),
58
+ 'oauth-client-secret': core_1.Flags.string({ description: '--auth oauth: client secret' }),
59
+ 'oauth-authorization-url': core_1.Flags.string({ description: '--auth oauth: authorization URL' }),
60
+ 'oauth-client-url': core_1.Flags.string({ description: '--auth oauth: token URL' }),
61
+ 'oauth-scope': core_1.Flags.string({ description: '--auth oauth: space-separated scopes' }),
62
+ 'oauth-token-exchange-method': core_1.Flags.string({
63
+ description: '--auth oauth: how the token is exchanged',
64
+ options: [data_provider_1.TokenExchangeMethodEnum.DefaultPost, data_provider_1.TokenExchangeMethodEnum.BasicAuthHeader],
65
+ }),
66
+ 'dry-run': core_1.Flags.boolean({
67
+ description: 'Parse the spec and report the functions it yields, send nothing',
68
+ }),
69
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
70
+ };
71
+ async readSpec(source) {
72
+ if (source === '-') {
73
+ const chunks = [];
74
+ for await (const chunk of process.stdin)
75
+ chunks.push(Buffer.from(chunk));
76
+ return Buffer.concat(chunks).toString('utf8');
77
+ }
78
+ return (0, promises_1.readFile)(source, 'utf8');
79
+ }
80
+ buildAuth(flags) {
81
+ const type = flags.auth;
82
+ if (type === data_provider_1.AuthTypeEnum.ServiceHttp) {
83
+ if (!flags['api-key']) {
84
+ this.error('--auth service_http needs --api-key.', { exit: 1 });
85
+ }
86
+ if (flags['authorization-type'] === data_provider_1.AuthorizationTypeEnum.Custom &&
87
+ !flags['custom-auth-header']) {
88
+ this.error('--authorization-type custom needs --custom-auth-header.', { exit: 1 });
89
+ }
90
+ return {
91
+ api_key: String(flags['api-key']),
92
+ auth: {
93
+ type,
94
+ authorization_type: flags['authorization-type'] ?? data_provider_1.AuthorizationTypeEnum.Bearer,
95
+ ...(flags['custom-auth-header'] === undefined
96
+ ? {}
97
+ : { custom_auth_header: String(flags['custom-auth-header']) }),
98
+ },
99
+ };
100
+ }
101
+ if (type === data_provider_1.AuthTypeEnum.OAuth) {
102
+ const missing = [
103
+ ['--oauth-client-id', flags['oauth-client-id']],
104
+ ['--oauth-client-secret', flags['oauth-client-secret']],
105
+ ['--oauth-authorization-url', flags['oauth-authorization-url']],
106
+ ['--oauth-client-url', flags['oauth-client-url']],
107
+ ]
108
+ .filter(([, value]) => !value)
109
+ .map(([name]) => name);
110
+ if (missing.length > 0) {
111
+ this.error(`--auth oauth needs ${missing.join(', ')}.`, { exit: 1 });
112
+ }
113
+ return {
114
+ oauth_client_id: String(flags['oauth-client-id']),
115
+ oauth_client_secret: String(flags['oauth-client-secret']),
116
+ auth: {
117
+ type,
118
+ authorization_url: String(flags['oauth-authorization-url']),
119
+ client_url: String(flags['oauth-client-url']),
120
+ ...(flags['oauth-scope'] === undefined ? {} : { scope: String(flags['oauth-scope']) }),
121
+ token_exchange_method: flags['oauth-token-exchange-method'] ??
122
+ data_provider_1.TokenExchangeMethodEnum.DefaultPost,
123
+ },
124
+ };
125
+ }
126
+ return { auth: { type: data_provider_1.AuthTypeEnum.None } };
127
+ }
128
+ async run() {
129
+ this.requireAuth();
130
+ const { args, flags } = await this.parse(AgentsApiActionsAdd);
131
+ let rawSpec;
132
+ try {
133
+ rawSpec = await this.readSpec(flags.spec);
134
+ }
135
+ catch (err) {
136
+ this.error(`Could not read --spec ${flags.spec}: ${err.message}`, { exit: 1 });
137
+ }
138
+ const validation = (0, data_provider_1.validateAndParseOpenAPISpec)(rawSpec);
139
+ if (!validation.status || !validation.spec) {
140
+ this.error(`The OpenAPI document is not usable: ${validation.message}`, { exit: 1 });
141
+ }
142
+ const { functionSignatures, requestBuilders } = (0, data_provider_1.openapiToFunction)(validation.spec);
143
+ const functions = functionSignatures.map((signature) => signature.toObjectTool());
144
+ if (functions.length === 0) {
145
+ this.error('The spec parsed but yielded no callable operations. Every path needs an ' +
146
+ 'operationId and a method the parser understands.', { exit: 1 });
147
+ }
148
+ const first = Object.values(requestBuilders)[0];
149
+ if (!first?.domain) {
150
+ this.error('The spec has no server URL to call — `servers[0].url` is required.', { exit: 1 });
151
+ }
152
+ let domain;
153
+ try {
154
+ domain = new URL(first.domain).hostname;
155
+ }
156
+ catch {
157
+ this.error(`The spec's server URL is not a URL: ${first.domain}`, { exit: 1 });
158
+ }
159
+ if (flags['dry-run']) {
160
+ const preview = {
161
+ domain: domain,
162
+ functions: Object.entries(requestBuilders).map(([name, props]) => ({
163
+ name,
164
+ method: props.method,
165
+ path: props.path,
166
+ })),
167
+ };
168
+ this.log(flags.json
169
+ ? JSON.stringify(preview, null, 2)
170
+ : `${preview.functions.length} operation(s) on ${domain}:\n` +
171
+ preview.functions
172
+ .map((f) => ` ${f.name} ${f.method.toUpperCase()} ${f.path}`)
173
+ .join('\n'));
174
+ return;
175
+ }
176
+ const metadata = {
177
+ raw_spec: rawSpec,
178
+ domain: domain,
179
+ ...this.buildAuth(flags),
180
+ };
181
+ let result;
182
+ try {
183
+ result = await data_provider_1.dataService.updateAgentAction({
184
+ agent_id: args.agentId,
185
+ ...(flags['action-id'] === undefined ? {} : { action_id: flags['action-id'] }),
186
+ metadata,
187
+ functions,
188
+ });
189
+ }
190
+ catch (err) {
191
+ this.handleApiError(err);
192
+ }
193
+ if (flags.json) {
194
+ this.log(this.agentJson(args.agentId, result));
195
+ return;
196
+ }
197
+ this.log(`${flags['action-id'] ? 'Updated' : 'Added'} an OpenAPI action on agent ${args.agentId} — ` +
198
+ `${functions.length} operation(s) on ${domain}`);
199
+ this.printAgentUrl(args.agentId);
200
+ }
201
+ }
202
+ exports.default = AgentsApiActionsAdd;
@@ -0,0 +1,28 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ /**
3
+ * OpenAPI-spec-backed Actions — an agent calling a third-party HTTP API.
4
+ *
5
+ * WHY THE COMMAND IS NOT CALLED `actions`
6
+ * ───────────────────────────────────────
7
+ * Three different things in this product are called an "action", and two of
8
+ * them already own that word in the CLI:
9
+ *
10
+ * skrr agents actions — embedded `agentActions`: prompt/builtin buttons
11
+ * that live ON the agent document
12
+ * skrr actions — marketplace LISTINGS of those embedded actions
13
+ * skrr agents api-actions (this) — `/api/agents/actions`: a tool surface
14
+ * generated from an OpenAPI document
15
+ *
16
+ * The third had no CLI at all, which the naming collision helped hide. Renaming
17
+ * the other two would break muscle memory for a surface that works, so this one
18
+ * takes an unambiguous name and all three now say which concept they are.
19
+ */
20
+ export default class AgentsApiActionsList extends BaseCommand {
21
+ static description: string;
22
+ static examples: string[];
23
+ static flags: {
24
+ agent: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
25
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
26
+ };
27
+ run(): Promise<void>;
28
+ }
@@ -0,0 +1,77 @@
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
+ /**
8
+ * OpenAPI-spec-backed Actions — an agent calling a third-party HTTP API.
9
+ *
10
+ * WHY THE COMMAND IS NOT CALLED `actions`
11
+ * ───────────────────────────────────────
12
+ * Three different things in this product are called an "action", and two of
13
+ * them already own that word in the CLI:
14
+ *
15
+ * skrr agents actions — embedded `agentActions`: prompt/builtin buttons
16
+ * that live ON the agent document
17
+ * skrr actions — marketplace LISTINGS of those embedded actions
18
+ * skrr agents api-actions (this) — `/api/agents/actions`: a tool surface
19
+ * generated from an OpenAPI document
20
+ *
21
+ * The third had no CLI at all, which the naming collision helped hide. Renaming
22
+ * the other two would break muscle memory for a surface that works, so this one
23
+ * takes an unambiguous name and all three now say which concept they are.
24
+ */
25
+ class AgentsApiActionsList extends base_command_1.BaseCommand {
26
+ static description = 'List OpenAPI-backed Actions on agents you can edit (NOT `agents actions`, which is embedded buttons)';
27
+ static examples = [
28
+ '<%= config.bin %> agents api-actions',
29
+ '<%= config.bin %> agents api-actions --agent <agent-id>',
30
+ '<%= config.bin %> agents api-actions --json',
31
+ ];
32
+ static flags = {
33
+ agent: core_1.Flags.string({ description: 'Only actions on this agent' }),
34
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
35
+ };
36
+ async run() {
37
+ this.requireAuth();
38
+ const { flags } = await this.parse(AgentsApiActionsList);
39
+ let actions;
40
+ try {
41
+ actions = await data_provider_1.dataService.getActions();
42
+ }
43
+ catch (err) {
44
+ this.handleApiError(err);
45
+ }
46
+ // Filtered here rather than server-side: the endpoint returns every action
47
+ // on every agent the caller may EDIT, and has no agent filter. Doing it in
48
+ // the CLI keeps the flag honest instead of inventing a query the API does
49
+ // not answer.
50
+ const rows = flags.agent
51
+ ? actions.filter((action) => action.agent_id === flags.agent)
52
+ : actions;
53
+ if (flags.json) {
54
+ this.log(JSON.stringify(rows, null, 2));
55
+ return;
56
+ }
57
+ if (rows.length === 0) {
58
+ this.log(flags.agent
59
+ ? `No OpenAPI actions on agent ${flags.agent}.`
60
+ : 'No OpenAPI actions on any agent you can edit.');
61
+ this.log('Add one with: skrr agents api-actions add <agent-id> --spec <openapi.yaml>');
62
+ return;
63
+ }
64
+ (0, format_1.renderTable)(rows.map((action) => ({
65
+ actionId: action.action_id,
66
+ agentId: action.agent_id ?? '-',
67
+ domain: action.metadata?.domain ?? '-',
68
+ auth: action.metadata?.auth?.type ?? 'none',
69
+ })), [
70
+ { key: 'actionId', header: 'ACTION ID', verbatim: true },
71
+ { key: 'agentId', header: 'AGENT ID', verbatim: true },
72
+ { key: 'domain', header: 'DOMAIN', maxWidth: 40 },
73
+ { key: 'auth', header: 'AUTH' },
74
+ ], (line) => this.log(line));
75
+ }
76
+ }
77
+ exports.default = AgentsApiActionsList;
@@ -0,0 +1,14 @@
1
+ import { BaseCommand } from '../../../base-command';
2
+ /** Detach an OpenAPI Action from an agent. Wraps `DELETE /api/agents/actions/:agent_id/:action_id`. */
3
+ export default class AgentsApiActionsRemove extends BaseCommand {
4
+ static description: string;
5
+ static examples: string[];
6
+ static args: {
7
+ agentId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
8
+ actionId: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
9
+ };
10
+ static flags: {
11
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ };
13
+ run(): Promise<void>;
14
+ }
@@ -0,0 +1,36 @@
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
+ /** Detach an OpenAPI Action from an agent. Wraps `DELETE /api/agents/actions/:agent_id/:action_id`. */
7
+ class AgentsApiActionsRemove extends base_command_1.BaseCommand {
8
+ static description = 'Remove an OpenAPI-backed Action from an agent';
9
+ static examples = ['<%= config.bin %> agents api-actions remove <agent-id> <action-id>'];
10
+ static args = {
11
+ agentId: core_1.Args.string({ description: 'Agent ID', required: true, ignoreStdin: true }),
12
+ actionId: core_1.Args.string({ description: 'Action ID', required: true, ignoreStdin: true }),
13
+ };
14
+ static flags = {
15
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
16
+ };
17
+ async run() {
18
+ this.requireAuth();
19
+ const { args, flags } = await this.parse(AgentsApiActionsRemove);
20
+ try {
21
+ await data_provider_1.dataService.deleteAgentAction({
22
+ agent_id: args.agentId,
23
+ action_id: args.actionId,
24
+ });
25
+ }
26
+ catch (err) {
27
+ this.handleApiError(err);
28
+ }
29
+ if (flags.json) {
30
+ this.log(JSON.stringify({ removed: args.actionId, agentId: args.agentId }, null, 2));
31
+ return;
32
+ }
33
+ this.log(`Removed action ${args.actionId} from agent ${args.agentId}`);
34
+ }
35
+ }
36
+ exports.default = AgentsApiActionsRemove;
@@ -0,0 +1,25 @@
1
+ import { BaseCommand } from '../../../../base-command';
2
+ /**
3
+ * Apply the policy to agents that ALREADY EXIST — the one retroactive path in
4
+ * the avatar system, and deliberately user-initiated.
5
+ *
6
+ * It is not a sweep over everything: an agent whose owner explicitly chose the
7
+ * platform logo stores `{type:'default'}` and is NOT eligible, while an agent
8
+ * that never had a face stores nothing and is. "Never chose" and "chose the
9
+ * logo" are different facts and the server keeps them apart.
10
+ *
11
+ * The count is shown BEFORE anything is written. `--dry-run` asks the server how
12
+ * many are eligible without touching them; without `--yes` that is what this
13
+ * command does first, then asks. A command that silently re-skinned an unknown
14
+ * number of agents would be the wrong shape for an irreversible bulk write.
15
+ */
16
+ export default class AgentsAvatarDefaultApply extends BaseCommand {
17
+ static description: string;
18
+ static examples: string[];
19
+ static flags: {
20
+ 'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
21
+ yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
22
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
+ };
24
+ run(): Promise<void>;
25
+ }
@@ -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
+ /**
7
+ * Apply the policy to agents that ALREADY EXIST — the one retroactive path in
8
+ * the avatar system, and deliberately user-initiated.
9
+ *
10
+ * It is not a sweep over everything: an agent whose owner explicitly chose the
11
+ * platform logo stores `{type:'default'}` and is NOT eligible, while an agent
12
+ * that never had a face stores nothing and is. "Never chose" and "chose the
13
+ * logo" are different facts and the server keeps them apart.
14
+ *
15
+ * The count is shown BEFORE anything is written. `--dry-run` asks the server how
16
+ * many are eligible without touching them; without `--yes` that is what this
17
+ * command does first, then asks. A command that silently re-skinned an unknown
18
+ * number of agents would be the wrong shape for an irreversible bulk write.
19
+ */
20
+ class AgentsAvatarDefaultApply extends base_command_1.BaseCommand {
21
+ static description = 'Apply your default-avatar policy to existing agents that never had a face chosen';
22
+ static examples = [
23
+ '<%= config.bin %> agents avatar default apply --dry-run',
24
+ '<%= config.bin %> agents avatar default apply --yes',
25
+ ];
26
+ static flags = {
27
+ 'dry-run': core_1.Flags.boolean({ description: 'Report how many agents are eligible, write nothing' }),
28
+ yes: core_1.Flags.boolean({ description: 'Skip the eligible-count preview and write' }),
29
+ json: core_1.Flags.boolean({ description: 'Output as JSON' }),
30
+ };
31
+ async run() {
32
+ this.requireAuth();
33
+ const { flags } = await this.parse(AgentsAvatarDefaultApply);
34
+ const dryRun = flags['dry-run'] === true || flags.yes !== true;
35
+ let result;
36
+ try {
37
+ result = await data_provider_1.dataService.applyAgentAvatarDefault(dryRun);
38
+ }
39
+ catch (err) {
40
+ this.handleApiError(err);
41
+ }
42
+ if (flags.json) {
43
+ this.log(JSON.stringify(result, null, 2));
44
+ return;
45
+ }
46
+ if (!dryRun) {
47
+ this.log(`Applied the default-avatar policy to ${result.updated} agent(s).`);
48
+ return;
49
+ }
50
+ this.log(`${result.eligible} agent(s) would get a new avatar. Nothing was written.`);
51
+ if (!flags['dry-run']) {
52
+ this.log('Re-run with --yes to apply.');
53
+ }
54
+ }
55
+ }
56
+ exports.default = AgentsAvatarDefaultApply;