@skrr-ai/cli 0.1.37 → 0.1.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/dev-fallback.js +175 -4
- package/dist/base-command.js +46 -2
- package/dist/commands/agents/actions/create.js +18 -7
- package/dist/commands/agents/actions/delete.d.ts +1 -0
- package/dist/commands/agents/actions/delete.js +7 -0
- package/dist/commands/agents/actions/update.js +5 -3
- package/dist/commands/agents/api-actions/add.js +5 -2
- package/dist/commands/agents/api-actions/index.d.ts +11 -0
- package/dist/commands/agents/api-actions/index.js +27 -1
- package/dist/commands/agents/avatar/default/index.d.ts +11 -0
- package/dist/commands/agents/avatar/default/index.js +17 -0
- package/dist/commands/agents/avatar/default/set.d.ts +2 -1
- package/dist/commands/agents/avatar/default/set.js +32 -7
- package/dist/commands/agents/avatar/upload.js +7 -1
- package/dist/commands/agents/categories/delete.js +8 -0
- package/dist/commands/agents/categories/index.d.ts +21 -5
- package/dist/commands/agents/categories/index.js +68 -15
- package/dist/commands/agents/chat.d.ts +21 -0
- package/dist/commands/agents/chat.js +94 -7
- package/dist/commands/agents/create.js +11 -4
- package/dist/commands/agents/list.d.ts +15 -0
- package/dist/commands/agents/list.js +31 -1
- package/dist/commands/agents/scene-background/upload.d.ts +30 -0
- package/dist/commands/agents/scene-background/upload.js +97 -0
- package/dist/commands/agents/show.js +13 -0
- package/dist/commands/agents/tools/calls.d.ts +23 -5
- package/dist/commands/agents/tools/calls.js +81 -18
- package/dist/commands/agents/update.js +15 -5
- package/dist/commands/code/{oversky-agent.d.ts → skrr-agent.d.ts} +3 -3
- package/dist/commands/code/{oversky-agent.js → skrr-agent.js} +11 -8
- package/dist/commands/convos/messages.d.ts +13 -0
- package/dist/commands/convos/messages.js +40 -16
- package/dist/commands/daemon/index.js +8 -1
- package/dist/commands/daemon/logs.d.ts +26 -0
- package/dist/commands/daemon/logs.js +56 -0
- package/dist/commands/daemon/uninstall.js +1 -1
- package/dist/commands/followups/act.js +3 -2
- package/dist/commands/followups/cancel.d.ts +6 -3
- package/dist/commands/followups/cancel.js +16 -6
- package/dist/commands/followups/observability.d.ts +23 -0
- package/dist/commands/followups/observability.js +114 -0
- package/dist/commands/followups/reschedule.js +1 -1
- package/dist/commands/followups/resolve.js +3 -3
- package/dist/commands/followups/show.js +2 -1
- package/dist/commands/followups/watch.js +9 -5
- package/dist/commands/harnesses/forget.js +28 -0
- package/dist/commands/harnesses/install.d.ts +41 -0
- package/dist/commands/harnesses/install.js +165 -0
- package/dist/commands/harnesses/installers.d.ts +45 -0
- package/dist/commands/harnesses/installers.js +155 -0
- package/dist/commands/harnesses/list.d.ts +82 -1
- package/dist/commands/harnesses/list.js +104 -12
- package/dist/commands/harnesses/models.js +10 -1
- package/dist/commands/harnesses/show.d.ts +15 -0
- package/dist/commands/harnesses/show.js +44 -3
- package/dist/commands/harnesses/update.js +1 -1
- package/dist/commands/harnesses/usage.d.ts +25 -0
- package/dist/commands/harnesses/usage.js +24 -2
- package/dist/commands/instructions/status.js +13 -1
- package/dist/commands/machines/dedicated/catalog.js +4 -15
- package/dist/commands/machines/dedicated/create.d.ts +8 -0
- package/dist/commands/machines/dedicated/create.js +63 -2
- package/dist/commands/machines/dedicated/destroy.js +19 -5
- package/dist/commands/machines/dedicated/exec.js +3 -1
- package/dist/commands/machines/dedicated/list.js +9 -6
- package/dist/commands/machines/dedicated/price-book.d.ts +17 -0
- package/dist/commands/machines/dedicated/price-book.js +35 -0
- package/dist/commands/machines/hosted/list.js +12 -0
- package/dist/commands/machines/list.js +11 -0
- package/dist/commands/machines/show.d.ts +1 -0
- package/dist/commands/machines/show.js +40 -11
- package/dist/commands/profiles/list.d.ts +23 -0
- package/dist/commands/profiles/list.js +96 -0
- package/dist/commands/search/skills.d.ts +11 -1
- package/dist/commands/search/skills.js +26 -8
- package/dist/commands/skills/details.d.ts +2 -0
- package/dist/commands/skills/details.js +24 -1
- package/dist/commands/skills/import-as-actions.d.ts +32 -0
- package/dist/commands/skills/import-as-actions.js +175 -0
- package/dist/commands/skills/install.d.ts +2 -0
- package/dist/commands/skills/install.js +24 -1
- package/dist/commands/skills/invocable.js +6 -2
- package/dist/commands/skills/local.d.ts +40 -0
- package/dist/commands/skills/local.js +160 -0
- package/dist/commands/skills/search.d.ts +11 -1
- package/dist/commands/skills/search.js +29 -8
- package/dist/commands/spaces/actions/add.js +23 -5
- package/dist/commands/spaces/actions/available.js +3 -0
- package/dist/commands/spaces/actions/list.d.ts +5 -0
- package/dist/commands/spaces/actions/list.js +49 -3
- package/dist/commands/spaces/actions/run.d.ts +28 -0
- package/dist/commands/spaces/actions/run.js +146 -0
- package/dist/commands/spaces/actions/update.js +27 -5
- package/dist/commands/spaces/label-summaries.d.ts +27 -0
- package/dist/commands/spaces/label-summaries.js +64 -0
- package/dist/commands/spaces/task-rollups.d.ts +5 -0
- package/dist/commands/spaces/task-rollups.js +15 -4
- package/dist/commands/spaces/workflows/lifecycle-diagnostics.js +63 -3
- package/dist/commands/tasks/actions/attach.js +32 -7
- package/dist/commands/tasks/complete.js +13 -0
- package/dist/commands/tasks/create.js +1 -1
- package/dist/commands/tasks/events/append.js +29 -6
- package/dist/commands/tasks/expectations/assess.d.ts +1 -0
- package/dist/commands/tasks/expectations/assess.js +43 -5
- package/dist/commands/tasks/expectations.js +77 -16
- package/dist/commands/tasks/follow-up.js +2 -2
- package/dist/commands/tasks/lifecycle/definitions.js +21 -2
- package/dist/commands/tasks/lifecycle/detach.d.ts +7 -0
- package/dist/commands/tasks/lifecycle/detach.js +43 -3
- package/dist/commands/tasks/lifecycle/migrate.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/migrate.js +42 -3
- package/dist/commands/tasks/lifecycle/reopen.d.ts +2 -0
- package/dist/commands/tasks/lifecycle/reopen.js +40 -3
- package/dist/commands/tasks/lifecycle/transition.js +33 -2
- package/dist/commands/tasks/list.js +16 -9
- package/dist/commands/tasks/move.js +11 -13
- package/dist/commands/tasks/review-queue.d.ts +15 -0
- package/dist/commands/tasks/review-queue.js +180 -31
- package/dist/commands/tasks/show.d.ts +11 -0
- package/dist/commands/tasks/show.js +105 -12
- package/dist/commands/tasks/trust.js +7 -2
- package/dist/commands/tasks/update.js +46 -10
- package/dist/commands/tasks/updates/add.js +1 -1
- package/dist/commands/token/list.d.ts +22 -0
- package/dist/commands/token/list.js +68 -0
- package/dist/commands/token/revoke.d.ts +23 -0
- package/dist/commands/token/revoke.js +53 -0
- package/dist/lib/agent-actions.d.ts +57 -2
- package/dist/lib/agent-actions.js +113 -21
- package/dist/lib/agent-pin-mute.d.ts +10 -5
- package/dist/lib/agent-pin-mute.js +17 -4
- package/dist/lib/agent-visual-refs.d.ts +27 -0
- package/dist/lib/agent-visual-refs.js +127 -2
- package/dist/lib/agentic-stream.d.ts +6 -0
- package/dist/lib/agentic-stream.js +34 -3
- package/dist/lib/assignee-resolver.d.ts +1 -1
- package/dist/lib/assignee-resolver.js +8 -0
- package/dist/lib/bulk-task-targets.d.ts +12 -0
- package/dist/lib/bulk-task-targets.js +34 -1
- package/dist/lib/cli-installers.d.ts +130 -0
- package/dist/lib/cli-installers.js +145 -0
- package/dist/lib/command-miss.js +55 -7
- package/dist/lib/dedicated-lease-command.d.ts +16 -1
- package/dist/lib/dedicated-lease-command.js +26 -3
- package/dist/lib/dedicated-machines.d.ts +135 -1
- package/dist/lib/dedicated-machines.js +307 -3
- package/dist/lib/failed-lookup.d.ts +3 -0
- package/dist/lib/failed-lookup.js +40 -0
- package/dist/lib/first-party-harness-agent.js +9 -2
- package/dist/lib/first-party-harness-doctor.d.ts +15 -0
- package/dist/lib/first-party-harness-doctor.js +126 -27
- package/dist/lib/followups.d.ts +14 -6
- package/dist/lib/followups.js +31 -6
- package/dist/lib/harnesses.d.ts +8 -0
- package/dist/lib/instruction-input.d.ts +19 -1
- package/dist/lib/instruction-input.js +52 -1
- package/dist/lib/label-scope.d.ts +15 -0
- package/dist/lib/label-scope.js +25 -5
- package/dist/lib/local-skills.d.ts +98 -0
- package/dist/lib/local-skills.js +195 -0
- package/dist/lib/machines.d.ts +10 -10
- package/dist/lib/machines.js +23 -1
- package/dist/lib/search-query.d.ts +19 -0
- package/dist/lib/search-query.js +35 -0
- package/dist/lib/space-custom-actions.d.ts +72 -0
- package/dist/lib/space-custom-actions.js +117 -0
- package/dist/lib/space-resolver.d.ts +1 -21
- package/dist/lib/space-resolver.js +19 -10
- package/dist/lib/task-closure.d.ts +3 -2
- package/dist/lib/task-closure.js +18 -20
- package/dist/lib/task-lifecycle-output.js +117 -9
- package/dist/lib/task-ref-resolver.d.ts +1 -17
- package/dist/lib/task-ref-resolver.js +18 -8
- package/dist/lib/tasks.js +9 -3
- package/dist/node_modules/@skrr-ai/data-provider/index.js +5076 -4947
- package/oclif.manifest.json +15505 -14460
- package/package.json +9 -3
|
@@ -35,6 +35,9 @@ class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
|
35
35
|
description: 'Only Tasks where a Result is already in — the ones a reviewer can act on',
|
|
36
36
|
}),
|
|
37
37
|
limit: core_1.Flags.integer({ description: 'Maximum Tasks to inspect (default 100)', default: 100 }),
|
|
38
|
+
'include-closed': core_1.Flags.boolean({
|
|
39
|
+
description: 'Also list Tasks already closed — for auditing what was closed over',
|
|
40
|
+
}),
|
|
38
41
|
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
39
42
|
};
|
|
40
43
|
async run() {
|
|
@@ -66,7 +69,27 @@ class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
|
66
69
|
// unlooked-for empty answer this command refuses to give.
|
|
67
70
|
this.error('--limit must be at least 1.', { exit: 1 });
|
|
68
71
|
}
|
|
72
|
+
/*
|
|
73
|
+
* oclif's `required: true` asserts the flag was SUPPLIED, not that it says
|
|
74
|
+
* anything. `--space ""` — an unset shell variable, which is how it happens
|
|
75
|
+
* — satisfied it, and the empty string was then dropped from the query
|
|
76
|
+
* string as falsy, so the command silently widened from one Space to every
|
|
77
|
+
* Space the caller can see and reported that as the answer.
|
|
78
|
+
*/
|
|
79
|
+
if (!flags.space.trim()) {
|
|
80
|
+
this.error('--space needs a Space id; it was given an empty value.', { exit: 1 });
|
|
81
|
+
}
|
|
69
82
|
const tasks = [];
|
|
83
|
+
/*
|
|
84
|
+
* Whether the scan actually reached the end.
|
|
85
|
+
*
|
|
86
|
+
* The loop already followed the cursor, and then stopped at `--limit` with
|
|
87
|
+
* `has_more` still true and threw that fact away — so a Space with 95 owed
|
|
88
|
+
* Expectations reported on the first 11 and printed the same sentence it
|
|
89
|
+
* prints for a Space that owes nothing. The comment above states the
|
|
90
|
+
* principle this had to satisfy; nothing recorded whether it had.
|
|
91
|
+
*/
|
|
92
|
+
let truncated = false;
|
|
70
93
|
try {
|
|
71
94
|
let cursor;
|
|
72
95
|
for (;;) {
|
|
@@ -80,8 +103,12 @@ class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
|
80
103
|
'say whether anything is owed. Refusing to report an empty queue.', { exit: 1 });
|
|
81
104
|
}
|
|
82
105
|
tasks.push(...response.data);
|
|
83
|
-
if (!response.has_more || !response.next_cursor
|
|
106
|
+
if (!response.has_more || !response.next_cursor)
|
|
107
|
+
break;
|
|
108
|
+
if (tasks.length >= flags.limit) {
|
|
109
|
+
truncated = true;
|
|
84
110
|
break;
|
|
111
|
+
}
|
|
85
112
|
cursor = response.next_cursor;
|
|
86
113
|
}
|
|
87
114
|
}
|
|
@@ -95,34 +122,101 @@ class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
|
95
122
|
* worse than no queue: the reviewer would believe they had seen everything.
|
|
96
123
|
*/
|
|
97
124
|
const rows = [];
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
/*
|
|
126
|
+
* A finished Task is not a worklist item.
|
|
127
|
+
*
|
|
128
|
+
* Closing is the closer's call now, so a Task can reach `done` over
|
|
129
|
+
* Expectations nobody judged — and those rows stayed in the queue forever,
|
|
130
|
+
* captioned in the present tense ("settling these will not close it") about
|
|
131
|
+
* something already closed. Every forced close permanently added noise to
|
|
132
|
+
* the list a reviewer is supposed to work down. `--include-closed` keeps the
|
|
133
|
+
* old view for anyone auditing what was closed over.
|
|
134
|
+
*/
|
|
135
|
+
const CLOSED_STATUS_TYPES = new Set(['completed', 'cancelled']);
|
|
136
|
+
const candidates = tasks.filter((task) => flags['include-closed'] || !CLOSED_STATUS_TYPES.has(String(task.statusType ?? '')));
|
|
137
|
+
const skippedClosed = tasks.length - candidates.length;
|
|
138
|
+
/*
|
|
139
|
+
* Acceptance is one request per Task and there is no batch endpoint, so the
|
|
140
|
+
* serial loop this replaces took 61 seconds on 100 Tasks and printed nothing
|
|
141
|
+
* at all until it finished. Bounded rather than `Promise.all`: 100
|
|
142
|
+
* simultaneous authorized reads hit the same cascade the `/cards` endpoint
|
|
143
|
+
* exists to avoid. Results are written by INDEX so output order stays the
|
|
144
|
+
* list's order regardless of which request returns first.
|
|
145
|
+
*/
|
|
146
|
+
const ACCEPTANCE_CONCURRENCY = 6;
|
|
147
|
+
const settled = new Array(candidates.length).fill(null);
|
|
148
|
+
let next = 0;
|
|
149
|
+
const worker = async () => {
|
|
150
|
+
for (;;) {
|
|
151
|
+
const index = next;
|
|
152
|
+
next += 1;
|
|
153
|
+
if (index >= candidates.length)
|
|
154
|
+
return;
|
|
155
|
+
const task = candidates[index];
|
|
156
|
+
const taskId = String(task.id ?? task._id ?? '');
|
|
157
|
+
if (!taskId)
|
|
158
|
+
continue;
|
|
159
|
+
const base = {
|
|
160
|
+
taskId,
|
|
161
|
+
identifier: String(task.identifier ?? taskId),
|
|
162
|
+
title: String(task.title ?? '(untitled)'),
|
|
163
|
+
status: String(task.status ?? '-'),
|
|
164
|
+
hasResult: Boolean(task.currentResultId),
|
|
165
|
+
};
|
|
166
|
+
try {
|
|
167
|
+
const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskId);
|
|
168
|
+
const awaiting = acceptance.expectations.filter((e) => e.gating && !e.met);
|
|
169
|
+
if (awaiting.length > 0)
|
|
170
|
+
settled[index] = { ...base, awaiting };
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
settled[index] = {
|
|
174
|
+
...base,
|
|
175
|
+
awaiting: [],
|
|
176
|
+
error: error?.message || 'unreadable',
|
|
177
|
+
};
|
|
178
|
+
}
|
|
117
179
|
}
|
|
118
|
-
}
|
|
180
|
+
};
|
|
181
|
+
await Promise.all(Array.from({ length: Math.min(ACCEPTANCE_CONCURRENCY, candidates.length) }, worker));
|
|
182
|
+
rows.push(...settled.filter((row) => row !== null));
|
|
119
183
|
const visible = flags.actionable ? rows.filter((row) => row.hasResult || row.error) : rows;
|
|
120
184
|
if (flags.json) {
|
|
121
|
-
this.log(JSON.stringify({
|
|
185
|
+
this.log(JSON.stringify({
|
|
186
|
+
space: flags.space,
|
|
187
|
+
inspected: candidates.length,
|
|
188
|
+
truncated,
|
|
189
|
+
...(skippedClosed > 0 ? { skippedClosed } : {}),
|
|
190
|
+
owedTasks: rows.length,
|
|
191
|
+
tasks: visible,
|
|
192
|
+
}, null, 2));
|
|
122
193
|
return;
|
|
123
194
|
}
|
|
124
|
-
|
|
195
|
+
/*
|
|
196
|
+
* "Nothing is owed" may only be said by a scan that reached the end.
|
|
197
|
+
*
|
|
198
|
+
* One sentence used to cover four different states — a clean queue, a
|
|
199
|
+
* truncated scan, a filter that emptied the list, and a Space that does not
|
|
200
|
+
* exist — and in three of them it was false. Each now says its own thing,
|
|
201
|
+
* and the two that cannot support the claim refuse to make it, in the same
|
|
202
|
+
* shape as the misread-envelope guard above.
|
|
203
|
+
*/
|
|
204
|
+
if (truncated && rows.length === 0) {
|
|
205
|
+
this.error(`Inspected only the first ${candidates.length} Task(s) of a longer list in ${flags.space}, ` +
|
|
206
|
+
'so it cannot say whether anything is owed. Refusing to report an empty queue. ' +
|
|
207
|
+
'Re-run with a larger --limit.', { exit: 1 });
|
|
208
|
+
}
|
|
209
|
+
if (rows.length === 0) {
|
|
210
|
+
await this.assertSpaceExists(flags.space);
|
|
125
211
|
this.log(`Nothing in ${flags.space} is awaiting a judgement.`);
|
|
212
|
+
if (skippedClosed > 0) {
|
|
213
|
+
this.log(` (${skippedClosed} closed Task(s) skipped — see them with --include-closed.)`);
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (visible.length === 0) {
|
|
218
|
+
this.log(`${rows.length} Task(s) in ${flags.space} owe judgements, but none has a Result yet — ` +
|
|
219
|
+
're-run without --actionable to see them.');
|
|
126
220
|
return;
|
|
127
221
|
}
|
|
128
222
|
let total = 0;
|
|
@@ -133,18 +227,37 @@ class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
|
133
227
|
this.log(` could not read its Expectations: ${row.error}`);
|
|
134
228
|
continue;
|
|
135
229
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
230
|
+
/*
|
|
231
|
+
* State the fact, not a gate. This read "no Result submitted yet — settling
|
|
232
|
+
* these will not close it", which implied that a Result is what stands
|
|
233
|
+
* between these judgements and a close. Since `56a6ded703` it is not: a
|
|
234
|
+
* Task closes without one and the absence is recorded on
|
|
235
|
+
* `resolution.closure`. What a reviewer needs to know is only that there is
|
|
236
|
+
* no Result to judge the work against yet.
|
|
237
|
+
*/
|
|
139
238
|
if (!row.hasResult) {
|
|
140
|
-
this.log(' no Result submitted yet —
|
|
239
|
+
this.log(' no Result submitted yet — nothing to judge the work against');
|
|
141
240
|
}
|
|
142
241
|
for (const expectation of row.awaiting) {
|
|
143
242
|
total += 1;
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
243
|
+
this.log(` ${expectation.id} ${expectation.sentence || expectation.text || ''}`);
|
|
244
|
+
/*
|
|
245
|
+
* The judgement itself, not just the KIND of judge.
|
|
246
|
+
*
|
|
247
|
+
* `[last judged by person]` named no person, no decision, no date and no
|
|
248
|
+
* reason — so a reviewer working down this list could see that someone
|
|
249
|
+
* had looked and not what they concluded, which is the one thing they
|
|
250
|
+
* need before looking again. The acceptance projection carries all of it
|
|
251
|
+
* now; this is where it was being dropped.
|
|
252
|
+
*/
|
|
253
|
+
if (expectation.assessedByKind) {
|
|
254
|
+
const decision = expectation.decision || 'judged';
|
|
255
|
+
const when = expectation.assessedAt
|
|
256
|
+
? ` on ${String(expectation.assessedAt).slice(0, 10)}`
|
|
257
|
+
: '';
|
|
258
|
+
const why = expectation.reason ? `: ${expectation.reason}` : '';
|
|
259
|
+
this.log(` ${decision} by ${(0, task_closure_1.describeAssessor)(expectation.assessedByKind)}${when}${why}`);
|
|
260
|
+
}
|
|
148
261
|
if (expectation.evidenceLevel) {
|
|
149
262
|
this.log(` evidence: ${expectation.evidenceLevel}${expectation.requiredEvidence ? ` (asked for ${expectation.requiredEvidence})` : ''}`);
|
|
150
263
|
}
|
|
@@ -155,11 +268,47 @@ class TasksReviewQueue extends base_command_1.BaseCommand {
|
|
|
155
268
|
}
|
|
156
269
|
this.log('');
|
|
157
270
|
this.log(`${total} Expectation(s) awaiting a judgement across ${visible.length} Task(s).`);
|
|
271
|
+
if (truncated) {
|
|
272
|
+
this.log(`Only the first ${candidates.length} Task(s) were inspected and more remain — ` +
|
|
273
|
+
're-run with a larger --limit to see the rest.');
|
|
274
|
+
}
|
|
275
|
+
if (skippedClosed > 0) {
|
|
276
|
+
this.log(`${skippedClosed} closed Task(s) skipped — see them with --include-closed.`);
|
|
277
|
+
}
|
|
158
278
|
this.log('');
|
|
159
279
|
this.log('Settle one: skrr tasks expectations assess <task-id> <expectation-id> \\');
|
|
160
280
|
this.log(' --decision met --reason "..."');
|
|
161
281
|
this.log('Settle a Task: skrr tasks expectations assess <task-id> --all \\');
|
|
162
282
|
this.log(' --decision met --reason "..."');
|
|
163
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* An empty queue must not be how you learn a Space id is wrong.
|
|
286
|
+
*
|
|
287
|
+
* A UUID-shaped ref is accepted without a lookup (`base-command` short-circuits
|
|
288
|
+
* on the SHAPE, which is a cheap and correct optimisation nearly everywhere),
|
|
289
|
+
* and the list route deliberately never 404s — an unknown Space falls back to
|
|
290
|
+
* the ACL enumeration and returns an honest empty page. Those two reasonable
|
|
291
|
+
* decisions compose into "Nothing is awaiting a judgement", exit 0, for a
|
|
292
|
+
* Space that does not exist. A typo read as done.
|
|
293
|
+
*
|
|
294
|
+
* So the existence check is paid for ONLY on the path that is about to make
|
|
295
|
+
* the completeness claim — never on the path that found work.
|
|
296
|
+
*/
|
|
297
|
+
async assertSpaceExists(spaceId) {
|
|
298
|
+
try {
|
|
299
|
+
await data_provider_1.dataService.getSpace(spaceId);
|
|
300
|
+
}
|
|
301
|
+
catch (error) {
|
|
302
|
+
// The status rides the error itself here, the way `base-command` reads it
|
|
303
|
+
// (`e.status === 404`) — not on a nested `response`.
|
|
304
|
+
const status = error?.status;
|
|
305
|
+
if (status === 404 || status === 403) {
|
|
306
|
+
this.error(`No Space ${spaceId} is visible to you, so there is nothing to report on. ` +
|
|
307
|
+
'Check the id with `skrr spaces list`.', { exit: 2 });
|
|
308
|
+
}
|
|
309
|
+
// Any other failure is about this read, not about the Space. Let the
|
|
310
|
+
// empty answer stand rather than turning a blip into a false "not found".
|
|
311
|
+
}
|
|
312
|
+
}
|
|
164
313
|
}
|
|
165
314
|
exports.default = TasksReviewQueue;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { BaseCommand } from '../../base-command';
|
|
2
|
+
/**
|
|
3
|
+
* Where to look next — as COMMANDS, not as facts about the task.
|
|
4
|
+
*
|
|
5
|
+
* These used to print as `What the agent produced: skrr tasks output <ref>`,
|
|
6
|
+
* in the same `Label: value` grammar as every line above them, so the line read
|
|
7
|
+
* as a statement of what the agent had produced. It also printed on tasks no
|
|
8
|
+
* agent had ever run, asserting output that did not exist (OSK-9669). They are
|
|
9
|
+
* now a visibly separate list, and only once a run, a conversation or a Result
|
|
10
|
+
* exists for them to show.
|
|
11
|
+
*/
|
|
12
|
+
export declare function taskPointerLines(t: Record<string, unknown>, ref: string, bin?: string): string[];
|
|
2
13
|
/**
|
|
3
14
|
* The failure rows of `tasks show`, when there are any. (S3 dogfood finding)
|
|
4
15
|
*
|
|
@@ -1,14 +1,43 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.taskPointerLines = taskPointerLines;
|
|
3
4
|
exports.taskFailureLines = taskFailureLines;
|
|
4
5
|
const core_1 = require("@oclif/core");
|
|
5
6
|
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
6
7
|
const api_fetch_1 = require("../../lib/api-fetch");
|
|
7
8
|
const session_task_endpoints_1 = require("../../lib/session-task-endpoints");
|
|
8
9
|
const base_command_1 = require("../../base-command");
|
|
10
|
+
const task_closure_1 = require("../../lib/task-closure");
|
|
9
11
|
const task_resolver_1 = require("../../lib/task-resolver");
|
|
10
12
|
const web_url_1 = require("../../lib/web-url");
|
|
11
13
|
const html_text_1 = require("../../lib/html-text");
|
|
14
|
+
/**
|
|
15
|
+
* Where to look next — as COMMANDS, not as facts about the task.
|
|
16
|
+
*
|
|
17
|
+
* These used to print as `What the agent produced: skrr tasks output <ref>`,
|
|
18
|
+
* in the same `Label: value` grammar as every line above them, so the line read
|
|
19
|
+
* as a statement of what the agent had produced. It also printed on tasks no
|
|
20
|
+
* agent had ever run, asserting output that did not exist (OSK-9669). They are
|
|
21
|
+
* now a visibly separate list, and only once a run, a conversation or a Result
|
|
22
|
+
* exists for them to show.
|
|
23
|
+
*/
|
|
24
|
+
function taskPointerLines(t, ref, bin = 'skrr') {
|
|
25
|
+
const hasSomethingToShow = Boolean(t.conversationId || t.lastFinalizedRunId || t.checkoutRunId || t.currentResultId);
|
|
26
|
+
if (!hasSomethingToShow)
|
|
27
|
+
return [];
|
|
28
|
+
const pointers = [
|
|
29
|
+
[`${bin} tasks output ${ref}`, 'what the agent produced'],
|
|
30
|
+
];
|
|
31
|
+
if (t.conversationId) {
|
|
32
|
+
pointers.push([`${bin} tasks transcript ${ref}`, 'the full agent transcript']);
|
|
33
|
+
}
|
|
34
|
+
const width = Math.max(...pointers.map(([command]) => command.length));
|
|
35
|
+
return [
|
|
36
|
+
'',
|
|
37
|
+
'See also:',
|
|
38
|
+
...pointers.map(([command, what]) => ` ${command.padEnd(width)} ${what}`),
|
|
39
|
+
];
|
|
40
|
+
}
|
|
12
41
|
/**
|
|
13
42
|
* The failure rows of `tasks show`, when there are any. (S3 dogfood finding)
|
|
14
43
|
*
|
|
@@ -179,13 +208,80 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
179
208
|
* it stood on at close. Show it so a bare "done" never reads as "clean."
|
|
180
209
|
*/
|
|
181
210
|
const resolution = t.resolution;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
211
|
+
/*
|
|
212
|
+
* Same renderer as the `tasks move` receipt, so the two cannot disagree
|
|
213
|
+
* about a Task they are both describing.
|
|
214
|
+
*
|
|
215
|
+
* This copy showed an owner's ordinary close as an override:
|
|
216
|
+
* `TASK_RESULT_REVIEW_REQUIRED` lands in `blockers` whenever the policy is
|
|
217
|
+
* unsatisfied — including when the owner, who is not bound by the Review
|
|
218
|
+
* they declared, closes it themselves — and this rendered it identically to
|
|
219
|
+
* a genuine forced close. So the only read surface for "was this gate
|
|
220
|
+
* overridden?" could not answer the question.
|
|
221
|
+
*/
|
|
222
|
+
if (resolution?.closure) {
|
|
223
|
+
const sentences = (0, task_closure_1.closureSnapshotLines)(resolution.closure);
|
|
224
|
+
if (sentences.length > 0) {
|
|
225
|
+
this.log(`Resolution: ${resolution.kind ?? '-'} — ${sentences.join(' ')}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
/*
|
|
229
|
+
* A Result orphaned by a spec edit is not the same as no Result.
|
|
230
|
+
*
|
|
231
|
+
* Editing a `description` or an Expectation advances `specVersion`, which
|
|
232
|
+
* unsets `currentResultId` by design — the old answer replied to a question
|
|
233
|
+
* that has changed. But every CLI surface then reported the Task as though
|
|
234
|
+
* nothing had ever been submitted, and the prior Result is still there. The
|
|
235
|
+
* web already says this correctly ("No Result answers the current Task spec
|
|
236
|
+
* vN", plus the previous one); the CLI said nothing at all.
|
|
237
|
+
*
|
|
238
|
+
* The extra request is paid only in the ambiguous case — when there is no
|
|
239
|
+
* current Result — and `tasks show` is a detail view, so one call to
|
|
240
|
+
* distinguish "nobody answered" from "the answer is out of date" is worth
|
|
241
|
+
* it. A failed lookup degrades to silence rather than to a claim.
|
|
242
|
+
*/
|
|
243
|
+
const taskSpecVersion = Number(t.specVersion) || 1;
|
|
244
|
+
if (t.currentResultId) {
|
|
245
|
+
this.log(`Result: ${String(t.currentResultId)} (answers spec v${taskSpecVersion})`);
|
|
246
|
+
/*
|
|
247
|
+
* The Review on that Result, with its REASON.
|
|
248
|
+
*
|
|
249
|
+
* Closing over a `changes_requested` Review is allowed and recorded, and
|
|
250
|
+
* the closure line says "a reviewer requested changes" — the verdict. What
|
|
251
|
+
* they asked for lived only on the Review row, which no text surface
|
|
252
|
+
* printed, so the objection survived as a fact and lost its content. One
|
|
253
|
+
* read, on a detail view, only when there is a Result to have been
|
|
254
|
+
* reviewed; a failed read says nothing rather than implying no Review.
|
|
255
|
+
*/
|
|
256
|
+
try {
|
|
257
|
+
const history = await data_provider_1.dataService.listTaskResults(taskIdentity.id);
|
|
258
|
+
const review = (history?.reviews || []).find((row) => row.resultId === String(t.currentResultId));
|
|
259
|
+
if (review) {
|
|
260
|
+
const who = (0, task_closure_1.describeAssessor)(review.reviewedBy?.kind);
|
|
261
|
+
const when = review.reviewedAt ? ` on ${String(review.reviewedAt).slice(0, 10)}` : '';
|
|
262
|
+
const why = review.rationale ? `: ${review.rationale}` : '';
|
|
263
|
+
this.log(`Review: ${review.decision} by ${who}${when}${why}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
// Silence, not "no Review": this read failing is not evidence of absence.
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
let priorLine = 'none submitted';
|
|
272
|
+
try {
|
|
273
|
+
const history = await data_provider_1.dataService.listTaskResults(taskIdentity.id);
|
|
274
|
+
const prior = history?.results?.[0];
|
|
275
|
+
if (prior) {
|
|
276
|
+
priorLine =
|
|
277
|
+
`none answers spec v${taskSpecVersion} — previous v${prior.version} ` +
|
|
278
|
+
`answered spec v${prior.specVersion ?? '?'}`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
priorLine = 'none answers the current spec (earlier Results could not be read)';
|
|
283
|
+
}
|
|
284
|
+
this.log(`Result: ${priorLine}`);
|
|
189
285
|
}
|
|
190
286
|
this.log(`Executor: ${t.executionMode ?? 'legacy / inferred'}`);
|
|
191
287
|
this.log(`Priority: ${t.priority ?? '-'}`);
|
|
@@ -333,11 +429,8 @@ class TasksShow extends base_command_1.BaseCommand {
|
|
|
333
429
|
// Silent: a Task this caller can VIEW but whose acceptance they cannot
|
|
334
430
|
// read is a permissions shape, not something to shout about mid-page.
|
|
335
431
|
}
|
|
336
|
-
this.
|
|
337
|
-
|
|
338
|
-
if (t.conversationId) {
|
|
339
|
-
this.log(`Full agent transcript: skrr tasks transcript ${ref}`);
|
|
340
|
-
}
|
|
432
|
+
for (const line of taskPointerLines(t, ref, this.config.bin))
|
|
433
|
+
this.log(line);
|
|
341
434
|
}
|
|
342
435
|
}
|
|
343
436
|
exports.default = TasksShow;
|
|
@@ -41,8 +41,13 @@ class TasksTrust extends base_command_1.BaseCommand {
|
|
|
41
41
|
level: core_1.Flags.string({
|
|
42
42
|
options: [...data_provider_1.DELIVERABLE_AUTHORITIES],
|
|
43
43
|
required: true,
|
|
44
|
-
description:
|
|
45
|
-
|
|
44
|
+
description:
|
|
45
|
+
// `observation_backed` is a RETIRED rung name for this domain — the flag
|
|
46
|
+
// rejects it, so the only two values the help explained were one real one
|
|
47
|
+
// and one the command refuses. The four the enum actually accepts:
|
|
48
|
+
'How well evidenced the answer must be: self_reported (the doer says so), ' +
|
|
49
|
+
'human_confirmed (a person confirmed it), system_observed (the platform saw it), ' +
|
|
50
|
+
'external_receipt (a provider receipt proves it).',
|
|
46
51
|
}),
|
|
47
52
|
reason: core_1.Flags.string({
|
|
48
53
|
required: true,
|
|
@@ -251,26 +251,62 @@ class TasksUpdate extends base_command_1.BaseCommand {
|
|
|
251
251
|
* rewrote the list and revoked the assessments with no warning at all.
|
|
252
252
|
* Same write, same price: the disclosure belongs on the effective change.
|
|
253
253
|
*/
|
|
254
|
-
|
|
255
|
-
|
|
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;
|
|
256
270
|
try {
|
|
257
271
|
const acceptance = await data_provider_1.dataService.getTaskAcceptance(taskIdentity.id);
|
|
258
|
-
|
|
272
|
+
settled = acceptance.expectations.filter((e) => e.assessmentId);
|
|
259
273
|
}
|
|
260
274
|
catch {
|
|
261
275
|
// An unreadable acceptance is not a reason to refuse the edit. Warn
|
|
262
276
|
// without a number rather than inventing one or blocking the write.
|
|
263
|
-
|
|
277
|
+
unreadable = true;
|
|
264
278
|
}
|
|
265
|
-
if (
|
|
266
|
-
const noun =
|
|
267
|
-
const count =
|
|
268
|
-
|
|
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} ` +
|
|
269
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
|
+
}
|
|
270
299
|
const ok = await this.confirm('Continue? [y/N] ');
|
|
271
300
|
if (!ok) {
|
|
272
|
-
|
|
273
|
-
|
|
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 });
|
|
274
310
|
}
|
|
275
311
|
}
|
|
276
312
|
}
|
|
@@ -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
|
+
}
|