@skrr-ai/cli 0.1.36 → 0.1.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -4
- package/dist/commands/agents/actions/create.d.ts +5 -0
- package/dist/commands/agents/actions/create.js +26 -0
- package/dist/commands/agents/actions/update.d.ts +5 -0
- package/dist/commands/agents/actions/update.js +24 -0
- package/dist/commands/agents/api-actions/add.d.ts +41 -0
- package/dist/commands/agents/api-actions/add.js +202 -0
- package/dist/commands/agents/api-actions/index.d.ts +28 -0
- package/dist/commands/agents/api-actions/index.js +77 -0
- package/dist/commands/agents/api-actions/remove.d.ts +14 -0
- package/dist/commands/agents/api-actions/remove.js +36 -0
- package/dist/commands/agents/avatar/default/apply.d.ts +25 -0
- package/dist/commands/agents/avatar/default/apply.js +56 -0
- package/dist/commands/agents/avatar/default/index.d.ts +18 -0
- package/dist/commands/agents/avatar/default/index.js +44 -0
- package/dist/commands/agents/avatar/default/set.d.ts +23 -0
- package/dist/commands/agents/avatar/default/set.js +95 -0
- package/dist/commands/agents/avatar/library/delete.d.ts +20 -0
- package/dist/commands/agents/avatar/library/delete.js +47 -0
- package/dist/commands/agents/avatar/library/index.d.ts +16 -0
- package/dist/commands/agents/avatar/library/index.js +56 -0
- package/dist/commands/agents/avatar/presets.d.ts +19 -0
- package/dist/commands/agents/avatar/presets.js +56 -0
- package/dist/commands/agents/categories/create.d.ts +14 -0
- package/dist/commands/agents/categories/create.js +46 -0
- package/dist/commands/agents/categories/delete.d.ts +13 -0
- package/dist/commands/agents/categories/delete.js +33 -0
- package/dist/commands/agents/categories/index.d.ts +20 -0
- package/dist/commands/agents/categories/index.js +82 -0
- package/dist/commands/agents/categories/update.d.ts +22 -0
- package/dist/commands/agents/categories/update.js +59 -0
- package/dist/commands/agents/create.d.ts +10 -0
- package/dist/commands/agents/create.js +57 -3
- package/dist/commands/agents/ensure-default.d.ts +27 -0
- package/dist/commands/agents/ensure-default.js +65 -0
- package/dist/commands/agents/mute.d.ts +16 -0
- package/dist/commands/agents/mute.js +38 -0
- package/dist/commands/agents/pin.d.ts +16 -0
- package/dist/commands/agents/pin.js +38 -0
- package/dist/commands/agents/tools/auth.d.ts +19 -0
- package/dist/commands/agents/tools/auth.js +41 -0
- package/dist/commands/agents/tools/calls.d.ts +18 -0
- package/dist/commands/agents/tools/calls.js +54 -0
- package/dist/commands/agents/tools/index.d.ts +20 -0
- package/dist/commands/agents/tools/index.js +77 -0
- package/dist/commands/agents/unmute.d.ts +16 -0
- package/dist/commands/agents/unmute.js +38 -0
- package/dist/commands/agents/unpin.d.ts +16 -0
- package/dist/commands/agents/unpin.js +38 -0
- package/dist/commands/agents/update.d.ts +12 -0
- package/dist/commands/agents/update.js +64 -3
- package/dist/commands/followups/act.d.ts +22 -0
- package/dist/commands/followups/act.js +102 -0
- package/dist/commands/followups/cancel.d.ts +17 -0
- package/dist/commands/followups/cancel.js +40 -0
- package/dist/commands/followups/checkin.d.ts +27 -0
- package/dist/commands/followups/checkin.js +107 -0
- package/dist/commands/followups/list.d.ts +24 -0
- package/dist/commands/followups/list.js +90 -0
- package/dist/commands/followups/remind.d.ts +26 -0
- package/dist/commands/followups/remind.js +106 -0
- package/dist/commands/followups/reschedule.d.ts +15 -0
- package/dist/commands/followups/reschedule.js +48 -0
- package/dist/commands/followups/resolve.d.ts +23 -0
- package/dist/commands/followups/resolve.js +54 -0
- package/dist/commands/followups/show.d.ts +12 -0
- package/dist/commands/followups/show.js +45 -0
- package/dist/commands/followups/watch.d.ts +51 -0
- package/dist/commands/followups/watch.js +207 -0
- package/dist/commands/goals/labels/add.js +19 -2
- package/dist/commands/goals/labels/remove.js +22 -2
- package/dist/commands/labels/list.d.ts +24 -1
- package/dist/commands/labels/list.js +62 -19
- package/dist/commands/memory/governance/index.d.ts +21 -0
- package/dist/commands/memory/governance/index.js +64 -0
- package/dist/commands/memory/governance/set.d.ts +24 -0
- package/dist/commands/memory/governance/set.js +95 -0
- package/dist/commands/memory/provenance.d.ts +18 -0
- package/dist/commands/memory/provenance.js +66 -0
- package/dist/commands/spaces/create.d.ts +3 -0
- package/dist/commands/spaces/create.js +32 -2
- package/dist/commands/spaces/labels/add.js +19 -2
- package/dist/commands/spaces/labels/remove.js +22 -2
- package/dist/commands/spaces/show.js +2 -0
- package/dist/commands/spaces/update.d.ts +5 -0
- package/dist/commands/spaces/update.js +41 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.d.ts +11 -0
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +45 -0
- package/dist/commands/tasks/complete.d.ts +1 -0
- package/dist/commands/tasks/complete.js +8 -1
- package/dist/commands/tasks/create.d.ts +3 -0
- package/dist/commands/tasks/create.js +34 -2
- package/dist/commands/tasks/expectations/assess.d.ts +11 -0
- package/dist/commands/tasks/expectations/assess.js +85 -14
- package/dist/commands/tasks/expectations.js +19 -2
- package/dist/commands/tasks/labels/attach.js +20 -3
- package/dist/commands/tasks/labels/detach.js +21 -3
- package/dist/commands/tasks/lifecycle/attach.d.ts +14 -0
- package/dist/commands/tasks/lifecycle/attach.js +47 -0
- package/dist/commands/tasks/lifecycle/definitions.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/definitions.js +40 -0
- package/dist/commands/tasks/lifecycle/detach.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/detach.js +32 -0
- package/dist/commands/tasks/lifecycle/history.d.ts +13 -0
- package/dist/commands/tasks/lifecycle/history.js +38 -0
- package/dist/commands/tasks/lifecycle/migrate.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/migrate.js +29 -0
- package/dist/commands/tasks/lifecycle/reconcile.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/reconcile.js +27 -0
- package/dist/commands/tasks/lifecycle/reopen.d.ts +13 -0
- package/dist/commands/tasks/lifecycle/reopen.js +34 -0
- package/dist/commands/tasks/lifecycle/show.d.ts +11 -0
- package/dist/commands/tasks/lifecycle/show.js +27 -0
- package/dist/commands/tasks/lifecycle/start.d.ts +12 -0
- package/dist/commands/tasks/lifecycle/start.js +30 -0
- package/dist/commands/tasks/lifecycle/transition.d.ts +15 -0
- package/dist/commands/tasks/lifecycle/transition.js +78 -0
- package/dist/commands/tasks/move.d.ts +1 -0
- package/dist/commands/tasks/move.js +31 -0
- package/dist/commands/tasks/result/submit.js +11 -1
- package/dist/commands/tasks/review-queue.d.ts +29 -0
- package/dist/commands/tasks/review-queue.js +165 -0
- package/dist/commands/tasks/show.js +42 -0
- package/dist/commands/tasks/update.d.ts +1 -0
- package/dist/commands/tasks/update.js +47 -0
- package/dist/lib/agent-actions.d.ts +36 -10
- package/dist/lib/agent-actions.js +63 -9
- package/dist/lib/agent-config.d.ts +11 -0
- package/dist/lib/agent-config.js +85 -3
- package/dist/lib/agent-pin-mute.d.ts +24 -0
- package/dist/lib/agent-pin-mute.js +17 -0
- package/dist/lib/agent-visual-refs.d.ts +6 -0
- package/dist/lib/agent-visual-refs.js +142 -0
- package/dist/lib/first-party-harness-agent.js +7 -0
- package/dist/lib/followups.d.ts +107 -0
- package/dist/lib/followups.js +102 -0
- package/dist/lib/label-ref.d.ts +95 -0
- package/dist/lib/label-ref.js +163 -0
- package/dist/lib/label-scope.d.ts +2 -2
- package/dist/lib/label-scope.js +3 -3
- package/dist/lib/task-closure.d.ts +32 -0
- package/dist/lib/task-closure.js +106 -0
- package/dist/lib/task-lifecycle-output.d.ts +14 -0
- package/dist/lib/task-lifecycle-output.js +101 -0
- package/dist/lib/tasks.d.ts +3 -0
- package/dist/lib/tasks.js +31 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/harnessTrust.js +4 -0
- package/dist/node_modules/@skrr-ai/auth-core/package.json +1 -1
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5079 -4546
- package/oclif.manifest.json +20216 -16002
- package/package.json +16 -4
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../base-command");
|
|
6
|
+
const task_closure_1 = require("../../lib/task-closure");
|
|
7
|
+
const web_url_1 = require("../../lib/web-url");
|
|
8
|
+
/**
|
|
9
|
+
* Everything in one Space that is waiting on a judgement, in one pass.
|
|
10
|
+
*
|
|
11
|
+
* WHY THIS EXISTS
|
|
12
|
+
* ---------------
|
|
13
|
+
* An agent fans out. One session routinely produces nine Tasks carrying twenty
|
|
14
|
+
* or more Expectations, and every surface for settling them was built for one
|
|
15
|
+
* Task at a time — so the cost of CLOSING the work grew linearly with how well
|
|
16
|
+
* the work was DECOMPOSED, which punishes exactly the decomposition the product
|
|
17
|
+
* wants. Finding what was owed meant knowing that `tasks expectations` exists
|
|
18
|
+
* and running it per Task, having first worked out which Tasks to run it on.
|
|
19
|
+
*
|
|
20
|
+
* This is a read. It changes nothing, it names every outstanding judgement in
|
|
21
|
+
* the Space with the evidence already bound to it, and it prints the exact
|
|
22
|
+
* command that settles each one — so a reviewer can work down a list instead of
|
|
23
|
+
* reconstructing it.
|
|
24
|
+
*/
|
|
25
|
+
class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
26
|
+
static description = 'Every Expectation in a Space still awaiting a judgement, with its evidence and the command that settles it';
|
|
27
|
+
static examples = [
|
|
28
|
+
'<%= config.bin %> tasks review-queue --space <space-id>',
|
|
29
|
+
'<%= config.bin %> tasks review-queue --space <space-id> --json',
|
|
30
|
+
'<%= config.bin %> tasks review-queue --space <space-id> --actionable',
|
|
31
|
+
];
|
|
32
|
+
static flags = {
|
|
33
|
+
space: core_1.Flags.string({ description: 'Space id', required: true }),
|
|
34
|
+
actionable: core_1.Flags.boolean({
|
|
35
|
+
description: 'Only Tasks where a Result is already in — the ones a reviewer can act on',
|
|
36
|
+
}),
|
|
37
|
+
limit: core_1.Flags.integer({ description: 'Maximum Tasks to inspect (default 100)', default: 100 }),
|
|
38
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
39
|
+
};
|
|
40
|
+
async run() {
|
|
41
|
+
this.requireAuth();
|
|
42
|
+
const { flags } = await this.parse(TasksReviewQueue);
|
|
43
|
+
/**
|
|
44
|
+
* `response.data`, read from the TYPE rather than guessed.
|
|
45
|
+
*
|
|
46
|
+
* The first version of this read `response.tasks`, which does not exist —
|
|
47
|
+
* and the failure was silent in the worst possible direction: an empty array
|
|
48
|
+
* printed "Nothing is awaiting a judgement" for a Space with twenty-three
|
|
49
|
+
* unassessed Expectations. A reviewer would have believed they were done.
|
|
50
|
+
*
|
|
51
|
+
* `COMMAND_INDEX.md` warns about exactly this ("read the wrong key and you
|
|
52
|
+
* get an empty result rather than an error, which looks exactly like 'no
|
|
53
|
+
* rows matched'"). So the shape is taken from `TaskListResponse` and a
|
|
54
|
+
* missing envelope is an ERROR, never an empty queue: this command's whole
|
|
55
|
+
* value is telling someone there is nothing left, and it may only say that
|
|
56
|
+
* when it actually looked.
|
|
57
|
+
*/
|
|
58
|
+
/*
|
|
59
|
+
* Follow the cursor — a truncated list is the same silent false negative
|
|
60
|
+
* as a misread envelope, one page later. This command's whole value is
|
|
61
|
+
* "there is nothing left," and a tail it never saw breaks that claim.
|
|
62
|
+
* `--limit` caps how many Tasks get inspected, not how many pages get read.
|
|
63
|
+
*/
|
|
64
|
+
if (flags.limit < 1) {
|
|
65
|
+
// Inspecting zero Tasks and then saying "nothing is owed" is the exact
|
|
66
|
+
// unlooked-for empty answer this command refuses to give.
|
|
67
|
+
this.error('--limit must be at least 1.', { exit: 1 });
|
|
68
|
+
}
|
|
69
|
+
const tasks = [];
|
|
70
|
+
try {
|
|
71
|
+
let cursor;
|
|
72
|
+
for (;;) {
|
|
73
|
+
const response = await data_provider_1.dataService.listTasks({
|
|
74
|
+
spaceId: flags.space,
|
|
75
|
+
limit: Math.min(100, flags.limit - tasks.length),
|
|
76
|
+
...(cursor ? { cursor } : {}),
|
|
77
|
+
});
|
|
78
|
+
if (!response || !Array.isArray(response.data)) {
|
|
79
|
+
this.error('The task list came back in a shape this command does not recognise, so it cannot ' +
|
|
80
|
+
'say whether anything is owed. Refusing to report an empty queue.', { exit: 1 });
|
|
81
|
+
}
|
|
82
|
+
tasks.push(...response.data);
|
|
83
|
+
if (!response.has_more || !response.next_cursor || tasks.length >= flags.limit)
|
|
84
|
+
break;
|
|
85
|
+
cursor = response.next_cursor;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
this.handleApiError(error);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Acceptance is read per Task, and a Task whose acceptance cannot be read is
|
|
94
|
+
* REPORTED rather than dropped. A queue that silently omitted a row would be
|
|
95
|
+
* worse than no queue: the reviewer would believe they had seen everything.
|
|
96
|
+
*/
|
|
97
|
+
const rows = [];
|
|
98
|
+
for (const task of tasks) {
|
|
99
|
+
const taskId = String(task.id ?? task._id ?? '');
|
|
100
|
+
if (!taskId)
|
|
101
|
+
continue;
|
|
102
|
+
const base = {
|
|
103
|
+
taskId,
|
|
104
|
+
identifier: String(task.identifier ?? taskId),
|
|
105
|
+
title: String(task.title ?? '(untitled)'),
|
|
106
|
+
status: String(task.status ?? '-'),
|
|
107
|
+
hasResult: Boolean(task.currentResultId),
|
|
108
|
+
};
|
|
109
|
+
try {
|
|
110
|
+
const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskId);
|
|
111
|
+
const awaiting = acceptance.expectations.filter((e) => e.gating && !e.met);
|
|
112
|
+
if (awaiting.length > 0)
|
|
113
|
+
rows.push({ ...base, awaiting });
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
rows.push({ ...base, awaiting: [], error: error?.message || 'unreadable' });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const visible = flags.actionable ? rows.filter((row) => row.hasResult || row.error) : rows;
|
|
120
|
+
if (flags.json) {
|
|
121
|
+
this.log(JSON.stringify({ space: flags.space, tasks: visible }, null, 2));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (visible.length === 0) {
|
|
125
|
+
this.log(`Nothing in ${flags.space} is awaiting a judgement.`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
let total = 0;
|
|
129
|
+
for (const row of visible) {
|
|
130
|
+
this.log('');
|
|
131
|
+
this.log(`${row.identifier} ${row.title}`);
|
|
132
|
+
if (row.error) {
|
|
133
|
+
this.log(` could not read its Expectations: ${row.error}`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
// A Task with no Result yet is listed but marked: its Expectations are
|
|
137
|
+
// owed, and settling them still leaves it unclosable. Saying so here stops
|
|
138
|
+
// a reviewer working through a list that cannot finish.
|
|
139
|
+
if (!row.hasResult) {
|
|
140
|
+
this.log(' no Result submitted yet — settling these will not close it');
|
|
141
|
+
}
|
|
142
|
+
for (const expectation of row.awaiting) {
|
|
143
|
+
total += 1;
|
|
144
|
+
const settledBy = expectation.assessedByKind
|
|
145
|
+
? ` [last judged by ${(0, task_closure_1.describeAssessor)(expectation.assessedByKind)}]`
|
|
146
|
+
: '';
|
|
147
|
+
this.log(` ${expectation.id} ${expectation.sentence || expectation.text || ''}${settledBy}`);
|
|
148
|
+
if (expectation.evidenceLevel) {
|
|
149
|
+
this.log(` evidence: ${expectation.evidenceLevel}${expectation.requiredEvidence ? ` (asked for ${expectation.requiredEvidence})` : ''}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const url = (0, web_url_1.taskUrlFrom)(this.cliConfig.baseURL, { id: row.taskId });
|
|
153
|
+
if (url)
|
|
154
|
+
this.log(` ${url}`);
|
|
155
|
+
}
|
|
156
|
+
this.log('');
|
|
157
|
+
this.log(`${total} Expectation(s) awaiting a judgement across ${visible.length} Task(s).`);
|
|
158
|
+
this.log('');
|
|
159
|
+
this.log('Settle one: skrr tasks expectations assess <task-id> <expectation-id> \\');
|
|
160
|
+
this.log(' --decision met --reason "..."');
|
|
161
|
+
this.log('Settle a Task: skrr tasks expectations assess <task-id> --all \\');
|
|
162
|
+
this.log(' --decision met --reason "..."');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
exports.default = TasksReviewQueue;
|
|
@@ -173,6 +173,20 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
173
173
|
// question and this is the answer to it.
|
|
174
174
|
for (const line of taskFailureLines(t, this.config.bin))
|
|
175
175
|
this.log(line);
|
|
176
|
+
/*
|
|
177
|
+
* Closing is the actor's call — a Task may be `done` with work still
|
|
178
|
+
* outstanding, and `resolution.closure` is where the server recorded what
|
|
179
|
+
* it stood on at close. Show it so a bare "done" never reads as "clean."
|
|
180
|
+
*/
|
|
181
|
+
const resolution = t.resolution;
|
|
182
|
+
if (resolution?.closure && resolution.closure.closable === false) {
|
|
183
|
+
const parts = [];
|
|
184
|
+
const unmet = resolution.closure.expectations?.unmet?.length ?? 0;
|
|
185
|
+
if (unmet > 0)
|
|
186
|
+
parts.push(`${unmet} Expectation${unmet === 1 ? '' : 's'} still unmet`);
|
|
187
|
+
parts.push(...(resolution.closure.blockers || []).filter((c) => c !== 'TASK_EXPECTATIONS_NOT_MET'));
|
|
188
|
+
this.log(`Resolution: ${resolution.kind ?? '-'} — closed over ${parts.join('; ') || 'outstanding items'}`);
|
|
189
|
+
}
|
|
176
190
|
this.log(`Executor: ${t.executionMode ?? 'legacy / inferred'}`);
|
|
177
191
|
this.log(`Priority: ${t.priority ?? '-'}`);
|
|
178
192
|
this.log(`Parent: ${t.parentId ?? '-'}`);
|
|
@@ -291,6 +305,34 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
291
305
|
}
|
|
292
306
|
}
|
|
293
307
|
const ref = String(t.id ?? t._id ?? taskIdentity.id);
|
|
308
|
+
/**
|
|
309
|
+
* Where this Task stands, on the surface people already open.
|
|
310
|
+
*
|
|
311
|
+
* `tasks expectations <id>` answers this well and is reachable only if you
|
|
312
|
+
* already know it exists — its one pointer lives in the `--expect` help of
|
|
313
|
+
* `tasks create`, which you read while AUTHORING and not while closing. So
|
|
314
|
+
* an agent that submitted a Result had no cheap way to learn the Task was
|
|
315
|
+
* still owed, and reasonably concluded from the CLI's own output that it was
|
|
316
|
+
* not. Say it here, where the question is actually asked.
|
|
317
|
+
*
|
|
318
|
+
* Read, not recomputed, and never fatal: a Task page must still render when
|
|
319
|
+
* the acceptance read fails, and it must not invent a state it could not
|
|
320
|
+
* fetch.
|
|
321
|
+
*/
|
|
322
|
+
try {
|
|
323
|
+
const acceptance = await data_provider_1.dataService.getTaskAcceptance(ref);
|
|
324
|
+
const gating = acceptance.expectations.filter((e) => e.gating);
|
|
325
|
+
if (gating.length > 0) {
|
|
326
|
+
const settled = gating.filter((e) => e.met).length;
|
|
327
|
+
this.log('');
|
|
328
|
+
this.log(`Expectations: ${settled} of ${gating.length} settled · overall: ${acceptance.state}` +
|
|
329
|
+
(settled < gating.length ? ` — skrr tasks expectations ${ref}` : ''));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Silent: a Task this caller can VIEW but whose acceptance they cannot
|
|
334
|
+
// read is a permissions shape, not something to shout about mid-page.
|
|
335
|
+
}
|
|
294
336
|
this.log('');
|
|
295
337
|
this.log(`What the agent produced: skrr tasks output ${ref}`);
|
|
296
338
|
if (t.conversationId) {
|
|
@@ -10,6 +10,7 @@ export default class TasksUpdate extends BaseCommand {
|
|
|
10
10
|
task: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
11
|
'from-json': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
12
|
title: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
13
14
|
expect: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
15
|
description: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
16
|
'description-format': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -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,50 @@ 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
|
+
if (expectationsPatch !== undefined || body.expectations !== undefined) {
|
|
255
|
+
let settledCount = 0;
|
|
256
|
+
try {
|
|
257
|
+
const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskIdentity.id);
|
|
258
|
+
settledCount = acceptance.expectations.filter((e) => e.assessmentId).length;
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// An unreadable acceptance is not a reason to refuse the edit. Warn
|
|
262
|
+
// without a number rather than inventing one or blocking the write.
|
|
263
|
+
settledCount = -1;
|
|
264
|
+
}
|
|
265
|
+
if (settledCount !== 0 && !flags.yes) {
|
|
266
|
+
const noun = settledCount === 1 ? 'assessment' : 'assessments';
|
|
267
|
+
const count = settledCount < 0 ? 'Any existing' : `${settledCount} existing`;
|
|
268
|
+
this.log(`Changing Expectations advances the Task specification, so ${count} ${noun} ` +
|
|
269
|
+
'will stop counting and must be recorded again.');
|
|
270
|
+
const ok = await this.confirm('Continue? [y/N] ');
|
|
271
|
+
if (!ok) {
|
|
272
|
+
this.log('No change made.');
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
230
277
|
const payload = (0, prompt_1.mergeDefined)((0, task_resolver_1.stripTaskIdentityFields)(body), {
|
|
231
278
|
title: flags.title,
|
|
232
279
|
expectations: expectationsPatch === null ? [] : (expectationsPatch ?? undefined),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Agent, AgentAction, BuiltinActionConfig, BuiltinActionType, BuiltinAgentAction, EmbeddedActionRef, PromptAgentAction } from '@skrr-ai/data-provider';
|
|
1
|
+
import type { Agent, AgentAction, AgentActionOutcome, AgentActionScope, BuiltinActionConfig, BuiltinActionType, BuiltinAgentAction, EmbeddedActionRef, PromptAgentAction } from '@skrr-ai/data-provider';
|
|
2
2
|
export declare const BUILTIN_ACTION_TYPES: readonly ["slack_send_message", "slack_tool", "group_chat_message", "space_create_task", "space_post_update", "task_create", "task_mark_done", "task_assign", "goal_create", "goal_mark_done", "smart_schedule_plan", "smart_schedule_delta_watch"];
|
|
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];
|
|
@@ -7,28 +7,54 @@ 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
9
|
export declare function updateAgentActions(agentId: string, actions: AgentAction[]): Promise<Agent>;
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Fields every action shape carries regardless of kind.
|
|
12
|
+
*
|
|
13
|
+
* `scope` and `outcome` are listed HERE rather than threaded through each
|
|
14
|
+
* factory's own parameter list, because the previous version enumerated the
|
|
15
|
+
* fields it copied and simply omitted `scope` — so a space-scoped action was
|
|
16
|
+
* unauthorable from the CLI even via `--from-json`, and the omission was
|
|
17
|
+
* invisible (the row wrote fine, it was just offered everywhere).
|
|
18
|
+
*/
|
|
19
|
+
export type AgentActionCommonInput = {
|
|
11
20
|
title: string;
|
|
12
21
|
description?: string;
|
|
13
|
-
prompt: string;
|
|
14
22
|
order: number;
|
|
15
23
|
enabled: boolean;
|
|
16
24
|
id?: string;
|
|
17
25
|
sourceListingId?: string;
|
|
26
|
+
scope?: AgentActionScope;
|
|
27
|
+
outcome?: AgentActionOutcome;
|
|
28
|
+
};
|
|
29
|
+
export declare function makePromptAction(input: AgentActionCommonInput & {
|
|
30
|
+
prompt: string;
|
|
18
31
|
/** Structured built-in actions embedded in the prompt — the chip source of truth. */
|
|
19
32
|
embeddedActions?: EmbeddedActionRef[];
|
|
20
33
|
}): PromptAgentAction;
|
|
21
|
-
export declare function makeBuiltinAction(input: {
|
|
22
|
-
title: string;
|
|
23
|
-
description?: string;
|
|
34
|
+
export declare function makeBuiltinAction(input: AgentActionCommonInput & {
|
|
24
35
|
builtinType: BuiltinActionType;
|
|
25
36
|
config: BuiltinActionConfig | Record<string, unknown>;
|
|
26
37
|
prompt?: string;
|
|
27
|
-
order: number;
|
|
28
|
-
enabled: boolean;
|
|
29
|
-
id?: string;
|
|
30
|
-
sourceListingId?: string;
|
|
31
38
|
}): BuiltinAgentAction;
|
|
39
|
+
export declare const AGENT_ACTION_SCOPE_CHOICES: readonly ["general", "space", "label"];
|
|
40
|
+
export declare const AGENT_ACTION_OUTCOME_CHOICES: readonly ["ephemeral", "durable"];
|
|
41
|
+
export type AgentActionScopeFlags = {
|
|
42
|
+
scope?: string;
|
|
43
|
+
space?: string;
|
|
44
|
+
'space-title'?: string;
|
|
45
|
+
label?: string[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Turn the scope flags into a stored scope, or `undefined` when the caller said
|
|
49
|
+
* nothing about scope (so an update leaves the existing one alone).
|
|
50
|
+
*
|
|
51
|
+
* `--space <id>` and `--label <id>` imply their kind, because typing
|
|
52
|
+
* `--scope space --space s1` twice is the kind of ceremony people skip and then
|
|
53
|
+
* wonder why the action is everywhere. An explicit `--scope general` clears it.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveAgentActionScopeFlags(flags: AgentActionScopeFlags): AgentActionScope | undefined;
|
|
56
|
+
/** Human-readable one-liner for a scope, used by list/show renderers. */
|
|
57
|
+
export declare function describeAgentActionScope(scope?: AgentActionScope | null): string;
|
|
32
58
|
export declare function nextActionOrder(actions: AgentAction[]): number;
|
|
33
59
|
export declare function actionKind(action: AgentAction): 'prompt' | 'builtin';
|
|
34
60
|
export declare function renderActions(actions: AgentAction[], log: (line: string) => void): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
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;
|
|
@@ -8,6 +8,8 @@ exports.findAgentAction = findAgentAction;
|
|
|
8
8
|
exports.updateAgentActions = updateAgentActions;
|
|
9
9
|
exports.makePromptAction = makePromptAction;
|
|
10
10
|
exports.makeBuiltinAction = makeBuiltinAction;
|
|
11
|
+
exports.resolveAgentActionScopeFlags = resolveAgentActionScopeFlags;
|
|
12
|
+
exports.describeAgentActionScope = describeAgentActionScope;
|
|
11
13
|
exports.nextActionOrder = nextActionOrder;
|
|
12
14
|
exports.actionKind = actionKind;
|
|
13
15
|
exports.renderActions = renderActions;
|
|
@@ -70,34 +72,77 @@ async function updateAgentActions(agentId, actions) {
|
|
|
70
72
|
data: { agentActions: actions },
|
|
71
73
|
});
|
|
72
74
|
}
|
|
73
|
-
function
|
|
75
|
+
function commonActionFields(input) {
|
|
74
76
|
return {
|
|
75
77
|
id: input.id ?? (0, node_crypto_1.randomUUID)(),
|
|
76
78
|
title: input.title,
|
|
77
79
|
description: input.description,
|
|
78
80
|
order: input.order,
|
|
79
81
|
enabled: input.enabled,
|
|
82
|
+
...(input.scope ? { scope: input.scope } : {}),
|
|
83
|
+
...(input.outcome ? { outcome: input.outcome } : {}),
|
|
84
|
+
...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function makePromptAction(input) {
|
|
88
|
+
return {
|
|
89
|
+
...commonActionFields(input),
|
|
80
90
|
prompt: input.prompt,
|
|
81
91
|
...(input.embeddedActions && input.embeddedActions.length > 0
|
|
82
92
|
? { embeddedActions: input.embeddedActions }
|
|
83
93
|
: {}),
|
|
84
|
-
...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
|
|
85
94
|
};
|
|
86
95
|
}
|
|
87
96
|
function makeBuiltinAction(input) {
|
|
88
97
|
return {
|
|
89
|
-
|
|
98
|
+
...commonActionFields(input),
|
|
90
99
|
kind: 'builtin',
|
|
91
|
-
title: input.title,
|
|
92
|
-
description: input.description,
|
|
93
|
-
order: input.order,
|
|
94
|
-
enabled: input.enabled,
|
|
95
100
|
builtinType: input.builtinType,
|
|
96
101
|
config: input.config,
|
|
97
102
|
...(input.prompt ? { prompt: input.prompt } : {}),
|
|
98
|
-
...(input.sourceListingId ? { sourceListingId: input.sourceListingId } : {}),
|
|
99
103
|
};
|
|
100
104
|
}
|
|
105
|
+
/* ── scope + outcome flags (shared by `create` and `update`) ─────────────── */
|
|
106
|
+
exports.AGENT_ACTION_SCOPE_CHOICES = ['general', 'space', 'label'];
|
|
107
|
+
exports.AGENT_ACTION_OUTCOME_CHOICES = ['ephemeral', 'durable'];
|
|
108
|
+
/**
|
|
109
|
+
* Turn the scope flags into a stored scope, or `undefined` when the caller said
|
|
110
|
+
* nothing about scope (so an update leaves the existing one alone).
|
|
111
|
+
*
|
|
112
|
+
* `--space <id>` and `--label <id>` imply their kind, because typing
|
|
113
|
+
* `--scope space --space s1` twice is the kind of ceremony people skip and then
|
|
114
|
+
* wonder why the action is everywhere. An explicit `--scope general` clears it.
|
|
115
|
+
*/
|
|
116
|
+
function resolveAgentActionScopeFlags(flags) {
|
|
117
|
+
const labelIds = (flags.label ?? []).map((value) => value.trim()).filter(Boolean);
|
|
118
|
+
const spaceId = flags.space?.trim();
|
|
119
|
+
const declared = flags.scope?.trim();
|
|
120
|
+
const kind = declared ?? (spaceId ? 'space' : labelIds.length ? 'label' : undefined);
|
|
121
|
+
if (!kind)
|
|
122
|
+
return undefined;
|
|
123
|
+
if (kind === 'general')
|
|
124
|
+
return { kind: 'general' };
|
|
125
|
+
if (kind === 'space') {
|
|
126
|
+
if (!spaceId)
|
|
127
|
+
throw new Error('--scope space requires --space <space-id>.');
|
|
128
|
+
const spaceTitle = flags['space-title']?.trim();
|
|
129
|
+
return { kind: 'space', spaceId, ...(spaceTitle ? { spaceTitle } : {}) };
|
|
130
|
+
}
|
|
131
|
+
if (kind === 'label') {
|
|
132
|
+
if (!labelIds.length)
|
|
133
|
+
throw new Error('--scope label requires at least one --label <label-id>.');
|
|
134
|
+
return { kind: 'label', labelIds };
|
|
135
|
+
}
|
|
136
|
+
throw new Error(`--scope must be one of ${exports.AGENT_ACTION_SCOPE_CHOICES.join(', ')}.`);
|
|
137
|
+
}
|
|
138
|
+
/** Human-readable one-liner for a scope, used by list/show renderers. */
|
|
139
|
+
function describeAgentActionScope(scope) {
|
|
140
|
+
if (scope?.kind === 'space')
|
|
141
|
+
return `space:${scope.spaceId}`;
|
|
142
|
+
if (scope?.kind === 'label')
|
|
143
|
+
return `label:${scope.labelIds.join('|')}`;
|
|
144
|
+
return 'general';
|
|
145
|
+
}
|
|
101
146
|
function nextActionOrder(actions) {
|
|
102
147
|
if (actions.length === 0)
|
|
103
148
|
return 0;
|
|
@@ -122,12 +167,19 @@ function renderActions(actions, log) {
|
|
|
122
167
|
target: action.kind === 'builtin'
|
|
123
168
|
? action.builtinType
|
|
124
169
|
: `${(action.prompt || '').trim().length} chars`,
|
|
170
|
+
// Where an action is offered and what it leaves behind decide whether
|
|
171
|
+
// a person ever sees it fire. A listing that omits both makes a
|
|
172
|
+
// mis-scoped action indistinguishable from a working one.
|
|
173
|
+
scope: describeAgentActionScope(action.scope),
|
|
174
|
+
outcome: action.outcome ?? 'ephemeral',
|
|
125
175
|
order: String(action.order),
|
|
126
176
|
})), [
|
|
127
177
|
{ key: 'id', header: 'ID', verbatim: true },
|
|
128
178
|
{ key: 'title', header: 'Title', maxWidth: 30 },
|
|
129
179
|
{ key: 'kind', header: 'Kind' },
|
|
130
180
|
{ key: 'target', header: 'Target', maxWidth: 24 },
|
|
181
|
+
{ key: 'scope', header: 'Scope', maxWidth: 24 },
|
|
182
|
+
{ key: 'outcome', header: 'Outcome' },
|
|
131
183
|
{ key: 'enabled', header: 'On' },
|
|
132
184
|
{ key: 'order', header: 'Order' },
|
|
133
185
|
], log);
|
|
@@ -137,6 +189,8 @@ function renderAction(action, log) {
|
|
|
137
189
|
log(`Title: ${action.title}`);
|
|
138
190
|
log(`Kind: ${actionKind(action)}`);
|
|
139
191
|
log(`Enabled: ${action.enabled === false ? 'no' : 'yes'}`);
|
|
192
|
+
log(`Scope: ${describeAgentActionScope(action.scope)}`);
|
|
193
|
+
log(`Outcome: ${action.outcome ?? 'ephemeral'}`);
|
|
140
194
|
log(`Order: ${action.order}`);
|
|
141
195
|
if (action.description) {
|
|
142
196
|
log(`Description: ${action.description}`);
|
|
@@ -1,2 +1,13 @@
|
|
|
1
|
+
export declare const COMMITMENT_RESPONSIBILITY_LEVELS: readonly ["reasoning_only", "full_ownership"];
|
|
2
|
+
export declare const REASONING_TOOL_ESCAPES: readonly ["bash", "browser"];
|
|
3
|
+
export declare const RELEASE_INSTALL_CHANNELS: readonly ["latest", "manual"];
|
|
4
|
+
/**
|
|
5
|
+
* `09:00-18:00` or `09:00-18:00@America/Los_Angeles`, or a JSON object.
|
|
6
|
+
*
|
|
7
|
+
* The stored shape is `{start, end, timezone}` with `start`/`end` REQUIRED, so
|
|
8
|
+
* the shorthand always supplies both and never a half-open window the schema
|
|
9
|
+
* would reject at write time with a message about a subdocument.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseWorkingHoursFlag(value: string): Record<string, unknown>;
|
|
1
12
|
/** Apply the structured agent fields exposed by the web config editor. */
|
|
2
13
|
export declare function mergeAgentConfigFlags(body: Record<string, unknown>, flags: Record<string, unknown>): Record<string, unknown>;
|
package/dist/lib/agent-config.js
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RELEASE_INSTALL_CHANNELS = exports.REASONING_TOOL_ESCAPES = exports.COMMITMENT_RESPONSIBILITY_LEVELS = void 0;
|
|
4
|
+
exports.parseWorkingHoursFlag = parseWorkingHoursFlag;
|
|
3
5
|
exports.mergeAgentConfigFlags = mergeAgentConfigFlags;
|
|
4
6
|
const prompt_1 = require("./prompt");
|
|
7
|
+
const agent_visual_refs_1 = require("./agent-visual-refs");
|
|
8
|
+
exports.COMMITMENT_RESPONSIBILITY_LEVELS = ['reasoning_only', 'full_ownership'];
|
|
9
|
+
exports.REASONING_TOOL_ESCAPES = ['bash', 'browser'];
|
|
10
|
+
exports.RELEASE_INSTALL_CHANNELS = ['latest', 'manual'];
|
|
11
|
+
/**
|
|
12
|
+
* `09:00-18:00` or `09:00-18:00@America/Los_Angeles`, or a JSON object.
|
|
13
|
+
*
|
|
14
|
+
* The stored shape is `{start, end, timezone}` with `start`/`end` REQUIRED, so
|
|
15
|
+
* the shorthand always supplies both and never a half-open window the schema
|
|
16
|
+
* would reject at write time with a message about a subdocument.
|
|
17
|
+
*/
|
|
18
|
+
function parseWorkingHoursFlag(value) {
|
|
19
|
+
const trimmed = value.trim();
|
|
20
|
+
if (trimmed.startsWith('{'))
|
|
21
|
+
return JSON.parse(trimmed);
|
|
22
|
+
const [window, timezone] = trimmed.split('@');
|
|
23
|
+
const match = /^([0-2]\d:[0-5]\d)-([0-2]\d:[0-5]\d)$/.exec(window ?? '');
|
|
24
|
+
if (!match) {
|
|
25
|
+
throw new Error(`--todo-working-hours: cannot read "${value}". ` +
|
|
26
|
+
'Write HH:MM-HH:MM, optionally @<IANA timezone> — for example ' +
|
|
27
|
+
'09:00-18:00@America/Los_Angeles. A JSON object is also accepted.');
|
|
28
|
+
}
|
|
29
|
+
return timezone
|
|
30
|
+
? { start: match[1], end: match[2], timezone }
|
|
31
|
+
: { start: match[1], end: match[2] };
|
|
32
|
+
}
|
|
5
33
|
/** Apply the structured agent fields exposed by the web config editor. */
|
|
6
34
|
function mergeAgentConfigFlags(body, flags) {
|
|
7
35
|
const json = {
|
|
@@ -22,10 +50,21 @@ function mergeAgentConfigFlags(body, flags) {
|
|
|
22
50
|
if (value !== undefined)
|
|
23
51
|
parsed[field] = JSON.parse(String(value));
|
|
24
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* `avatar` and `sceneBackground` are DISCRIMINATED UNIONS server-side, not
|
|
55
|
+
* strings — see `agent-visual-refs.ts`. `--scene-background` used to sit in
|
|
56
|
+
* the pass-through map below, which made it a flag with no value that could
|
|
57
|
+
* pass validation. Both go through the shared parser.
|
|
58
|
+
*/
|
|
59
|
+
if (flags['scene-background'] !== undefined) {
|
|
60
|
+
parsed.sceneBackground = (0, agent_visual_refs_1.parseSceneBackgroundFlag)(String(flags['scene-background']));
|
|
61
|
+
}
|
|
62
|
+
if (flags.avatar !== undefined) {
|
|
63
|
+
parsed.avatar = (0, agent_visual_refs_1.parseAvatarRefFlag)(String(flags.avatar));
|
|
64
|
+
}
|
|
25
65
|
const direct = {
|
|
26
66
|
'network-mode': 'network_mode',
|
|
27
67
|
'character-3d-id': 'character3DId',
|
|
28
|
-
'scene-background': 'sceneBackground',
|
|
29
68
|
'tone-mode': 'toneMode',
|
|
30
69
|
'tone-id': 'toneId',
|
|
31
70
|
'tone-notes': 'toneNotes',
|
|
@@ -46,8 +85,51 @@ function mergeAgentConfigFlags(body, flags) {
|
|
|
46
85
|
if (flags[flag] !== undefined)
|
|
47
86
|
parsed[field] = flags[flag];
|
|
48
87
|
}
|
|
49
|
-
|
|
50
|
-
|
|
88
|
+
const integers = {
|
|
89
|
+
'recursion-limit': 'recursion_limit',
|
|
90
|
+
'max-turns': 'maxTurns',
|
|
91
|
+
};
|
|
92
|
+
for (const [flag, field] of Object.entries(integers)) {
|
|
93
|
+
if (flags[flag] !== undefined)
|
|
94
|
+
parsed[field] = flags[flag];
|
|
95
|
+
}
|
|
96
|
+
/* Fields the web config editor has always written and no flag reached. */
|
|
97
|
+
if (flags['conversation-starter'] !== undefined) {
|
|
98
|
+
parsed.conversation_starters = flags['conversation-starter'];
|
|
99
|
+
}
|
|
100
|
+
if (flags['todo-working-hours'] !== undefined) {
|
|
101
|
+
parsed.todoWorkingHours = parseWorkingHoursFlag(String(flags['todo-working-hours']));
|
|
102
|
+
}
|
|
103
|
+
if (flags['reasoning-tool-escape'] !== undefined) {
|
|
104
|
+
parsed.reasoningToolEscapes = flags['reasoning-tool-escape'];
|
|
105
|
+
}
|
|
106
|
+
if (flags['commitment-responsibility'] !== undefined) {
|
|
107
|
+
parsed.commitmentResponsibilityDefault = flags['commitment-responsibility'];
|
|
108
|
+
}
|
|
109
|
+
if (flags['commitment-responsibility-ceiling'] !== undefined) {
|
|
110
|
+
parsed.commitmentResponsibilityCeiling = flags['commitment-responsibility-ceiling'];
|
|
111
|
+
}
|
|
112
|
+
if (flags['tool-resources'] !== undefined) {
|
|
113
|
+
parsed.tool_resources = JSON.parse(String(flags['tool-resources']));
|
|
114
|
+
}
|
|
115
|
+
if (flags['project-id'] !== undefined)
|
|
116
|
+
parsed.projectIds = flags['project-id'];
|
|
117
|
+
if (flags['remove-project-id'] !== undefined) {
|
|
118
|
+
parsed.removeProjectIds = flags['remove-project-id'];
|
|
119
|
+
}
|
|
120
|
+
// Two flags, one stored object. Sent whole so a caller who sets only the
|
|
121
|
+
// channel does not silently clear `allowAutoMinorUpdates` — the server
|
|
122
|
+
// replaces the subdocument rather than merging into it.
|
|
123
|
+
if (flags['install-channel'] !== undefined || flags['auto-minor-updates'] !== undefined) {
|
|
124
|
+
const releasePolicy = {};
|
|
125
|
+
if (flags['install-channel'] !== undefined) {
|
|
126
|
+
releasePolicy.defaultInstallChannel = flags['install-channel'];
|
|
127
|
+
}
|
|
128
|
+
if (flags['auto-minor-updates'] !== undefined) {
|
|
129
|
+
releasePolicy.allowAutoMinorUpdates = flags['auto-minor-updates'];
|
|
130
|
+
}
|
|
131
|
+
parsed.releasePolicy = releasePolicy;
|
|
132
|
+
}
|
|
51
133
|
// Cross-Space Task execution ceiling. `0` means unlimited, matching the
|
|
52
134
|
// Space limits' convention so a user learns one spelling of "no cap".
|
|
53
135
|
if (flags['max-concurrent-task-executions'] !== undefined) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pin` / `unpin` / `mute` / `unmute` on top of a TOGGLE endpoint.
|
|
3
|
+
*
|
|
4
|
+
* `PATCH /api/user/agent-preferences/:agentId/pin` flips the bit; it does not
|
|
5
|
+
* take a desired state. A CLI that exposed the flip directly would make
|
|
6
|
+
* `skrr agents pin X` mean "pin it, unless it already was, in which case unpin
|
|
7
|
+
* it" — fine for a button a human clicks while looking at the result, wrong for
|
|
8
|
+
* a command in a script, where the outcome would depend on state the script
|
|
9
|
+
* never read.
|
|
10
|
+
*
|
|
11
|
+
* So the desired state is read first and the toggle is sent only when it
|
|
12
|
+
* differs. That makes each command idempotent and its name true. The read is not
|
|
13
|
+
* a lock: two concurrent invocations can still race, which is a real limit of a
|
|
14
|
+
* toggle endpoint and not something the CLI can fix from out here — the
|
|
15
|
+
* returned state is always what the server says, never what was asked for.
|
|
16
|
+
*/
|
|
17
|
+
export type AgentFlag = 'pin' | 'mute';
|
|
18
|
+
export interface FlagChange {
|
|
19
|
+
/** The value the server reports AFTER this call. */
|
|
20
|
+
value: boolean;
|
|
21
|
+
/** False when the flag already held the desired value and nothing was sent. */
|
|
22
|
+
changed: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function setAgentFlag(agentId: string, flag: AgentFlag, desired: boolean): Promise<FlagChange>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setAgentFlag = setAgentFlag;
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
async function setAgentFlag(agentId, flag, desired) {
|
|
6
|
+
const current = await data_provider_1.dataService.getAgentPreferences(agentId);
|
|
7
|
+
const held = flag === 'pin' ? current.preferences?.isPinned : current.preferences?.isMuted;
|
|
8
|
+
if (Boolean(held) === desired) {
|
|
9
|
+
return { value: desired, changed: false };
|
|
10
|
+
}
|
|
11
|
+
if (flag === 'pin') {
|
|
12
|
+
const result = await data_provider_1.dataService.toggleAgentPin(agentId);
|
|
13
|
+
return { value: result.isPinned, changed: true };
|
|
14
|
+
}
|
|
15
|
+
const result = await data_provider_1.dataService.toggleAgentMute(agentId);
|
|
16
|
+
return { value: result.isMuted, changed: true };
|
|
17
|
+
}
|