@skrr-ai/cli 0.1.36 → 0.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/bin/dev-fallback.js +167 -4
- package/dist/base-command.js +46 -2
- package/dist/commands/agents/actions/create.d.ts +5 -0
- package/dist/commands/agents/actions/create.js +42 -5
- 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.d.ts +5 -0
- package/dist/commands/agents/actions/update.js +27 -1
- package/dist/commands/agents/api-actions/add.d.ts +41 -0
- package/dist/commands/agents/api-actions/add.js +205 -0
- package/dist/commands/agents/api-actions/index.d.ts +39 -0
- package/dist/commands/agents/api-actions/index.js +103 -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 +29 -0
- package/dist/commands/agents/avatar/default/index.js +61 -0
- package/dist/commands/agents/avatar/default/set.d.ts +24 -0
- package/dist/commands/agents/avatar/default/set.js +120 -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/avatar/upload.js +7 -1
- 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 +41 -0
- package/dist/commands/agents/categories/index.d.ts +36 -0
- package/dist/commands/agents/categories/index.js +135 -0
- package/dist/commands/agents/categories/update.d.ts +22 -0
- package/dist/commands/agents/categories/update.js +59 -0
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +94 -7
- package/dist/commands/agents/create.d.ts +10 -0
- package/dist/commands/agents/create.js +64 -3
- package/dist/commands/agents/ensure-default.d.ts +27 -0
- package/dist/commands/agents/ensure-default.js +65 -0
- package/dist/commands/agents/list.d.ts +15 -0
- package/dist/commands/agents/list.js +31 -1
- 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/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/auth.d.ts +19 -0
- package/dist/commands/agents/tools/auth.js +41 -0
- package/dist/commands/agents/tools/calls.d.ts +36 -0
- package/dist/commands/agents/tools/calls.js +117 -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 +74 -3
- 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.d.ts +22 -0
- package/dist/commands/followups/act.js +103 -0
- package/dist/commands/followups/cancel.d.ts +20 -0
- package/dist/commands/followups/cancel.js +50 -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/observability.d.ts +23 -0
- package/dist/commands/followups/observability.js +114 -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 +46 -0
- package/dist/commands/followups/watch.d.ts +51 -0
- package/dist/commands/followups/watch.js +211 -0
- package/dist/commands/goals/labels/add.js +19 -2
- package/dist/commands/goals/labels/remove.js +22 -2
- 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/labels/list.d.ts +24 -1
- package/dist/commands/labels/list.js +62 -19
- 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/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/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/create.d.ts +3 -0
- package/dist/commands/spaces/create.js +32 -2
- package/dist/commands/spaces/label-summaries.d.ts +27 -0
- package/dist/commands/spaces/label-summaries.js +64 -0
- 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/task-rollups.d.ts +5 -0
- package/dist/commands/spaces/task-rollups.js +15 -4
- 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 +105 -0
- package/dist/commands/tasks/actions/attach.js +32 -7
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +21 -1
- package/dist/commands/tasks/create.d.ts +3 -0
- package/dist/commands/tasks/create.js +34 -2
- package/dist/commands/tasks/events/append.js +29 -6
- package/dist/commands/tasks/expectations/assess.d.ts +12 -0
- package/dist/commands/tasks/expectations/assess.js +123 -14
- package/dist/commands/tasks/expectations.js +95 -17
- package/dist/commands/tasks/follow-up.js +2 -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 +59 -0
- package/dist/commands/tasks/lifecycle/detach.d.ts +19 -0
- package/dist/commands/tasks/lifecycle/detach.js +72 -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 +14 -0
- package/dist/commands/tasks/lifecycle/migrate.js +68 -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 +15 -0
- package/dist/commands/tasks/lifecycle/reopen.js +71 -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 +109 -0
- package/dist/commands/tasks/list.js +16 -9
- package/dist/commands/tasks/move.d.ts +1 -0
- package/dist/commands/tasks/move.js +29 -0
- package/dist/commands/tasks/result/submit.js +11 -1
- package/dist/commands/tasks/review-queue.d.ts +44 -0
- package/dist/commands/tasks/review-queue.js +314 -0
- package/dist/commands/tasks/show.d.ts +11 -0
- package/dist/commands/tasks/show.js +139 -4
- package/dist/commands/tasks/trust.js +7 -2
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +83 -0
- 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 +92 -11
- package/dist/lib/agent-actions.js +171 -25
- 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 +29 -0
- package/dist/lib/agent-pin-mute.js +30 -0
- package/dist/lib/agent-visual-refs.d.ts +33 -0
- package/dist/lib/agent-visual-refs.js +267 -0
- 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 +16 -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 +115 -0
- package/dist/lib/followups.js +127 -0
- 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-ref.d.ts +95 -0
- package/dist/lib/label-ref.js +163 -0
- package/dist/lib/label-scope.d.ts +17 -2
- package/dist/lib/label-scope.js +27 -7
- 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 +33 -0
- package/dist/lib/task-closure.js +104 -0
- package/dist/lib/task-lifecycle-output.d.ts +14 -0
- package/dist/lib/task-lifecycle-output.js +209 -0
- package/dist/lib/task-ref-resolver.d.ts +1 -17
- package/dist/lib/task-ref-resolver.js +18 -8
- package/dist/lib/tasks.d.ts +3 -0
- package/dist/lib/tasks.js +40 -3
- 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 +5559 -4897
- package/oclif.manifest.json +33890 -28690
- package/package.json +24 -6
|
@@ -42,6 +42,9 @@ class TasksUpdate extends base_command_1.BaseCommand {
|
|
|
42
42
|
description: 'Path to a JSON file (or "-" for stdin) to use as the patch body; may include taskId',
|
|
43
43
|
}),
|
|
44
44
|
title: core_1.Flags.string({ description: 'New title' }),
|
|
45
|
+
yes: core_1.Flags.boolean({
|
|
46
|
+
description: 'Skip the confirmation when changing Expectations revokes assessments already recorded',
|
|
47
|
+
}),
|
|
45
48
|
expect: core_1.Flags.string({
|
|
46
49
|
multiple: true,
|
|
47
50
|
description: tasks_1.EXPECT_FLAG_HELP +
|
|
@@ -227,6 +230,86 @@ class TasksUpdate extends base_command_1.BaseCommand {
|
|
|
227
230
|
}
|
|
228
231
|
}
|
|
229
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Say what the edit costs BEFORE making it.
|
|
235
|
+
*
|
|
236
|
+
* `expectations` is a TaskSpecFence field, and assessments are matched by
|
|
237
|
+
* exact `specVersion` — so rewriting the list bumps the version and every
|
|
238
|
+
* judgement already recorded against the old one stops counting. Assess
|
|
239
|
+
* five, fix a typo in the sixth, and the five are gone.
|
|
240
|
+
*
|
|
241
|
+
* Disclosure, not a block: the edit is legitimate and must stay possible.
|
|
242
|
+
* The point is only that its price should not be discovered afterwards, by
|
|
243
|
+
* a Task that will not close. `--yes` states the intent in the command line
|
|
244
|
+
* where it can be reviewed, which is also what a non-TTY caller needs.
|
|
245
|
+
*/
|
|
246
|
+
/*
|
|
247
|
+
* The trigger is the PAYLOAD, not the flag that produced it.
|
|
248
|
+
*
|
|
249
|
+
* The first version guarded only `--expect`, so `--from-json
|
|
250
|
+
* '{"expectations": [...]}'` — exactly what an agent batching edits uses —
|
|
251
|
+
* rewrote the list and revoked the assessments with no warning at all.
|
|
252
|
+
* Same write, same price: the disclosure belongs on the effective change.
|
|
253
|
+
*/
|
|
254
|
+
/*
|
|
255
|
+
* The DESCRIPTION is a spec field too.
|
|
256
|
+
*
|
|
257
|
+
* `TaskSpecFence.TASK_SPEC_FIELDS` is `['description', 'expectations']`, and
|
|
258
|
+
* both advance `specVersion` — which revokes every assessment, because they
|
|
259
|
+
* are matched by exact version. The disclosure was wired to the Expectations
|
|
260
|
+
* payload alone, so fixing a typo in the prose voided a reviewer's sign-off
|
|
261
|
+
* with no warning and no receipt. Same write, same price, same disclosure.
|
|
262
|
+
*/
|
|
263
|
+
const changesSpec = expectationsPatch !== undefined ||
|
|
264
|
+
body.expectations !== undefined ||
|
|
265
|
+
flags.description !== undefined ||
|
|
266
|
+
body.description !== undefined;
|
|
267
|
+
if (changesSpec) {
|
|
268
|
+
let settled = [];
|
|
269
|
+
let unreadable = false;
|
|
270
|
+
try {
|
|
271
|
+
const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskIdentity.id);
|
|
272
|
+
settled = acceptance.expectations.filter((e) => e.assessmentId);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
// An unreadable acceptance is not a reason to refuse the edit. Warn
|
|
276
|
+
// without a number rather than inventing one or blocking the write.
|
|
277
|
+
unreadable = true;
|
|
278
|
+
}
|
|
279
|
+
if ((unreadable || settled.length > 0) && !flags.yes) {
|
|
280
|
+
const noun = settled.length === 1 ? 'assessment' : 'assessments';
|
|
281
|
+
const count = unreadable ? 'Any existing' : `${settled.length} existing`;
|
|
282
|
+
const field = expectationsPatch !== undefined || body.expectations !== undefined
|
|
283
|
+
? 'Changing Expectations'
|
|
284
|
+
: 'Changing the description';
|
|
285
|
+
this.log(`${field} advances the Task specification, so ${count} ${noun} ` +
|
|
286
|
+
'will stop counting and must be recorded again.');
|
|
287
|
+
/*
|
|
288
|
+
* NAME them. The count alone made the warning unactionable — and it is
|
|
289
|
+
* task-WIDE, so Expectations you are not touching lose their judgements
|
|
290
|
+
* too, which a bare number actively hides.
|
|
291
|
+
*/
|
|
292
|
+
for (const row of settled) {
|
|
293
|
+
this.log(` ${row.id} ${row.sentence || row.text || ''}`);
|
|
294
|
+
}
|
|
295
|
+
if (settled.length > 0) {
|
|
296
|
+
this.log('Revocation covers every Expectation on this Task, including ones this edit ' +
|
|
297
|
+
'does not touch.');
|
|
298
|
+
}
|
|
299
|
+
const ok = await this.confirm('Continue? [y/N] ');
|
|
300
|
+
if (!ok) {
|
|
301
|
+
/*
|
|
302
|
+
* Non-zero, because the edit did NOT happen.
|
|
303
|
+
*
|
|
304
|
+
* This printed "No change made." and exited 0, so `skrr tasks update
|
|
305
|
+
* … && echo applied` printed `applied`. The guard exists to protect
|
|
306
|
+
* the non-interactive path, and the non-interactive path is precisely
|
|
307
|
+
* the one that cannot see a message — it can only read the exit code.
|
|
308
|
+
*/
|
|
309
|
+
this.error('No change made — re-run with `--yes` to accept the revocation.', { exit: 2 });
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
230
313
|
const payload = (0, prompt_1.mergeDefined)((0, task_resolver_1.stripTaskIdentityFields)(body), {
|
|
231
314
|
title: flags.title,
|
|
232
315
|
expectations: expectationsPatch === null ? [] : (expectationsPatch ?? undefined),
|
|
@@ -42,7 +42,7 @@ class TasksUpdatesAdd extends base_command_1.BaseCommand {
|
|
|
42
42
|
'fields are required even when empty. ' +
|
|
43
43
|
'progress {completedSinceLast:[],nextActions:[],currentFocus?} · ' +
|
|
44
44
|
'finding {finding,evidenceRefs:[],impact?,severity?} · ' +
|
|
45
|
-
'decision {decision,rationale,alternativesConsidered
|
|
45
|
+
'decision {decision,rationale,alternativesConsidered?:[]} · ' +
|
|
46
46
|
'blocker {cause,requiredAction,nextOwner} · ' +
|
|
47
47
|
'verification {claim,result:passed|failed|inconclusive,evidenceRefs:[]}. ' +
|
|
48
48
|
'nextOwner is a principal object like {"kind":"human","userId":"..."}, not a name. ' +
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr token list`
|
|
4
|
+
*
|
|
5
|
+
* The other half of `token mint`. Minting binds a long-lived refresh session to
|
|
6
|
+
* a machine and records the `--label` with it — which reads as a promise that
|
|
7
|
+
* the credential can be found again — and there was no way to see it: `token`
|
|
8
|
+
* had only `mint`, and `list-tokens` shows CI tokens, a different credential
|
|
9
|
+
* type, so `revoke-token` had nothing to aim at. The only remedy was
|
|
10
|
+
* `logout --all-devices`, which signs every machine out.
|
|
11
|
+
*
|
|
12
|
+
* `GET /api/auth/sessions/refresh` has served exactly this list all along; it
|
|
13
|
+
* was simply not reachable from the CLI.
|
|
14
|
+
*/
|
|
15
|
+
export default class TokenList extends BaseCommand {
|
|
16
|
+
static description: string;
|
|
17
|
+
static examples: string[];
|
|
18
|
+
static flags: {
|
|
19
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
};
|
|
21
|
+
run(): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../base-command");
|
|
5
|
+
const api_fetch_1 = require("../../lib/api-fetch");
|
|
6
|
+
const format_1 = require("../../lib/format");
|
|
7
|
+
/**
|
|
8
|
+
* `skrr token list`
|
|
9
|
+
*
|
|
10
|
+
* The other half of `token mint`. Minting binds a long-lived refresh session to
|
|
11
|
+
* a machine and records the `--label` with it — which reads as a promise that
|
|
12
|
+
* the credential can be found again — and there was no way to see it: `token`
|
|
13
|
+
* had only `mint`, and `list-tokens` shows CI tokens, a different credential
|
|
14
|
+
* type, so `revoke-token` had nothing to aim at. The only remedy was
|
|
15
|
+
* `logout --all-devices`, which signs every machine out.
|
|
16
|
+
*
|
|
17
|
+
* `GET /api/auth/sessions/refresh` has served exactly this list all along; it
|
|
18
|
+
* was simply not reachable from the CLI.
|
|
19
|
+
*/
|
|
20
|
+
class TokenList extends base_command_1.BaseCommand {
|
|
21
|
+
static description = 'List the active sessions a minted token belongs to — the other half of `token mint`';
|
|
22
|
+
static examples = [
|
|
23
|
+
'<%= config.bin %> token list',
|
|
24
|
+
'<%= config.bin %> token list --json',
|
|
25
|
+
];
|
|
26
|
+
static flags = { json: core_1.Flags.boolean({ description: 'Output JSON' }) };
|
|
27
|
+
async run() {
|
|
28
|
+
this.requireAuth();
|
|
29
|
+
const { flags } = await this.parse(TokenList);
|
|
30
|
+
let data = null;
|
|
31
|
+
try {
|
|
32
|
+
data = await (0, api_fetch_1.apiFetch)('/api/auth/sessions/refresh', {
|
|
33
|
+
method: 'GET',
|
|
34
|
+
credential: this.resolvedCredential,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
this.handleApiError(err);
|
|
39
|
+
}
|
|
40
|
+
const sessions = data?.sessions || [];
|
|
41
|
+
if (flags.json)
|
|
42
|
+
return this.log(JSON.stringify({ sessions, count: sessions.length }, null, 2));
|
|
43
|
+
if (!sessions.length)
|
|
44
|
+
return this.log('No active sessions.');
|
|
45
|
+
(0, format_1.renderTable)(sessions.map((session) => ({
|
|
46
|
+
id: session.id,
|
|
47
|
+
kind: session.kind,
|
|
48
|
+
// The operator's own name for the credential wins over a derived
|
|
49
|
+
// device string — it is what they would search by.
|
|
50
|
+
device: session.label || session.device || '-',
|
|
51
|
+
ip: session.ip || '-',
|
|
52
|
+
lastActive: session.lastActiveAt || session.createdAt || '-',
|
|
53
|
+
// The session you are typing in. Revoking it signs THIS machine out,
|
|
54
|
+
// which is the one outcome nobody means when they revoke a credential.
|
|
55
|
+
current: session.current ? 'yes' : '',
|
|
56
|
+
})), [
|
|
57
|
+
{ key: 'id', header: 'ID' },
|
|
58
|
+
{ key: 'kind', header: 'KIND' },
|
|
59
|
+
{ key: 'device', header: 'DEVICE', maxWidth: 34 },
|
|
60
|
+
{ key: 'ip', header: 'IP' },
|
|
61
|
+
{ key: 'lastActive', header: 'LAST ACTIVE' },
|
|
62
|
+
{ key: 'current', header: 'CURRENT' },
|
|
63
|
+
], (line) => this.log(line));
|
|
64
|
+
this.log('');
|
|
65
|
+
this.log('Retire one with: skrr token revoke <id>');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.default = TokenList;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* `skrr token revoke <id>`
|
|
4
|
+
*
|
|
5
|
+
* Retire ONE session — the credential `token mint` handed to one machine —
|
|
6
|
+
* without signing every other machine out. `logout --all-devices` was the only
|
|
7
|
+
* way to do this, which is a blunt instrument for "that one CI box is
|
|
8
|
+
* decommissioned".
|
|
9
|
+
*
|
|
10
|
+
* Owner-gated server-side: a row that is not the caller's returns
|
|
11
|
+
* `{ revoked: false }` rather than an error, so ids cannot be enumerated.
|
|
12
|
+
*/
|
|
13
|
+
export default class TokenRevoke extends BaseCommand {
|
|
14
|
+
static description: string;
|
|
15
|
+
static examples: string[];
|
|
16
|
+
static args: {
|
|
17
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
18
|
+
};
|
|
19
|
+
static flags: {
|
|
20
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
21
|
+
};
|
|
22
|
+
run(): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../base-command");
|
|
5
|
+
const api_fetch_1 = require("../../lib/api-fetch");
|
|
6
|
+
/**
|
|
7
|
+
* `skrr token revoke <id>`
|
|
8
|
+
*
|
|
9
|
+
* Retire ONE session — the credential `token mint` handed to one machine —
|
|
10
|
+
* without signing every other machine out. `logout --all-devices` was the only
|
|
11
|
+
* way to do this, which is a blunt instrument for "that one CI box is
|
|
12
|
+
* decommissioned".
|
|
13
|
+
*
|
|
14
|
+
* Owner-gated server-side: a row that is not the caller's returns
|
|
15
|
+
* `{ revoked: false }` rather than an error, so ids cannot be enumerated.
|
|
16
|
+
*/
|
|
17
|
+
class TokenRevoke extends base_command_1.BaseCommand {
|
|
18
|
+
static description = 'Revoke one session by id — see `skrr token list` for the ids';
|
|
19
|
+
static examples = ['<%= config.bin %> token revoke 665f1c2e9a4b3d0011aa77bc'];
|
|
20
|
+
static args = {
|
|
21
|
+
id: core_1.Args.string({
|
|
22
|
+
required: true,
|
|
23
|
+
ignoreStdin: true,
|
|
24
|
+
description: 'Session id from `skrr token list`',
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
static flags = { json: core_1.Flags.boolean({ description: 'Output JSON' }) };
|
|
28
|
+
async run() {
|
|
29
|
+
this.requireAuth();
|
|
30
|
+
const { args, flags } = await this.parse(TokenRevoke);
|
|
31
|
+
let data = null;
|
|
32
|
+
try {
|
|
33
|
+
data = await (0, api_fetch_1.apiFetch)(`/api/auth/sessions/refresh/${encodeURIComponent(args.id)}/revoke`, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
credential: this.resolvedCredential,
|
|
36
|
+
body: {},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
this.handleApiError(err);
|
|
41
|
+
}
|
|
42
|
+
if (flags.json)
|
|
43
|
+
return this.log(JSON.stringify(data, null, 2));
|
|
44
|
+
if (data?.revoked)
|
|
45
|
+
return this.log(`Revoked session ${args.id}. Other machines stay signed in.`);
|
|
46
|
+
// The server does not distinguish "already gone" from "not yours" on
|
|
47
|
+
// purpose, so neither does this — saying "not found" would leak the
|
|
48
|
+
// difference and let somebody probe for ids.
|
|
49
|
+
this.log(`Nothing to revoke for ${args.id} — it is already revoked, or it is not one of your sessions.`);
|
|
50
|
+
this.log('List what is active with: skrr token list');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.default = TokenRevoke;
|
|
@@ -1,34 +1,115 @@
|
|
|
1
|
-
import type { Agent, AgentAction, BuiltinActionConfig, BuiltinActionType, BuiltinAgentAction, EmbeddedActionRef, PromptAgentAction } from '@skrr-ai/data-provider';
|
|
2
|
-
export
|
|
1
|
+
import type { Agent, AgentAction, AgentActionOutcome, AgentActionScope, BuiltinActionConfig, BuiltinActionType, BuiltinAgentAction, EmbeddedActionRef, PromptAgentAction } from '@skrr-ai/data-provider';
|
|
2
|
+
export { BUILTIN_ACTION_TYPES } from '@skrr-ai/data-provider';
|
|
3
3
|
export declare const ACTION_TARGET_TYPES: readonly ["group-chats", "spaces", "tasks", "goals", "slack-channels", "slack-users"];
|
|
4
4
|
export type ActionTargetType = (typeof ACTION_TARGET_TYPES)[number];
|
|
5
5
|
export declare function parseJsonObjectFlag(value: string | undefined, flagName: string): Record<string, unknown> | undefined;
|
|
6
6
|
export declare function fetchAgentForActionEdit(agentId: string): Promise<Agent>;
|
|
7
7
|
export declare function getAgentActions(agent: Agent): AgentAction[];
|
|
8
8
|
export declare function findAgentAction(agent: Agent, actionId: string): AgentAction | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* The row as the SERVER stored it, not as we sent it.
|
|
11
|
+
*
|
|
12
|
+
* `updateAgentActions` returns the updated Agent, and both editors used to
|
|
13
|
+
* discard it and print the object they had just built — so the output was the
|
|
14
|
+
* input, restated. That is not a cosmetic difference: the server normalizes
|
|
15
|
+
* `agentActions` through an allowlist before persisting, so a field it drops is
|
|
16
|
+
* echoed back by the CLI as though it had been saved. A `label` scope and
|
|
17
|
+
* `outcome: durable` were both silently discarded that way and the CLI reported
|
|
18
|
+
* success with the values the caller had typed (OSK-9628).
|
|
19
|
+
*
|
|
20
|
+
* Falling back to the local object keeps the command working if the write
|
|
21
|
+
* succeeds but the response is unexpectedly shaped; it cannot make the output
|
|
22
|
+
* wrong in a way it was not already.
|
|
23
|
+
*/
|
|
24
|
+
export declare function storedActionOrLocal(agent: Agent | null | undefined, local: AgentAction): AgentAction;
|
|
25
|
+
export type AppendedAgentAction = {
|
|
26
|
+
/** The action as the server stored it. */
|
|
27
|
+
action: AgentAction;
|
|
28
|
+
/** False when this id was already in the library — a replayed request. */
|
|
29
|
+
created: boolean;
|
|
30
|
+
total: number;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Append ONE action atomically.
|
|
34
|
+
*
|
|
35
|
+
* `agents actions create` used to read the agent, append in memory and write
|
|
36
|
+
* the whole library back through `updateAgentActions`. Two concurrent creates
|
|
37
|
+
* therefore each read the same library and the later write erased the earlier
|
|
38
|
+
* action — six parallel creates all printed success and left one (OSK-9673).
|
|
39
|
+
* This endpoint appends with a single conditional `$push` on the server, so
|
|
40
|
+
* concurrent creates all land, the cap is enforced at the instant of the write,
|
|
41
|
+
* and a retried request whose id already landed returns `created: false`
|
|
42
|
+
* instead of adding a second copy. The client-generated id is what makes that
|
|
43
|
+
* retry safe, so it is sent rather than left for the server to assign.
|
|
44
|
+
*
|
|
45
|
+
* Update and delete still use `updateAgentActions` and still read-modify-write.
|
|
46
|
+
*/
|
|
47
|
+
export declare function appendAgentAction(agentId: string, action: AgentAction): Promise<AppendedAgentAction>;
|
|
9
48
|
export declare function updateAgentActions(agentId: string, actions: AgentAction[]): Promise<Agent>;
|
|
10
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Fields every action shape carries regardless of kind.
|
|
51
|
+
*
|
|
52
|
+
* `scope` and `outcome` are listed HERE rather than threaded through each
|
|
53
|
+
* factory's own parameter list, because the previous version enumerated the
|
|
54
|
+
* fields it copied and simply omitted `scope` — so a space-scoped action was
|
|
55
|
+
* unauthorable from the CLI even via `--from-json`, and the omission was
|
|
56
|
+
* invisible (the row wrote fine, it was just offered everywhere).
|
|
57
|
+
*/
|
|
58
|
+
export type AgentActionCommonInput = {
|
|
11
59
|
title: string;
|
|
12
60
|
description?: string;
|
|
13
|
-
prompt: string;
|
|
14
61
|
order: number;
|
|
15
62
|
enabled: boolean;
|
|
16
63
|
id?: string;
|
|
17
64
|
sourceListingId?: string;
|
|
65
|
+
scope?: AgentActionScope;
|
|
66
|
+
outcome?: AgentActionOutcome;
|
|
67
|
+
};
|
|
68
|
+
export declare function makePromptAction(input: AgentActionCommonInput & {
|
|
69
|
+
prompt: string;
|
|
18
70
|
/** Structured built-in actions embedded in the prompt — the chip source of truth. */
|
|
19
71
|
embeddedActions?: EmbeddedActionRef[];
|
|
20
72
|
}): PromptAgentAction;
|
|
21
|
-
export declare function makeBuiltinAction(input: {
|
|
22
|
-
title: string;
|
|
23
|
-
description?: string;
|
|
73
|
+
export declare function makeBuiltinAction(input: AgentActionCommonInput & {
|
|
24
74
|
builtinType: BuiltinActionType;
|
|
25
75
|
config: BuiltinActionConfig | Record<string, unknown>;
|
|
26
76
|
prompt?: string;
|
|
27
|
-
order: number;
|
|
28
|
-
enabled: boolean;
|
|
29
|
-
id?: string;
|
|
30
|
-
sourceListingId?: string;
|
|
31
77
|
}): BuiltinAgentAction;
|
|
78
|
+
export declare const AGENT_ACTION_SCOPE_CHOICES: readonly ["general", "space", "label"];
|
|
79
|
+
export declare const AGENT_ACTION_OUTCOME_CHOICES: readonly ["ephemeral", "durable"];
|
|
80
|
+
export type AgentActionScopeFlags = {
|
|
81
|
+
scope?: string;
|
|
82
|
+
space?: string;
|
|
83
|
+
'space-title'?: string;
|
|
84
|
+
label?: string[];
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Turn the scope flags into a stored scope, or `undefined` when the caller said
|
|
88
|
+
* nothing about scope (so an update leaves the existing one alone).
|
|
89
|
+
*
|
|
90
|
+
* `--space <id>` and `--label <id>` imply their kind, because typing
|
|
91
|
+
* `--scope space --space s1` twice is the kind of ceremony people skip and then
|
|
92
|
+
* wonder why the action is everywhere. An explicit `--scope general` clears it.
|
|
93
|
+
*/
|
|
94
|
+
/**
|
|
95
|
+
* `--label` accepts an id OR a name, like every other `--label` in the CLI.
|
|
96
|
+
*
|
|
97
|
+
* It used to take the value verbatim as a `labelId`. A name was therefore
|
|
98
|
+
* stored as though it were an id, matched no space's `labelIds`, and produced
|
|
99
|
+
* an action offered NOWHERE — silently, with the create reporting success. That
|
|
100
|
+
* is exactly the "an action that disappears reads as deletion" hazard the label
|
|
101
|
+
* tier was designed around, arriving through the CLI instead of through a card
|
|
102
|
+
* that forgot to pass its labels. An unknown name was accepted too, so a typo
|
|
103
|
+
* was indistinguishable from a working scope.
|
|
104
|
+
*
|
|
105
|
+
* `resolveLabelRefs` is the same resolver `spaces create --label` uses: it
|
|
106
|
+
* short-circuits when every value already looks like an id (so a scripted
|
|
107
|
+
* caller pays no request), refuses an unknown name with the near misses named,
|
|
108
|
+
* and refuses an ambiguous one rather than guessing.
|
|
109
|
+
*/
|
|
110
|
+
export declare function resolveAgentActionScopeFlags(flags: AgentActionScopeFlags): Promise<AgentActionScope | undefined>;
|
|
111
|
+
/** Human-readable one-liner for a scope, used by list/show renderers. */
|
|
112
|
+
export declare function describeAgentActionScope(scope?: AgentActionScope | null): string;
|
|
32
113
|
export declare function nextActionOrder(actions: AgentAction[]): number;
|
|
33
114
|
export declare function actionKind(action: AgentAction): 'prompt' | 'builtin';
|
|
34
115
|
export declare function renderActions(actions: AgentAction[], log: (line: string) => void): void;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ACTION_TARGET_TYPES = exports.BUILTIN_ACTION_TYPES = void 0;
|
|
3
|
+
exports.AGENT_ACTION_OUTCOME_CHOICES = exports.AGENT_ACTION_SCOPE_CHOICES = exports.ACTION_TARGET_TYPES = exports.BUILTIN_ACTION_TYPES = void 0;
|
|
4
4
|
exports.parseJsonObjectFlag = parseJsonObjectFlag;
|
|
5
5
|
exports.fetchAgentForActionEdit = fetchAgentForActionEdit;
|
|
6
6
|
exports.getAgentActions = getAgentActions;
|
|
7
7
|
exports.findAgentAction = findAgentAction;
|
|
8
|
+
exports.storedActionOrLocal = storedActionOrLocal;
|
|
9
|
+
exports.appendAgentAction = appendAgentAction;
|
|
8
10
|
exports.updateAgentActions = updateAgentActions;
|
|
9
11
|
exports.makePromptAction = makePromptAction;
|
|
10
12
|
exports.makeBuiltinAction = makeBuiltinAction;
|
|
13
|
+
exports.resolveAgentActionScopeFlags = resolveAgentActionScopeFlags;
|
|
14
|
+
exports.describeAgentActionScope = describeAgentActionScope;
|
|
11
15
|
exports.nextActionOrder = nextActionOrder;
|
|
12
16
|
exports.actionKind = actionKind;
|
|
13
17
|
exports.renderActions = renderActions;
|
|
@@ -15,22 +19,13 @@ exports.renderAction = renderAction;
|
|
|
15
19
|
const node_crypto_1 = require("node:crypto");
|
|
16
20
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
17
21
|
const format_1 = require("./format");
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
'task_mark_done',
|
|
26
|
-
'task_assign',
|
|
27
|
-
'goal_create',
|
|
28
|
-
'goal_mark_done',
|
|
29
|
-
'smart_schedule_plan',
|
|
30
|
-
'smart_schedule_delta_watch',
|
|
31
|
-
];
|
|
32
|
-
const _builtinActionTypesAreExhaustive = true;
|
|
33
|
-
void _builtinActionTypesAreExhaustive;
|
|
22
|
+
const label_ref_1 = require("./label-ref");
|
|
23
|
+
const api_fetch_1 = require("./api-fetch");
|
|
24
|
+
// The vocabulary is owned by `@skrr-ai/data-provider`, which also proves it
|
|
25
|
+
// complete against `BuiltinActionType`. This file used to hold a second copy
|
|
26
|
+
// with its own guard (OSK-9668).
|
|
27
|
+
var data_provider_2 = require("@skrr-ai/data-provider");
|
|
28
|
+
Object.defineProperty(exports, "BUILTIN_ACTION_TYPES", { enumerable: true, get: function () { return data_provider_2.BUILTIN_ACTION_TYPES; } });
|
|
34
29
|
exports.ACTION_TARGET_TYPES = [
|
|
35
30
|
'group-chats',
|
|
36
31
|
'spaces',
|
|
@@ -64,40 +59,182 @@ function getAgentActions(agent) {
|
|
|
64
59
|
function findAgentAction(agent, actionId) {
|
|
65
60
|
return getAgentActions(agent).find((action) => action.id === actionId);
|
|
66
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* The row as the SERVER stored it, not as we sent it.
|
|
64
|
+
*
|
|
65
|
+
* `updateAgentActions` returns the updated Agent, and both editors used to
|
|
66
|
+
* discard it and print the object they had just built — so the output was the
|
|
67
|
+
* input, restated. That is not a cosmetic difference: the server normalizes
|
|
68
|
+
* `agentActions` through an allowlist before persisting, so a field it drops is
|
|
69
|
+
* echoed back by the CLI as though it had been saved. A `label` scope and
|
|
70
|
+
* `outcome: durable` were both silently discarded that way and the CLI reported
|
|
71
|
+
* success with the values the caller had typed (OSK-9628).
|
|
72
|
+
*
|
|
73
|
+
* Falling back to the local object keeps the command working if the write
|
|
74
|
+
* succeeds but the response is unexpectedly shaped; it cannot make the output
|
|
75
|
+
* wrong in a way it was not already.
|
|
76
|
+
*/
|
|
77
|
+
function storedActionOrLocal(agent, local) {
|
|
78
|
+
if (!agent)
|
|
79
|
+
return local;
|
|
80
|
+
return findAgentAction(agent, local.id) ?? local;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Append ONE action atomically.
|
|
84
|
+
*
|
|
85
|
+
* `agents actions create` used to read the agent, append in memory and write
|
|
86
|
+
* the whole library back through `updateAgentActions`. Two concurrent creates
|
|
87
|
+
* therefore each read the same library and the later write erased the earlier
|
|
88
|
+
* action — six parallel creates all printed success and left one (OSK-9673).
|
|
89
|
+
* This endpoint appends with a single conditional `$push` on the server, so
|
|
90
|
+
* concurrent creates all land, the cap is enforced at the instant of the write,
|
|
91
|
+
* and a retried request whose id already landed returns `created: false`
|
|
92
|
+
* instead of adding a second copy. The client-generated id is what makes that
|
|
93
|
+
* retry safe, so it is sent rather than left for the server to assign.
|
|
94
|
+
*
|
|
95
|
+
* Update and delete still use `updateAgentActions` and still read-modify-write.
|
|
96
|
+
*/
|
|
97
|
+
async function appendAgentAction(agentId, action) {
|
|
98
|
+
try {
|
|
99
|
+
return await (0, api_fetch_1.apiFetch)(`/api/agents/${encodeURIComponent(agentId)}/agent-actions`, { method: 'POST', body: { action } });
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
if (!isMissingRoute(err))
|
|
103
|
+
throw err;
|
|
104
|
+
return appendAgentActionByRewrite(agentId, action);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The server predates the append route.
|
|
109
|
+
*
|
|
110
|
+
* A released CLI is not guaranteed a server that has every route it knows —
|
|
111
|
+
* a self-hosted instance, or production mid-rollout — and without this,
|
|
112
|
+
* `agents actions create` against such a server simply failed. A missing ROUTE
|
|
113
|
+
* answers 404 with no `code` and a "No API route matches" message; a missing
|
|
114
|
+
* AGENT answers 404 with `code: 'agent_not_found'`, which must NOT fall back.
|
|
115
|
+
*/
|
|
116
|
+
function isMissingRoute(err) {
|
|
117
|
+
return (err instanceof api_fetch_1.ApiFetchError &&
|
|
118
|
+
err.status === 404 &&
|
|
119
|
+
!err.code &&
|
|
120
|
+
typeof err.body === 'string' &&
|
|
121
|
+
err.body.includes('No API route matches'));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The pre-append behaviour, kept only for servers without the route: read the
|
|
125
|
+
* library, append in memory, write it back. It is NOT safe under concurrency —
|
|
126
|
+
* that is the defect the route exists to fix — but it is correct for a single
|
|
127
|
+
* writer, which beats refusing to create anything.
|
|
128
|
+
*/
|
|
129
|
+
async function appendAgentActionByRewrite(agentId, action) {
|
|
130
|
+
const agent = await fetchAgentForActionEdit(agentId);
|
|
131
|
+
const actions = getAgentActions(agent);
|
|
132
|
+
const earlier = actions.find((candidate) => candidate.id === action.id);
|
|
133
|
+
if (earlier) {
|
|
134
|
+
return { action: earlier, created: false, total: actions.length };
|
|
135
|
+
}
|
|
136
|
+
const placed = typeof action.order === 'number' ? action : { ...action, order: nextActionOrder(actions) };
|
|
137
|
+
const saved = await updateAgentActions(agentId, [...actions, placed]);
|
|
138
|
+
return {
|
|
139
|
+
action: storedActionOrLocal(saved, placed),
|
|
140
|
+
created: true,
|
|
141
|
+
total: getAgentActions(saved).length || actions.length + 1,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
67
144
|
async function updateAgentActions(agentId, actions) {
|
|
68
145
|
return data_provider_1.dataService.updateAgent({
|
|
69
146
|
agent_id: agentId,
|
|
70
147
|
data: { agentActions: actions },
|
|
71
148
|
});
|
|
72
149
|
}
|
|
73
|
-
function
|
|
150
|
+
function commonActionFields(input) {
|
|
74
151
|
return {
|
|
75
152
|
id: input.id ?? (0, node_crypto_1.randomUUID)(),
|
|
76
153
|
title: input.title,
|
|
77
154
|
description: input.description,
|
|
78
155
|
order: input.order,
|
|
79
156
|
enabled: input.enabled,
|
|
157
|
+
...(input.scope ? { scope: input.scope } : {}),
|
|
158
|
+
...(input.outcome ? { outcome: input.outcome } : {}),
|
|
159
|
+
...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function makePromptAction(input) {
|
|
163
|
+
return {
|
|
164
|
+
...commonActionFields(input),
|
|
80
165
|
prompt: input.prompt,
|
|
81
166
|
...(input.embeddedActions && input.embeddedActions.length > 0
|
|
82
167
|
? { embeddedActions: input.embeddedActions }
|
|
83
168
|
: {}),
|
|
84
|
-
...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
|
|
85
169
|
};
|
|
86
170
|
}
|
|
87
171
|
function makeBuiltinAction(input) {
|
|
88
172
|
return {
|
|
89
|
-
|
|
173
|
+
...commonActionFields(input),
|
|
90
174
|
kind: 'builtin',
|
|
91
|
-
title: input.title,
|
|
92
|
-
description: input.description,
|
|
93
|
-
order: input.order,
|
|
94
|
-
enabled: input.enabled,
|
|
95
175
|
builtinType: input.builtinType,
|
|
96
176
|
config: input.config,
|
|
97
177
|
...(input.prompt ? { prompt: input.prompt } : {}),
|
|
98
|
-
...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
|
|
99
178
|
};
|
|
100
179
|
}
|
|
180
|
+
/* ── scope + outcome flags (shared by `create` and `update`) ─────────────── */
|
|
181
|
+
exports.AGENT_ACTION_SCOPE_CHOICES = ['general', 'space', 'label'];
|
|
182
|
+
exports.AGENT_ACTION_OUTCOME_CHOICES = ['ephemeral', 'durable'];
|
|
183
|
+
/**
|
|
184
|
+
* Turn the scope flags into a stored scope, or `undefined` when the caller said
|
|
185
|
+
* nothing about scope (so an update leaves the existing one alone).
|
|
186
|
+
*
|
|
187
|
+
* `--space <id>` and `--label <id>` imply their kind, because typing
|
|
188
|
+
* `--scope space --space s1` twice is the kind of ceremony people skip and then
|
|
189
|
+
* wonder why the action is everywhere. An explicit `--scope general` clears it.
|
|
190
|
+
*/
|
|
191
|
+
/**
|
|
192
|
+
* `--label` accepts an id OR a name, like every other `--label` in the CLI.
|
|
193
|
+
*
|
|
194
|
+
* It used to take the value verbatim as a `labelId`. A name was therefore
|
|
195
|
+
* stored as though it were an id, matched no space's `labelIds`, and produced
|
|
196
|
+
* an action offered NOWHERE — silently, with the create reporting success. That
|
|
197
|
+
* is exactly the "an action that disappears reads as deletion" hazard the label
|
|
198
|
+
* tier was designed around, arriving through the CLI instead of through a card
|
|
199
|
+
* that forgot to pass its labels. An unknown name was accepted too, so a typo
|
|
200
|
+
* was indistinguishable from a working scope.
|
|
201
|
+
*
|
|
202
|
+
* `resolveLabelRefs` is the same resolver `spaces create --label` uses: it
|
|
203
|
+
* short-circuits when every value already looks like an id (so a scripted
|
|
204
|
+
* caller pays no request), refuses an unknown name with the near misses named,
|
|
205
|
+
* and refuses an ambiguous one rather than guessing.
|
|
206
|
+
*/
|
|
207
|
+
async function resolveAgentActionScopeFlags(flags) {
|
|
208
|
+
const labelRefs = (flags.label ?? []).map((value) => value.trim()).filter(Boolean);
|
|
209
|
+
const spaceId = flags.space?.trim();
|
|
210
|
+
const declared = flags.scope?.trim();
|
|
211
|
+
const kind = declared ?? (spaceId ? 'space' : labelRefs.length ? 'label' : undefined);
|
|
212
|
+
if (!kind)
|
|
213
|
+
return undefined;
|
|
214
|
+
if (kind === 'general')
|
|
215
|
+
return { kind: 'general' };
|
|
216
|
+
if (kind === 'space') {
|
|
217
|
+
if (!spaceId)
|
|
218
|
+
throw new Error('--scope space requires --space <space-id>.');
|
|
219
|
+
const spaceTitle = flags['space-title']?.trim();
|
|
220
|
+
return { kind: 'space', spaceId, ...(spaceTitle ? { spaceTitle } : {}) };
|
|
221
|
+
}
|
|
222
|
+
if (kind === 'label') {
|
|
223
|
+
if (!labelRefs.length)
|
|
224
|
+
throw new Error('--scope label requires at least one --label <label-id-or-name>.');
|
|
225
|
+
const labelIds = await (0, label_ref_1.resolveLabelRefs)(labelRefs, { applicableTo: 'space' });
|
|
226
|
+
return { kind: 'label', labelIds };
|
|
227
|
+
}
|
|
228
|
+
throw new Error(`--scope must be one of ${exports.AGENT_ACTION_SCOPE_CHOICES.join(', ')}.`);
|
|
229
|
+
}
|
|
230
|
+
/** Human-readable one-liner for a scope, used by list/show renderers. */
|
|
231
|
+
function describeAgentActionScope(scope) {
|
|
232
|
+
if (scope?.kind === 'space')
|
|
233
|
+
return `space:${scope.spaceId}`;
|
|
234
|
+
if (scope?.kind === 'label')
|
|
235
|
+
return `label:${scope.labelIds.join('|')}`;
|
|
236
|
+
return 'general';
|
|
237
|
+
}
|
|
101
238
|
function nextActionOrder(actions) {
|
|
102
239
|
if (actions.length === 0)
|
|
103
240
|
return 0;
|
|
@@ -122,12 +259,19 @@ function renderActions(actions, log) {
|
|
|
122
259
|
target: action.kind === 'builtin'
|
|
123
260
|
? action.builtinType
|
|
124
261
|
: `${(action.prompt || '').trim().length} chars`,
|
|
262
|
+
// Where an action is offered and what it leaves behind decide whether
|
|
263
|
+
// a person ever sees it fire. A listing that omits both makes a
|
|
264
|
+
// mis-scoped action indistinguishable from a working one.
|
|
265
|
+
scope: describeAgentActionScope(action.scope),
|
|
266
|
+
outcome: action.outcome ?? 'ephemeral',
|
|
125
267
|
order: String(action.order),
|
|
126
268
|
})), [
|
|
127
269
|
{ key: 'id', header: 'ID', verbatim: true },
|
|
128
270
|
{ key: 'title', header: 'Title', maxWidth: 30 },
|
|
129
271
|
{ key: 'kind', header: 'Kind' },
|
|
130
272
|
{ key: 'target', header: 'Target', maxWidth: 24 },
|
|
273
|
+
{ key: 'scope', header: 'Scope', maxWidth: 24 },
|
|
274
|
+
{ key: 'outcome', header: 'Outcome' },
|
|
131
275
|
{ key: 'enabled', header: 'On' },
|
|
132
276
|
{ key: 'order', header: 'Order' },
|
|
133
277
|
], log);
|
|
@@ -137,6 +281,8 @@ function renderAction(action, log) {
|
|
|
137
281
|
log(`Title: ${action.title}`);
|
|
138
282
|
log(`Kind: ${actionKind(action)}`);
|
|
139
283
|
log(`Enabled: ${action.enabled === false ? 'no' : 'yes'}`);
|
|
284
|
+
log(`Scope: ${describeAgentActionScope(action.scope)}`);
|
|
285
|
+
log(`Outcome: ${action.outcome ?? 'ephemeral'}`);
|
|
140
286
|
log(`Order: ${action.order}`);
|
|
141
287
|
if (action.description) {
|
|
142
288
|
log(`Description: ${action.description}`);
|