@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.
- package/README.md +17 -4
- package/dist/commands/agents/actions/create.d.ts +5 -0
- package/dist/commands/agents/actions/create.js +26 -0
- package/dist/commands/agents/actions/update.d.ts +5 -0
- package/dist/commands/agents/actions/update.js +24 -0
- package/dist/commands/agents/api-actions/add.d.ts +41 -0
- package/dist/commands/agents/api-actions/add.js +202 -0
- package/dist/commands/agents/api-actions/index.d.ts +28 -0
- package/dist/commands/agents/api-actions/index.js +77 -0
- package/dist/commands/agents/api-actions/remove.d.ts +14 -0
- package/dist/commands/agents/api-actions/remove.js +36 -0
- package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
- package/dist/commands/agents/avatar/default/apply.js +56 -0
- package/dist/commands/agents/avatar/default/index.d.ts +18 -0
- package/dist/commands/agents/avatar/default/index.js +44 -0
- package/dist/commands/agents/avatar/default/set.d.ts +23 -0
- package/dist/commands/agents/avatar/default/set.js +95 -0
- package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
- package/dist/commands/agents/avatar/library/delete.js +47 -0
- package/dist/commands/agents/avatar/library/index.d.ts +16 -0
- package/dist/commands/agents/avatar/library/index.js +56 -0
- package/dist/commands/agents/avatar/presets.d.ts +19 -0
- package/dist/commands/agents/avatar/presets.js +56 -0
- package/dist/commands/agents/categories/create.d.ts +14 -0
- package/dist/commands/agents/categories/create.js +46 -0
- package/dist/commands/agents/categories/delete.d.ts +13 -0
- package/dist/commands/agents/categories/delete.js +33 -0
- package/dist/commands/agents/categories/index.d.ts +20 -0
- package/dist/commands/agents/categories/index.js +82 -0
- package/dist/commands/agents/categories/update.d.ts +22 -0
- package/dist/commands/agents/categories/update.js +59 -0
- package/dist/commands/agents/create.d.ts +10 -0
- package/dist/commands/agents/create.js +57 -3
- package/dist/commands/agents/ensure-default.d.ts +27 -0
- package/dist/commands/agents/ensure-default.js +65 -0
- package/dist/commands/agents/mute.d.ts +16 -0
- package/dist/commands/agents/mute.js +38 -0
- package/dist/commands/agents/pin.d.ts +16 -0
- package/dist/commands/agents/pin.js +38 -0
- package/dist/commands/agents/tools/auth.d.ts +19 -0
- package/dist/commands/agents/tools/auth.js +41 -0
- package/dist/commands/agents/tools/calls.d.ts +18 -0
- package/dist/commands/agents/tools/calls.js +54 -0
- package/dist/commands/agents/tools/index.d.ts +20 -0
- package/dist/commands/agents/tools/index.js +77 -0
- package/dist/commands/agents/unmute.d.ts +16 -0
- package/dist/commands/agents/unmute.js +38 -0
- package/dist/commands/agents/unpin.d.ts +16 -0
- package/dist/commands/agents/unpin.js +38 -0
- package/dist/commands/agents/update.d.ts +12 -0
- package/dist/commands/agents/update.js +64 -3
- package/dist/commands/followups/act.d.ts +22 -0
- package/dist/commands/followups/act.js +102 -0
- package/dist/commands/followups/cancel.d.ts +17 -0
- package/dist/commands/followups/cancel.js +40 -0
- package/dist/commands/followups/checkin.d.ts +27 -0
- package/dist/commands/followups/checkin.js +107 -0
- package/dist/commands/followups/list.d.ts +24 -0
- package/dist/commands/followups/list.js +90 -0
- package/dist/commands/followups/remind.d.ts +26 -0
- package/dist/commands/followups/remind.js +106 -0
- package/dist/commands/followups/reschedule.d.ts +15 -0
- package/dist/commands/followups/reschedule.js +48 -0
- package/dist/commands/followups/resolve.d.ts +23 -0
- package/dist/commands/followups/resolve.js +54 -0
- package/dist/commands/followups/show.d.ts +12 -0
- package/dist/commands/followups/show.js +45 -0
- package/dist/commands/followups/watch.d.ts +51 -0
- package/dist/commands/followups/watch.js +207 -0
- package/dist/commands/goals/labels/add.js +19 -2
- package/dist/commands/goals/labels/remove.js +22 -2
- package/dist/commands/labels/list.d.ts +24 -1
- package/dist/commands/labels/list.js +62 -19
- package/dist/commands/memory/governance/index.d.ts +21 -0
- package/dist/commands/memory/governance/index.js +64 -0
- package/dist/commands/memory/governance/set.d.ts +24 -0
- package/dist/commands/memory/governance/set.js +95 -0
- package/dist/commands/memory/provenance.d.ts +18 -0
- package/dist/commands/memory/provenance.js +66 -0
- package/dist/commands/spaces/create.d.ts +3 -0
- package/dist/commands/spaces/create.js +32 -2
- package/dist/commands/spaces/labels/add.js +19 -2
- package/dist/commands/spaces/labels/remove.js +22 -2
- package/dist/commands/spaces/show.js +2 -0
- package/dist/commands/spaces/update.d.ts +5 -0
- package/dist/commands/spaces/update.js +41 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +45 -0
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +8 -1
- package/dist/commands/tasks/create.d.ts +3 -0
- package/dist/commands/tasks/create.js +34 -2
- package/dist/commands/tasks/expectations/assess.d.ts +11 -0
- package/dist/commands/tasks/expectations/assess.js +85 -14
- package/dist/commands/tasks/expectations.js +19 -2
- package/dist/commands/tasks/labels/attach.js +20 -3
- package/dist/commands/tasks/labels/detach.js +21 -3
- package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
- package/dist/commands/tasks/lifecycle/attach.js +47 -0
- package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/definitions.js +40 -0
- package/dist/commands/tasks/lifecycle/detach.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/detach.js +32 -0
- package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
- package/dist/commands/tasks/lifecycle/history.js +38 -0
- package/dist/commands/tasks/lifecycle/migrate.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/migrate.js +29 -0
- package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
- package/dist/commands/tasks/lifecycle/reopen.d.ts +13 -0
- package/dist/commands/tasks/lifecycle/reopen.js +34 -0
- package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/show.js +27 -0
- package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/start.js +30 -0
- package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
- package/dist/commands/tasks/lifecycle/transition.js +78 -0
- package/dist/commands/tasks/move.d.ts +1 -0
- package/dist/commands/tasks/move.js +31 -0
- package/dist/commands/tasks/result/submit.js +11 -1
- package/dist/commands/tasks/review-queue.d.ts +29 -0
- package/dist/commands/tasks/review-queue.js +165 -0
- package/dist/commands/tasks/show.js +42 -0
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +47 -0
- package/dist/lib/agent-actions.d.ts +36 -10
- package/dist/lib/agent-actions.js +63 -9
- package/dist/lib/agent-config.d.ts +11 -0
- package/dist/lib/agent-config.js +85 -3
- package/dist/lib/agent-pin-mute.d.ts +24 -0
- package/dist/lib/agent-pin-mute.js +17 -0
- package/dist/lib/agent-visual-refs.d.ts +6 -0
- package/dist/lib/agent-visual-refs.js +142 -0
- package/dist/lib/first-party-harness-agent.js +7 -0
- package/dist/lib/followups.d.ts +107 -0
- package/dist/lib/followups.js +102 -0
- package/dist/lib/label-ref.d.ts +95 -0
- package/dist/lib/label-ref.js +163 -0
- package/dist/lib/label-scope.d.ts +2 -2
- package/dist/lib/label-scope.js +3 -3
- package/dist/lib/task-closure.d.ts +32 -0
- package/dist/lib/task-closure.js +106 -0
- package/dist/lib/task-lifecycle-output.d.ts +14 -0
- package/dist/lib/task-lifecycle-output.js +101 -0
- package/dist/lib/tasks.d.ts +3 -0
- package/dist/lib/tasks.js +31 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5079 -4546
- package/oclif.manifest.json +20216 -16002
- 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`, `--
|
|
843
|
-
`--
|
|
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`, `--
|
|
856
|
-
`--
|
|
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;
|