@skrr-ai/cli 0.1.37 → 0.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/dev-fallback.js +167 -4
- package/dist/base-command.js +46 -2
- package/dist/commands/agents/actions/create.js +18 -7
- package/dist/commands/agents/actions/delete.d.ts +1 -0
- package/dist/commands/agents/actions/delete.js +7 -0
- package/dist/commands/agents/actions/update.js +5 -3
- package/dist/commands/agents/api-actions/add.js +5 -2
- package/dist/commands/agents/api-actions/index.d.ts +11 -0
- package/dist/commands/agents/api-actions/index.js +27 -1
- package/dist/commands/agents/avatar/default/index.d.ts +11 -0
- package/dist/commands/agents/avatar/default/index.js +17 -0
- package/dist/commands/agents/avatar/default/set.d.ts +2 -1
- package/dist/commands/agents/avatar/default/set.js +32 -7
- package/dist/commands/agents/avatar/upload.js +7 -1
- package/dist/commands/agents/categories/delete.js +8 -0
- package/dist/commands/agents/categories/index.d.ts +21 -5
- package/dist/commands/agents/categories/index.js +68 -15
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +94 -7
- package/dist/commands/agents/create.js +11 -4
- package/dist/commands/agents/list.d.ts +15 -0
- package/dist/commands/agents/list.js +31 -1
- package/dist/commands/agents/scene-background/upload.d.ts +30 -0
- package/dist/commands/agents/scene-background/upload.js +97 -0
- package/dist/commands/agents/show.js +13 -0
- package/dist/commands/agents/tools/calls.d.ts +23 -5
- package/dist/commands/agents/tools/calls.js +81 -18
- package/dist/commands/agents/update.js +15 -5
- package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
- package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
- package/dist/commands/convos/messages.d.ts +13 -0
- package/dist/commands/convos/messages.js +40 -16
- package/dist/commands/daemon/index.js +8 -1
- package/dist/commands/daemon/logs.d.ts +26 -0
- package/dist/commands/daemon/logs.js +56 -0
- package/dist/commands/daemon/uninstall.js +1 -1
- package/dist/commands/followups/act.js +3 -2
- package/dist/commands/followups/cancel.d.ts +6 -3
- package/dist/commands/followups/cancel.js +16 -6
- package/dist/commands/followups/observability.d.ts +23 -0
- package/dist/commands/followups/observability.js +114 -0
- package/dist/commands/followups/reschedule.js +1 -1
- package/dist/commands/followups/resolve.js +3 -3
- package/dist/commands/followups/show.js +2 -1
- package/dist/commands/followups/watch.js +9 -5
- package/dist/commands/harnesses/forget.js +28 -0
- package/dist/commands/harnesses/install.d.ts +41 -0
- package/dist/commands/harnesses/install.js +165 -0
- package/dist/commands/harnesses/installers.d.ts +45 -0
- package/dist/commands/harnesses/installers.js +155 -0
- package/dist/commands/harnesses/list.d.ts +82 -1
- package/dist/commands/harnesses/list.js +104 -12
- package/dist/commands/harnesses/models.js +10 -1
- package/dist/commands/harnesses/show.d.ts +15 -0
- package/dist/commands/harnesses/show.js +44 -3
- package/dist/commands/harnesses/update.js +1 -1
- package/dist/commands/harnesses/usage.d.ts +25 -0
- package/dist/commands/harnesses/usage.js +24 -2
- package/dist/commands/instructions/status.js +13 -1
- package/dist/commands/machines/dedicated/catalog.js +4 -15
- package/dist/commands/machines/dedicated/create.d.ts +8 -0
- package/dist/commands/machines/dedicated/create.js +58 -1
- package/dist/commands/machines/dedicated/destroy.js +18 -4
- package/dist/commands/machines/dedicated/list.js +9 -6
- package/dist/commands/machines/hosted/list.js +12 -0
- package/dist/commands/machines/list.js +11 -0
- package/dist/commands/machines/show.d.ts +1 -0
- package/dist/commands/machines/show.js +40 -11
- package/dist/commands/profiles/list.d.ts +23 -0
- package/dist/commands/profiles/list.js +96 -0
- package/dist/commands/search/skills.d.ts +11 -1
- package/dist/commands/search/skills.js +26 -8
- package/dist/commands/skills/details.d.ts +2 -0
- package/dist/commands/skills/details.js +24 -1
- package/dist/commands/skills/import-as-actions.d.ts +32 -0
- package/dist/commands/skills/import-as-actions.js +175 -0
- package/dist/commands/skills/install.d.ts +2 -0
- package/dist/commands/skills/install.js +24 -1
- package/dist/commands/skills/invocable.js +6 -2
- package/dist/commands/skills/local.d.ts +40 -0
- package/dist/commands/skills/local.js +160 -0
- package/dist/commands/skills/search.d.ts +11 -1
- package/dist/commands/skills/search.js +29 -8
- package/dist/commands/spaces/actions/add.js +23 -5
- package/dist/commands/spaces/actions/available.js +3 -0
- package/dist/commands/spaces/actions/list.d.ts +5 -0
- package/dist/commands/spaces/actions/list.js +49 -3
- package/dist/commands/spaces/actions/run.d.ts +28 -0
- package/dist/commands/spaces/actions/run.js +146 -0
- package/dist/commands/spaces/actions/update.js +27 -5
- package/dist/commands/spaces/label-summaries.d.ts +27 -0
- package/dist/commands/spaces/label-summaries.js +64 -0
- package/dist/commands/spaces/task-rollups.d.ts +5 -0
- package/dist/commands/spaces/task-rollups.js +15 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +63 -3
- package/dist/commands/tasks/actions/attach.js +32 -7
- package/dist/commands/tasks/complete.js +13 -0
- package/dist/commands/tasks/create.js +1 -1
- package/dist/commands/tasks/events/append.js +29 -6
- package/dist/commands/tasks/expectations/assess.d.ts +1 -0
- package/dist/commands/tasks/expectations/assess.js +43 -5
- package/dist/commands/tasks/expectations.js +77 -16
- package/dist/commands/tasks/follow-up.js +2 -2
- package/dist/commands/tasks/lifecycle/definitions.js +21 -2
- package/dist/commands/tasks/lifecycle/detach.d.ts +7 -0
- package/dist/commands/tasks/lifecycle/detach.js +43 -3
- package/dist/commands/tasks/lifecycle/migrate.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/migrate.js +42 -3
- package/dist/commands/tasks/lifecycle/reopen.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/reopen.js +40 -3
- package/dist/commands/tasks/lifecycle/transition.js +33 -2
- package/dist/commands/tasks/list.js +16 -9
- package/dist/commands/tasks/move.js +11 -13
- package/dist/commands/tasks/review-queue.d.ts +15 -0
- package/dist/commands/tasks/review-queue.js +180 -31
- package/dist/commands/tasks/show.d.ts +11 -0
- package/dist/commands/tasks/show.js +105 -12
- package/dist/commands/tasks/trust.js +7 -2
- package/dist/commands/tasks/update.js +46 -10
- package/dist/commands/tasks/updates/add.js +1 -1
- package/dist/commands/token/list.d.ts +22 -0
- package/dist/commands/token/list.js +68 -0
- package/dist/commands/token/revoke.d.ts +23 -0
- package/dist/commands/token/revoke.js +53 -0
- package/dist/lib/agent-actions.d.ts +57 -2
- package/dist/lib/agent-actions.js +113 -21
- package/dist/lib/agent-pin-mute.d.ts +10 -5
- package/dist/lib/agent-pin-mute.js +17 -4
- package/dist/lib/agent-visual-refs.d.ts +27 -0
- package/dist/lib/agent-visual-refs.js +127 -2
- package/dist/lib/agentic-stream.d.ts +6 -0
- package/dist/lib/agentic-stream.js +34 -3
- package/dist/lib/assignee-resolver.d.ts +1 -1
- package/dist/lib/assignee-resolver.js +8 -0
- package/dist/lib/bulk-task-targets.d.ts +12 -0
- package/dist/lib/bulk-task-targets.js +34 -1
- package/dist/lib/cli-installers.d.ts +130 -0
- package/dist/lib/cli-installers.js +145 -0
- package/dist/lib/command-miss.js +55 -7
- package/dist/lib/dedicated-lease-command.d.ts +13 -0
- package/dist/lib/dedicated-lease-command.js +22 -1
- package/dist/lib/dedicated-machines.d.ts +95 -1
- package/dist/lib/dedicated-machines.js +236 -2
- package/dist/lib/failed-lookup.d.ts +3 -0
- package/dist/lib/failed-lookup.js +40 -0
- package/dist/lib/first-party-harness-agent.js +9 -2
- package/dist/lib/first-party-harness-doctor.d.ts +15 -0
- package/dist/lib/first-party-harness-doctor.js +126 -27
- package/dist/lib/followups.d.ts +14 -6
- package/dist/lib/followups.js +31 -6
- package/dist/lib/harnesses.d.ts +8 -0
- package/dist/lib/instruction-input.d.ts +19 -1
- package/dist/lib/instruction-input.js +52 -1
- package/dist/lib/label-scope.d.ts +15 -0
- package/dist/lib/label-scope.js +25 -5
- package/dist/lib/local-skills.d.ts +98 -0
- package/dist/lib/local-skills.js +195 -0
- package/dist/lib/machines.d.ts +10 -10
- package/dist/lib/machines.js +23 -1
- package/dist/lib/search-query.d.ts +19 -0
- package/dist/lib/search-query.js +35 -0
- package/dist/lib/space-custom-actions.d.ts +72 -0
- package/dist/lib/space-custom-actions.js +117 -0
- package/dist/lib/space-resolver.d.ts +1 -21
- package/dist/lib/space-resolver.js +19 -10
- package/dist/lib/task-closure.d.ts +3 -2
- package/dist/lib/task-closure.js +18 -20
- package/dist/lib/task-lifecycle-output.js +117 -9
- package/dist/lib/task-ref-resolver.d.ts +1 -17
- package/dist/lib/task-ref-resolver.js +18 -8
- package/dist/lib/tasks.js +9 -3
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5076 -4947
- package/oclif.manifest.json +26635 -25649
- package/package.json +9 -3
package/bin/dev-fallback.js
CHANGED
|
@@ -48,6 +48,116 @@ function sourceTreeDigest(fileSystem, sourceRoot) {
|
|
|
48
48
|
return hash.digest('hex');
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Every relative specifier a source imports, re-exports, or dynamically loads.
|
|
53
|
+
*
|
|
54
|
+
* Deliberately a scan rather than a parse: this runs before the CLI starts, so
|
|
55
|
+
* it may not cost a TypeScript program, and over-collecting is harmless — an
|
|
56
|
+
* extra file in the closure can only make the guard more conservative, never
|
|
57
|
+
* less.
|
|
58
|
+
*/
|
|
59
|
+
function relativeSpecifiers(text) {
|
|
60
|
+
const found = [];
|
|
61
|
+
const patterns = [
|
|
62
|
+
/(?:^|[\s;}])(?:import|export)[\s\S]{0,400}?from\s*['"](\.[^'"]*)['"]/g,
|
|
63
|
+
/\bimport\s*\(\s*['"](\.[^'"]*)['"]\s*\)/g,
|
|
64
|
+
/\brequire\s*\(\s*['"](\.[^'"]*)['"]\s*\)/g,
|
|
65
|
+
/(?:^|[\s;}])import\s+['"](\.[^'"]*)['"]/g,
|
|
66
|
+
];
|
|
67
|
+
for (const pattern of patterns) {
|
|
68
|
+
let match;
|
|
69
|
+
while ((match = pattern.exec(text)) !== null) found.push(match[1]);
|
|
70
|
+
}
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Resolve a relative specifier the way tsc does, extensionless first. */
|
|
75
|
+
function resolveSourceSpecifier(fileSystem, fromDirectory, specifier) {
|
|
76
|
+
const base = path.resolve(fromDirectory, specifier);
|
|
77
|
+
const candidates = [
|
|
78
|
+
base,
|
|
79
|
+
`${base}.ts`,
|
|
80
|
+
`${base}.tsx`,
|
|
81
|
+
`${base}.json`,
|
|
82
|
+
path.join(base, 'index.ts'),
|
|
83
|
+
path.join(base, 'index.tsx'),
|
|
84
|
+
];
|
|
85
|
+
for (const candidate of candidates) {
|
|
86
|
+
try {
|
|
87
|
+
if (fileSystem.statSync(candidate).isFile()) return candidate;
|
|
88
|
+
} catch {
|
|
89
|
+
// try the next shape
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The digest of everything a single command is compiled FROM: its own source
|
|
97
|
+
* plus the transitive closure of the relative imports it reaches.
|
|
98
|
+
*
|
|
99
|
+
* This replaces a digest over the whole of `src` as the freshness test for one
|
|
100
|
+
* command, and the difference is not an optimisation — it is the difference
|
|
101
|
+
* between a true statement and a false one. The whole-tree digest answers "has
|
|
102
|
+
* anything in the CLI changed", and that was used to answer "is THIS command's
|
|
103
|
+
* build current". In a checkout where another session is editing a different
|
|
104
|
+
* command — routine here, see root CLAUDE.md on ~35 worktrees sharing one
|
|
105
|
+
* checkout — those answers disagree constantly, and the launcher then refuses a
|
|
106
|
+
* command whose own build it can prove is byte-current, or silently delegates it
|
|
107
|
+
* to whatever older CLI is on PATH. A dogfood run spent its first twenty minutes
|
|
108
|
+
* concluding that a shipped feature had not shipped, because the commands under
|
|
109
|
+
* test were being answered by a build that predated them.
|
|
110
|
+
*
|
|
111
|
+
* Commands do import other commands (`tasks update` imports `tasks create`), so
|
|
112
|
+
* the closure is walked rather than assuming command sources are independent —
|
|
113
|
+
* that assumption is false here, and a guard built on it would call a genuinely
|
|
114
|
+
* stale command fresh, which is the failure worth avoiding.
|
|
115
|
+
*
|
|
116
|
+
* An unresolvable specifier is hashed as its own text. The build script and this
|
|
117
|
+
* launcher run this same function, so they agree on that value; and a specifier
|
|
118
|
+
* that starts resolving later changes the digest, which is the correct verdict.
|
|
119
|
+
*/
|
|
120
|
+
function commandClosureDigest(fileSystem, sourceRoot, entrySource) {
|
|
121
|
+
const seen = new Set();
|
|
122
|
+
const unresolved = [];
|
|
123
|
+
const pending = [path.resolve(entrySource)];
|
|
124
|
+
while (pending.length) {
|
|
125
|
+
const current = pending.pop();
|
|
126
|
+
if (seen.has(current)) continue;
|
|
127
|
+
seen.add(current);
|
|
128
|
+
let text;
|
|
129
|
+
try {
|
|
130
|
+
text = fileSystem.readFileSync(current, 'utf8');
|
|
131
|
+
} catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
for (const specifier of relativeSpecifiers(text)) {
|
|
135
|
+
const resolved = resolveSourceSpecifier(fileSystem, path.dirname(current), specifier);
|
|
136
|
+
if (resolved) {
|
|
137
|
+
if (!seen.has(resolved)) pending.push(resolved);
|
|
138
|
+
} else {
|
|
139
|
+
unresolved.push(`${path.relative(sourceRoot, current)}:${specifier}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const hash = crypto.createHash('sha256');
|
|
144
|
+
for (const file of [...seen].sort()) {
|
|
145
|
+
hash.update(path.relative(sourceRoot, file).split(path.sep).join('/'));
|
|
146
|
+
hash.update('\0');
|
|
147
|
+
try {
|
|
148
|
+
hash.update(fileSystem.readFileSync(file));
|
|
149
|
+
} catch {
|
|
150
|
+
hash.update('<unreadable>');
|
|
151
|
+
}
|
|
152
|
+
hash.update('\0');
|
|
153
|
+
}
|
|
154
|
+
for (const miss of unresolved.sort()) {
|
|
155
|
+
hash.update(miss.split(path.sep).join('/'));
|
|
156
|
+
hash.update('\0');
|
|
157
|
+
}
|
|
158
|
+
return hash.digest('hex');
|
|
159
|
+
}
|
|
160
|
+
|
|
51
161
|
function findAlternateCli({
|
|
52
162
|
commandName,
|
|
53
163
|
currentEntry,
|
|
@@ -143,9 +253,17 @@ function missingLocalCommandBuild({ cliRoot, argv, fileSystem = fs, verifySource
|
|
|
143
253
|
} catch {
|
|
144
254
|
commandBuildManifest = null;
|
|
145
255
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
256
|
+
// Lazily, because the closure test below almost always settles the question
|
|
257
|
+
// first and this one reads every `.ts` under `src` — 1,300 files here, on a
|
|
258
|
+
// path that runs before any command starts.
|
|
259
|
+
let sourceTreeDigestCache;
|
|
260
|
+
const currentSourceTreeDigest = () => {
|
|
261
|
+
if (!commandBuildManifest) return null;
|
|
262
|
+
if (sourceTreeDigestCache === undefined) {
|
|
263
|
+
sourceTreeDigestCache = sourceTreeDigest(fileSystem, path.join(cliRoot, 'src'));
|
|
264
|
+
}
|
|
265
|
+
return sourceTreeDigestCache;
|
|
266
|
+
};
|
|
149
267
|
const commandParts = [];
|
|
150
268
|
for (const value of argv) {
|
|
151
269
|
if (String(value).startsWith('-')) break;
|
|
@@ -165,11 +283,26 @@ function missingLocalCommandBuild({ cliRoot, argv, fileSystem = fs, verifySource
|
|
|
165
283
|
if (!verifySourceIdentity) return null;
|
|
166
284
|
try {
|
|
167
285
|
const relative = path.relative(sourceCommandsDirectory, source).split(path.sep).join('/');
|
|
286
|
+
// What this command is actually compiled from: its own source plus the
|
|
287
|
+
// transitive closure of its relative imports. Scoped to the command
|
|
288
|
+
// because a change to an unrelated one cannot reach it, and walked rather
|
|
289
|
+
// than assumed because commands here do import each other.
|
|
290
|
+
const builtClosure = commandBuildManifest?.closures?.[relative];
|
|
291
|
+
if (typeof builtClosure === 'string') {
|
|
292
|
+
return builtClosure === commandClosureDigest(fileSystem, path.join(cliRoot, 'src'), source)
|
|
293
|
+
? null
|
|
294
|
+
: compiled;
|
|
295
|
+
}
|
|
168
296
|
const builtDigest = commandBuildManifest?.commands?.[relative];
|
|
297
|
+
// A manifest written before closures existed. Fall back to the old, wider
|
|
298
|
+
// test rather than trusting a per-file digest that cannot see an edited
|
|
299
|
+
// import — an over-cautious verdict is recoverable, a wrong "fresh" is
|
|
300
|
+
// what this launcher exists to prevent.
|
|
301
|
+
//
|
|
169
302
|
// Git checkouts and partial builds can make old JS newer than its source.
|
|
170
303
|
// Content identity is authoritative; no digest means the development
|
|
171
304
|
// build is unproved and the installed CLI is safer.
|
|
172
|
-
return commandBuildManifest?.sourceTreeDigest === currentSourceTreeDigest &&
|
|
305
|
+
return commandBuildManifest?.sourceTreeDigest === currentSourceTreeDigest() &&
|
|
173
306
|
typeof builtDigest === 'string' &&
|
|
174
307
|
builtDigest === sourceDigest(fileSystem, source)
|
|
175
308
|
? null
|
|
@@ -188,6 +321,35 @@ function missingLocalCommandBuild({ cliRoot, argv, fileSystem = fs, verifySource
|
|
|
188
321
|
if (incomplete) return incomplete;
|
|
189
322
|
break;
|
|
190
323
|
}
|
|
324
|
+
/*
|
|
325
|
+
* `--version` must report the binary that will actually RUN.
|
|
326
|
+
*
|
|
327
|
+
* It names no command, so the loop above never ran and this returned null —
|
|
328
|
+
* meaning `skrr --version` answered from the local checkout while every real
|
|
329
|
+
* command silently delegated to a different build. Someone verifying a change
|
|
330
|
+
* saw the version they expected and tested code they had not written, which is
|
|
331
|
+
* the precise failure this launcher exists to prevent, wearing a reassuring
|
|
332
|
+
* number.
|
|
333
|
+
*
|
|
334
|
+
* The whole-tree digest is the right test here: a stale tree means SOME
|
|
335
|
+
* command would fall back, so the version the user is about to rely on is not
|
|
336
|
+
* this one.
|
|
337
|
+
*/
|
|
338
|
+
if (argv.some((value) => value === '--version' || value === '-v')) {
|
|
339
|
+
// A STALE tree and a MISSING build are the same answer to the user's
|
|
340
|
+
// question. The digest comparison covers the first and skipped the second,
|
|
341
|
+
// because a wiped or half-written `dist` has no manifest to compare — so
|
|
342
|
+
// `--version` still answered from the checkout while every command fell
|
|
343
|
+
// back. Observed twice in one dogfood session, both times right after a
|
|
344
|
+
// rebuild left `dist` incomplete.
|
|
345
|
+
if (verifySourceIdentity && !commandBuildManifest) return commandsDirectory;
|
|
346
|
+
if (
|
|
347
|
+
verifySourceIdentity &&
|
|
348
|
+
commandBuildManifest.sourceTreeDigest !== currentSourceTreeDigest()
|
|
349
|
+
) {
|
|
350
|
+
return commandsDirectory;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
191
353
|
if (argv.some((value) => value === '--help' || value === '-h')) {
|
|
192
354
|
const sourceDirectory = path.join(sourceCommandsDirectory, ...commandParts);
|
|
193
355
|
const pending = [sourceDirectory];
|
|
@@ -215,6 +377,7 @@ function missingLocalCommandBuild({ cliRoot, argv, fileSystem = fs, verifySource
|
|
|
215
377
|
|
|
216
378
|
module.exports = {
|
|
217
379
|
COMMAND_BUILD_MANIFEST,
|
|
380
|
+
commandClosureDigest,
|
|
218
381
|
findAlternateCli,
|
|
219
382
|
missingLocalCommandBuild,
|
|
220
383
|
sourceTreeDigest,
|
package/dist/base-command.js
CHANGED
|
@@ -16,6 +16,7 @@ exports.isTypedServerRefusal = isTypedServerRefusal;
|
|
|
16
16
|
exports.isRetryableFailure = isRetryableFailure;
|
|
17
17
|
const core_1 = require("@oclif/core");
|
|
18
18
|
Object.defineProperty(exports, "Flags", { enumerable: true, get: function () { return core_1.Flags; } });
|
|
19
|
+
const failed_lookup_1 = require("./lib/failed-lookup");
|
|
19
20
|
// Re-exported from its home in `lib/keychain`, beside the other profile
|
|
20
21
|
// functions. It lived here while `init()` was its only caller; a lib module
|
|
21
22
|
// needing it would otherwise have to import the command base class, and with
|
|
@@ -112,7 +113,8 @@ class BaseCommand extends core_1.Command {
|
|
|
112
113
|
}),
|
|
113
114
|
profile: core_1.Flags.string({
|
|
114
115
|
description: 'Which stored session to use. Each profile keeps its own credential and deployment, ' +
|
|
115
|
-
'so signing into one does not sign you out of another. Also OVERSKY_PROFILE.'
|
|
116
|
+
'so signing into one does not sign you out of another. Also OVERSKY_PROFILE. ' +
|
|
117
|
+
'List them with `profiles list`.',
|
|
116
118
|
}),
|
|
117
119
|
};
|
|
118
120
|
cliConfig;
|
|
@@ -391,6 +393,14 @@ class BaseCommand extends core_1.Command {
|
|
|
391
393
|
// UUID, so refs go through the same exact-match resolution as titles.
|
|
392
394
|
if (!query || (0, space_resolver_1.looksLikeCanonicalSpaceId)(query))
|
|
393
395
|
return query;
|
|
396
|
+
if ((0, failed_lookup_1.isFailedLookupValue)(query)) {
|
|
397
|
+
this.failWithCliError({
|
|
398
|
+
message: (0, failed_lookup_1.describeFailedLookupValue)(query, 'Space'),
|
|
399
|
+
code: space_resolver_1.SPACE_CLI_ERROR_CODE.NOT_A_REFERENCE,
|
|
400
|
+
exit: 2,
|
|
401
|
+
retryable: false,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
394
404
|
const normalizedQuery = (0, space_resolver_1.normalizeSpaceRef)(query);
|
|
395
405
|
const load = async (includeArchived) => {
|
|
396
406
|
let response;
|
|
@@ -489,6 +499,16 @@ class BaseCommand extends core_1.Command {
|
|
|
489
499
|
const query = value.trim();
|
|
490
500
|
if (!query)
|
|
491
501
|
return query;
|
|
502
|
+
// Before the search, not after it: `null` from a failed `jq -r` must never
|
|
503
|
+
// reach the title tiers, and it should not cost a request to say so.
|
|
504
|
+
if ((0, failed_lookup_1.isFailedLookupValue)(query)) {
|
|
505
|
+
this.failWithCliError({
|
|
506
|
+
message: (0, failed_lookup_1.describeFailedLookupValue)(query, 'task'),
|
|
507
|
+
code: task_ref_resolver_1.TASK_REF_CLI_ERROR_CODE.NOT_A_REFERENCE,
|
|
508
|
+
exit: 2,
|
|
509
|
+
retryable: false,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
492
512
|
let response;
|
|
493
513
|
try {
|
|
494
514
|
response = await data_provider_1.dataService.listTasks({ q: query, limit: 50 });
|
|
@@ -690,6 +710,7 @@ class BaseCommand extends core_1.Command {
|
|
|
690
710
|
AMBIGUOUS: 'ASSIGNEE_AMBIGUOUS',
|
|
691
711
|
NO_SPACE: 'ASSIGNEE_NO_SPACE_CONTEXT',
|
|
692
712
|
NOT_FOUND: 'ASSIGNEE_NOT_FOUND',
|
|
713
|
+
NOT_A_REFERENCE: 'ASSIGNEE_NOT_A_REFERENCE',
|
|
693
714
|
};
|
|
694
715
|
this.failWithCliError({
|
|
695
716
|
message: outcome.failures
|
|
@@ -1231,7 +1252,21 @@ class BaseCommand extends core_1.Command {
|
|
|
1231
1252
|
//
|
|
1232
1253
|
// Field-level validation is appended for the same reason: the server names
|
|
1233
1254
|
// the offending field and only `--json` callers could read it.
|
|
1234
|
-
|
|
1255
|
+
//
|
|
1256
|
+
// And the REMEDY, when the message does not already carry one. This CLI's
|
|
1257
|
+
// convention is a `→` remedy line inside the message (103 sites), with
|
|
1258
|
+
// `details.suggestion` as its machine-readable twin for `--json`. Where a
|
|
1259
|
+
// call site wrote the remedy ONLY into `details.suggestion`, it reached
|
|
1260
|
+
// `--json` alone, and a person at a terminal was told what was wrong and
|
|
1261
|
+
// never what to do — `followups list` without an agent, OSK-9670. oclif
|
|
1262
|
+
// renders `suggestions` as its own "Try this:" block. Skipped when the
|
|
1263
|
+
// message opens a `→` line, so those do not print the remedy twice.
|
|
1264
|
+
const suggestion = hasRemedyLine(message) ? undefined : authoredSuggestion(details);
|
|
1265
|
+
this.error(`${message}${formatValidationIssues(details)}`, {
|
|
1266
|
+
exit,
|
|
1267
|
+
code,
|
|
1268
|
+
...(suggestion ? { suggestions: [suggestion] } : {}),
|
|
1269
|
+
});
|
|
1235
1270
|
}
|
|
1236
1271
|
writeJsonCliError({ message, code, status, exit, retryable, details, }) {
|
|
1237
1272
|
this.log(JSON.stringify({
|
|
@@ -1612,6 +1647,15 @@ function isRetryableFailure(status, body) {
|
|
|
1612
1647
|
return false;
|
|
1613
1648
|
return status === 408 || status === 425 || status === 429 || !!(status && status >= 500);
|
|
1614
1649
|
}
|
|
1650
|
+
/** True when a message already carries this CLI's `→` remedy line. */
|
|
1651
|
+
function hasRemedyLine(message) {
|
|
1652
|
+
return /^\s*→/m.test(message);
|
|
1653
|
+
}
|
|
1654
|
+
/** The remedy a call site wrote into `details.suggestion`, if it wrote one. */
|
|
1655
|
+
function authoredSuggestion(details) {
|
|
1656
|
+
const suggestion = details?.suggestion;
|
|
1657
|
+
return typeof suggestion === 'string' && suggestion.trim() ? suggestion.trim() : undefined;
|
|
1658
|
+
}
|
|
1615
1659
|
/**
|
|
1616
1660
|
* Render server-supplied field validation into the human error.
|
|
1617
1661
|
*
|
|
@@ -46,7 +46,7 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
46
46
|
space: core_1.Flags.string({ description: 'Offer only in this space (implies --scope space)' }),
|
|
47
47
|
'space-title': core_1.Flags.string({ description: 'Denormalized space title for the scope chip' }),
|
|
48
48
|
label: core_1.Flags.string({
|
|
49
|
-
description: 'Offer in every space carrying this
|
|
49
|
+
description: 'Offer in every space carrying this Label — a Label id or name from `labels list` (repeatable, any-of; implies --scope label). Not button text: that is `spaces actions add --label`.',
|
|
50
50
|
multiple: true,
|
|
51
51
|
}),
|
|
52
52
|
outcome: core_1.Flags.string({
|
|
@@ -70,7 +70,7 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
70
70
|
enabled: flags.enabled,
|
|
71
71
|
// Flags win over --from-json, and a JSON body may still carry these
|
|
72
72
|
// directly. Both paths land on the same two fields below.
|
|
73
|
-
scope: (0, agent_actions_1.resolveAgentActionScopeFlags)(flags),
|
|
73
|
+
scope: await (0, agent_actions_1.resolveAgentActionScopeFlags)(flags),
|
|
74
74
|
outcome: flags.outcome,
|
|
75
75
|
});
|
|
76
76
|
}
|
|
@@ -78,14 +78,17 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
78
78
|
this.error(err.message, { exit: 1 });
|
|
79
79
|
}
|
|
80
80
|
let created;
|
|
81
|
+
let replayed = false;
|
|
81
82
|
try {
|
|
82
|
-
const agent = await (0, agent_actions_1.fetchAgentForActionEdit)(args.agentId);
|
|
83
|
-
const actions = (0, agent_actions_1.getAgentActions)(agent);
|
|
84
83
|
const title = typeof body.title === 'string' ? body.title.trim() : '';
|
|
85
84
|
if (!title)
|
|
86
85
|
this.error('Action title is required. Pass --title or include title.', { exit: 1 });
|
|
87
86
|
const kind = body.kind === 'builtin' ? 'builtin' : 'prompt';
|
|
88
|
-
|
|
87
|
+
// No read of the library: position is assigned by the server at the
|
|
88
|
+
// moment of the append, so it cannot be computed from a stale copy. An
|
|
89
|
+
// explicit --order is still honoured.
|
|
90
|
+
const explicitOrder = typeof body.order === 'number' ? body.order : undefined;
|
|
91
|
+
const order = explicitOrder ?? 0;
|
|
89
92
|
const enabled = typeof body.enabled === 'boolean' ? body.enabled : true;
|
|
90
93
|
const scope = body.scope;
|
|
91
94
|
const outcome = body.outcome === 'durable' || body.outcome === 'ephemeral'
|
|
@@ -140,7 +143,13 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
140
143
|
sourceListingId: typeof body.sourceListingId === 'string' ? body.sourceListingId : undefined,
|
|
141
144
|
});
|
|
142
145
|
}
|
|
143
|
-
|
|
146
|
+
if (explicitOrder === undefined) {
|
|
147
|
+
delete created.order;
|
|
148
|
+
}
|
|
149
|
+
const appended = await (0, agent_actions_1.appendAgentAction)(args.agentId, created);
|
|
150
|
+
// Report what the server stored, not what we sent.
|
|
151
|
+
created = appended.action;
|
|
152
|
+
replayed = !appended.created;
|
|
144
153
|
}
|
|
145
154
|
catch (err) {
|
|
146
155
|
this.handleApiError(err);
|
|
@@ -149,7 +158,9 @@ class AgentsActionsCreate extends base_command_1.BaseCommand {
|
|
|
149
158
|
this.log(JSON.stringify(created, null, 2));
|
|
150
159
|
return;
|
|
151
160
|
}
|
|
152
|
-
this.log(
|
|
161
|
+
this.log(replayed
|
|
162
|
+
? `Action ${created.id} was already on agent ${args.agentId} (nothing added):`
|
|
163
|
+
: `Created action on agent ${args.agentId}:`);
|
|
153
164
|
(0, agent_actions_1.renderAction)(created, (line) => this.log(line));
|
|
154
165
|
}
|
|
155
166
|
}
|
|
@@ -16,6 +16,9 @@ class AgentsActionsDelete extends base_command_1.BaseCommand {
|
|
|
16
16
|
};
|
|
17
17
|
static flags = {
|
|
18
18
|
yes: core_1.Flags.boolean({ char: 'y', description: 'Skip confirmation prompt' }),
|
|
19
|
+
// The only sibling (create, update, list, show) without --json, so a script
|
|
20
|
+
// driving the five broke on the fifth.
|
|
21
|
+
json: core_1.Flags.boolean({ description: 'Output the result as JSON' }),
|
|
19
22
|
};
|
|
20
23
|
async run() {
|
|
21
24
|
this.requireAuth();
|
|
@@ -37,6 +40,10 @@ class AgentsActionsDelete extends base_command_1.BaseCommand {
|
|
|
37
40
|
catch (err) {
|
|
38
41
|
this.handleApiError(err);
|
|
39
42
|
}
|
|
43
|
+
if (flags.json) {
|
|
44
|
+
this.log(JSON.stringify({ deleted: true, agentId: args.agentId, actionId: args.actionId }, null, 2));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
40
47
|
this.log(`Deleted action ${args.actionId} from agent ${args.agentId}.`);
|
|
41
48
|
}
|
|
42
49
|
}
|
|
@@ -42,7 +42,7 @@ class AgentsActionsUpdate extends base_command_1.BaseCommand {
|
|
|
42
42
|
space: core_1.Flags.string({ description: 'Offer only in this space (implies --scope space)' }),
|
|
43
43
|
'space-title': core_1.Flags.string({ description: 'Denormalized space title for the scope chip' }),
|
|
44
44
|
label: core_1.Flags.string({
|
|
45
|
-
description: 'Offer in every space carrying this
|
|
45
|
+
description: 'Offer in every space carrying this Label — a Label id or name from `labels list` (repeatable, any-of; implies --scope label). Not button text: that is `spaces actions add --label`.',
|
|
46
46
|
multiple: true,
|
|
47
47
|
}),
|
|
48
48
|
outcome: core_1.Flags.string({
|
|
@@ -63,7 +63,7 @@ class AgentsActionsUpdate extends base_command_1.BaseCommand {
|
|
|
63
63
|
config: (0, agent_actions_1.parseJsonObjectFlag)(flags.config, '--config'),
|
|
64
64
|
order: flags.order,
|
|
65
65
|
enabled: flags.enabled,
|
|
66
|
-
scope: (0, agent_actions_1.resolveAgentActionScopeFlags)(flags),
|
|
66
|
+
scope: await (0, agent_actions_1.resolveAgentActionScopeFlags)(flags),
|
|
67
67
|
outcome: flags.outcome,
|
|
68
68
|
});
|
|
69
69
|
}
|
|
@@ -125,7 +125,9 @@ class AgentsActionsUpdate extends base_command_1.BaseCommand {
|
|
|
125
125
|
}
|
|
126
126
|
actions[index] = next;
|
|
127
127
|
updated = next;
|
|
128
|
-
await (0, agent_actions_1.updateAgentActions)(args.agentId, actions);
|
|
128
|
+
const savedAgent = await (0, agent_actions_1.updateAgentActions)(args.agentId, actions);
|
|
129
|
+
// Report what the server stored, not what we sent — see storedActionOrLocal.
|
|
130
|
+
updated = (0, agent_actions_1.storedActionOrLocal)(savedAgent, updated);
|
|
129
131
|
}
|
|
130
132
|
catch (err) {
|
|
131
133
|
this.handleApiError(err);
|
|
@@ -165,9 +165,12 @@ class AgentsApiActionsAdd extends base_command_1.BaseCommand {
|
|
|
165
165
|
path: props.path,
|
|
166
166
|
})),
|
|
167
167
|
};
|
|
168
|
+
// Say it was a dry run: the output used to be indistinguishable from what
|
|
169
|
+
// a real add would have printed, so a reader could not tell whether
|
|
170
|
+
// anything had been written.
|
|
168
171
|
this.log(flags.json
|
|
169
|
-
? JSON.stringify(preview, null, 2)
|
|
170
|
-
:
|
|
172
|
+
? JSON.stringify({ dryRun: true, written: false, ...preview }, null, 2)
|
|
173
|
+
: `Dry run — nothing was written. ${preview.functions.length} operation(s) on ${domain}:\n` +
|
|
171
174
|
preview.functions
|
|
172
175
|
.map((f) => ` ${f.name} ${f.method.toUpperCase()} ${f.path}`)
|
|
173
176
|
.join('\n'));
|
|
@@ -17,6 +17,17 @@ import { BaseCommand } from '../../../base-command';
|
|
|
17
17
|
* the other two would break muscle memory for a surface that works, so this one
|
|
18
18
|
* takes an unambiguous name and all three now say which concept they are.
|
|
19
19
|
*/
|
|
20
|
+
/**
|
|
21
|
+
* The operation names an action exposes, parsed from its stored spec by the same
|
|
22
|
+
* parser `add` and the web builder use. The listing used to show id, agent,
|
|
23
|
+
* domain and auth — never what the action can DO — so answering "which tools does
|
|
24
|
+
* this give the agent" meant reading the raw spec.
|
|
25
|
+
*/
|
|
26
|
+
export declare function operationNames(action: {
|
|
27
|
+
metadata?: {
|
|
28
|
+
raw_spec?: string;
|
|
29
|
+
};
|
|
30
|
+
}): string[];
|
|
20
31
|
export default class AgentsApiActionsList extends BaseCommand {
|
|
21
32
|
static description: string;
|
|
22
33
|
static examples: string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.operationNames = operationNames;
|
|
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");
|
|
@@ -22,6 +23,21 @@ const format_1 = require("../../../lib/format");
|
|
|
22
23
|
* the other two would break muscle memory for a surface that works, so this one
|
|
23
24
|
* takes an unambiguous name and all three now say which concept they are.
|
|
24
25
|
*/
|
|
26
|
+
/**
|
|
27
|
+
* The operation names an action exposes, parsed from its stored spec by the same
|
|
28
|
+
* parser `add` and the web builder use. The listing used to show id, agent,
|
|
29
|
+
* domain and auth — never what the action can DO — so answering "which tools does
|
|
30
|
+
* this give the agent" meant reading the raw spec.
|
|
31
|
+
*/
|
|
32
|
+
function operationNames(action) {
|
|
33
|
+
const raw = action.metadata?.raw_spec;
|
|
34
|
+
if (!raw)
|
|
35
|
+
return [];
|
|
36
|
+
const parsed = (0, data_provider_1.validateAndParseOpenAPISpec)(raw);
|
|
37
|
+
if (!parsed.status || !parsed.spec)
|
|
38
|
+
return [];
|
|
39
|
+
return Object.keys((0, data_provider_1.openapiToFunction)(parsed.spec).requestBuilders);
|
|
40
|
+
}
|
|
25
41
|
class AgentsApiActionsList extends base_command_1.BaseCommand {
|
|
26
42
|
static description = 'List OpenAPI-backed Actions on agents you can edit (NOT `agents actions`, which is embedded buttons)';
|
|
27
43
|
static examples = [
|
|
@@ -51,7 +67,15 @@ class AgentsApiActionsList extends base_command_1.BaseCommand {
|
|
|
51
67
|
? actions.filter((action) => action.agent_id === flags.agent)
|
|
52
68
|
: actions;
|
|
53
69
|
if (flags.json) {
|
|
54
|
-
|
|
70
|
+
// Database internals (`_id`, `__v`) are not part of an action; a script
|
|
71
|
+
// reading this should not learn to depend on them.
|
|
72
|
+
const clean = rows.map((action) => {
|
|
73
|
+
const { _id, __v, ...rest } = action;
|
|
74
|
+
void _id;
|
|
75
|
+
void __v;
|
|
76
|
+
return { ...rest, operations: operationNames(action) };
|
|
77
|
+
});
|
|
78
|
+
this.log(JSON.stringify(clean, null, 2));
|
|
55
79
|
return;
|
|
56
80
|
}
|
|
57
81
|
if (rows.length === 0) {
|
|
@@ -66,11 +90,13 @@ class AgentsApiActionsList extends base_command_1.BaseCommand {
|
|
|
66
90
|
agentId: action.agent_id ?? '-',
|
|
67
91
|
domain: action.metadata?.domain ?? '-',
|
|
68
92
|
auth: action.metadata?.auth?.type ?? 'none',
|
|
93
|
+
operations: operationNames(action).join(', ') || '-',
|
|
69
94
|
})), [
|
|
70
95
|
{ key: 'actionId', header: 'ACTION ID', verbatim: true },
|
|
71
96
|
{ key: 'agentId', header: 'AGENT ID', verbatim: true },
|
|
72
97
|
{ key: 'domain', header: 'DOMAIN', maxWidth: 40 },
|
|
73
98
|
{ key: 'auth', header: 'AUTH' },
|
|
99
|
+
{ key: 'operations', header: 'OPERATIONS', maxWidth: 48 },
|
|
74
100
|
], (line) => this.log(line));
|
|
75
101
|
}
|
|
76
102
|
}
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { BaseCommand } from '../../../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Which of the two states produced the policy line above it.
|
|
4
|
+
*
|
|
5
|
+
* The route sends `explicit` precisely because the policy alone cannot carry
|
|
6
|
+
* it: `resolveAgentAvatarDefaultPolicy` maps an absent field and a deliberate
|
|
7
|
+
* choice of the same shape onto one value. So "I picked random-from-all" and "I
|
|
8
|
+
* have never picked anything" printed identically, and they are not the same
|
|
9
|
+
* fact — only the second follows the shipped default if it ever changes, which
|
|
10
|
+
* is the whole reason clearing exists as a separate operation from choosing.
|
|
11
|
+
*/
|
|
12
|
+
export declare function describePolicyProvenance(explicit: boolean): string;
|
|
2
13
|
/**
|
|
3
14
|
* What face a NEW agent gets when its creator does not pick one.
|
|
4
15
|
*
|
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.describePolicyProvenance = describePolicyProvenance;
|
|
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
|
+
/**
|
|
8
|
+
* Which of the two states produced the policy line above it.
|
|
9
|
+
*
|
|
10
|
+
* The route sends `explicit` precisely because the policy alone cannot carry
|
|
11
|
+
* it: `resolveAgentAvatarDefaultPolicy` maps an absent field and a deliberate
|
|
12
|
+
* choice of the same shape onto one value. So "I picked random-from-all" and "I
|
|
13
|
+
* have never picked anything" printed identically, and they are not the same
|
|
14
|
+
* fact — only the second follows the shipped default if it ever changes, which
|
|
15
|
+
* is the whole reason clearing exists as a separate operation from choosing.
|
|
16
|
+
*/
|
|
17
|
+
function describePolicyProvenance(explicit) {
|
|
18
|
+
return explicit
|
|
19
|
+
? ' You chose this. It stays until you change or clear it.'
|
|
20
|
+
: ' You have not chosen one, so this follows the shipped default — including if it changes.';
|
|
21
|
+
}
|
|
6
22
|
/**
|
|
7
23
|
* What face a NEW agent gets when its creator does not pick one.
|
|
8
24
|
*
|
|
@@ -36,6 +52,7 @@ class AgentsAvatarDefaultShow extends base_command_1.BaseCommand {
|
|
|
36
52
|
return;
|
|
37
53
|
}
|
|
38
54
|
this.log((0, data_provider_1.describeAgentAvatarPolicy)(response.policy));
|
|
55
|
+
this.log(describePolicyProvenance(Boolean(response.explicit)));
|
|
39
56
|
this.log('');
|
|
40
57
|
this.log('Applies to agents created from now on. Existing agents keep the face they have —');
|
|
41
58
|
this.log('`skrr agents avatar default apply` is the one path that changes them.');
|
|
@@ -12,7 +12,8 @@ export default class AgentsAvatarDefaultSet extends BaseCommand {
|
|
|
12
12
|
static description: string;
|
|
13
13
|
static examples: string[];
|
|
14
14
|
static flags: {
|
|
15
|
-
mode: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
|
+
mode: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
|
+
clear: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
16
17
|
ref: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
18
|
scope: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
19
|
category: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -20,12 +20,18 @@ class AgentsAvatarDefaultSet extends base_command_1.BaseCommand {
|
|
|
20
20
|
'<%= config.bin %> agents avatar default set --mode fixed --ref preset:kosmo',
|
|
21
21
|
'<%= config.bin %> agents avatar default set --mode random --scope category --category illustrations',
|
|
22
22
|
'<%= config.bin %> agents avatar default set --mode random --scope mine',
|
|
23
|
+
'<%= config.bin %> agents avatar default set --clear',
|
|
23
24
|
];
|
|
24
25
|
static flags = {
|
|
25
26
|
mode: core_1.Flags.string({
|
|
26
27
|
description: 'platform = the shipped logo; fixed = one avatar; random = a different one each time',
|
|
27
28
|
options: ['platform', 'fixed', 'random'],
|
|
28
|
-
|
|
29
|
+
exclusive: ['clear'],
|
|
30
|
+
}),
|
|
31
|
+
clear: core_1.Flags.boolean({
|
|
32
|
+
description: 'Remove your policy entirely, so new agents follow whatever the workspace or the ' +
|
|
33
|
+
'platform ships. NOT the same as --mode platform, which pins the logo.',
|
|
34
|
+
exclusive: ['mode', 'ref', 'scope', 'category'],
|
|
29
35
|
}),
|
|
30
36
|
ref: core_1.Flags.string({
|
|
31
37
|
description: '--mode fixed: which avatar. default, preset:<id>, asset:<id>, or image:<filepath>@<source>',
|
|
@@ -70,12 +76,22 @@ class AgentsAvatarDefaultSet extends base_command_1.BaseCommand {
|
|
|
70
76
|
async run() {
|
|
71
77
|
this.requireAuth();
|
|
72
78
|
const { flags } = await this.parse(AgentsAvatarDefaultSet);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
// `--mode` was `required`, which made the cleared state — the one the write
|
|
80
|
+
// route goes out of its way to support — unreachable from here: every value
|
|
81
|
+
// of `--mode` WRITES a policy, so once this command had been run there was
|
|
82
|
+
// no way back to "no opinion" short of calling the API by hand.
|
|
83
|
+
if (!flags.clear && !flags.mode) {
|
|
84
|
+
this.error('Choose --mode platform|fixed|random to set a policy, or --clear to remove yours so ' +
|
|
85
|
+
'new agents follow whatever the workspace or the platform ships.', { exit: 1 });
|
|
76
86
|
}
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
let policy = null;
|
|
88
|
+
if (!flags.clear) {
|
|
89
|
+
try {
|
|
90
|
+
policy = this.buildPolicy(flags);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
this.error(err.message, { exit: 1 });
|
|
94
|
+
}
|
|
79
95
|
}
|
|
80
96
|
let response;
|
|
81
97
|
try {
|
|
@@ -88,7 +104,16 @@ class AgentsAvatarDefaultSet extends base_command_1.BaseCommand {
|
|
|
88
104
|
this.log(JSON.stringify(response, null, 2));
|
|
89
105
|
return;
|
|
90
106
|
}
|
|
91
|
-
|
|
107
|
+
if (flags.clear) {
|
|
108
|
+
// Say what it FOLLOWS now, not just that something was removed — the
|
|
109
|
+
// value is the same one an explicit `--mode random --scope all` would
|
|
110
|
+
// print, and the difference between them is the whole point of clearing.
|
|
111
|
+
this.log(`Cleared. New agents follow the current default: ${(0, data_provider_1.describeAgentAvatarPolicy)(response.policy)}.`);
|
|
112
|
+
this.log('If that default changes later, this account follows it.');
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
this.log(`Default avatar policy: ${(0, data_provider_1.describeAgentAvatarPolicy)(response.policy)}`);
|
|
116
|
+
}
|
|
92
117
|
this.log('Existing agents are unchanged. `skrr agents avatar default apply` changes those.');
|
|
93
118
|
}
|
|
94
119
|
}
|