@skrr-ai/cli 0.1.121 → 0.1.123
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/dist/commands/actions/publish.js +4 -0
- package/dist/commands/agent/message/send.js +6 -1
- package/dist/commands/agents/chat.d.ts +7 -0
- package/dist/commands/agents/chat.js +32 -6
- package/dist/commands/followups/act.js +3 -0
- package/dist/commands/followups/checkin.js +3 -0
- package/dist/commands/followups/remind.js +3 -0
- package/dist/commands/followups/show.js +1 -1
- package/dist/commands/followups/watch.js +3 -0
- package/dist/commands/store/gallery-admissions/approve.d.ts +16 -0
- package/dist/commands/store/gallery-admissions/approve.js +36 -0
- package/dist/commands/store/gallery-admissions/list.d.ts +9 -0
- package/dist/commands/store/gallery-admissions/list.js +49 -0
- package/dist/commands/store/gallery-admissions/preview.d.ts +15 -0
- package/dist/commands/store/gallery-admissions/preview.js +48 -0
- package/dist/commands/store/gallery-admissions/refuse.d.ts +15 -0
- package/dist/commands/store/gallery-admissions/refuse.js +35 -0
- package/dist/commands/store/gallery-admissions/show.d.ts +12 -0
- package/dist/commands/store/gallery-admissions/show.js +55 -0
- package/dist/commands/tasks/list.js +8 -0
- package/dist/generated/agent-guides.json +11 -11
- package/dist/lib/agentic-stream.d.ts +46 -0
- package/dist/lib/agentic-stream.js +135 -14
- package/dist/lib/auth-failure.js +12 -0
- package/dist/lib/command-miss.js +1 -0
- package/dist/lib/exec-runtime-binary.d.ts +9 -0
- package/dist/lib/exec-runtime-binary.js +15 -1
- package/dist/lib/followups.d.ts +13 -0
- package/dist/lib/followups.js +8 -0
- package/dist/lib/profile-machine-identity-guard.js +2 -1
- package/dist/lib/runtime-start-verification.js +6 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +58 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +60 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +8 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.js +7 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.js +3 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/macos.js +3 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.d.ts +29 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.js +37 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +12 -6
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.d.ts +3 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.js +41 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/types.d.ts +7 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +109 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +2 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +78 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.d.ts +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.js +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.js +3 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/macos.js +3 -2
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.d.ts +29 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.js +38 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.d.ts +1 -1
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +1 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +31 -6
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.d.ts +3 -0
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.js +40 -3
- package/dist/node_modules/@skrr-ai/auth-core/dist/esm/types.d.ts +7 -1
- package/dist/node_modules/@skrr-ai/auth-core/package.json +10 -0
- package/dist/node_modules/@skrr-ai/data-provider/index.js +7359 -7344
- package/oclif.manifest.json +478 -3
- package/package.json +1 -1
|
@@ -37,6 +37,10 @@ class ActionsPublish extends base_command_1.BaseCommand {
|
|
|
37
37
|
this.log(JSON.stringify(response, null, 2));
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
+
if (response.requiresReview) {
|
|
41
|
+
this.log('Action submitted for review. It will be listed after approval.');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
40
44
|
this.log(flags.unpublish ? 'Unpublished action listing:' : 'Published action listing:');
|
|
41
45
|
(0, action_listings_1.renderActionListing)(response.listing, (line) => this.log(line));
|
|
42
46
|
}
|
|
@@ -161,7 +161,7 @@ class AgentMessageSend extends base_command_1.BaseCommand {
|
|
|
161
161
|
allowNo: true,
|
|
162
162
|
}),
|
|
163
163
|
task: core_1.Flags.string({
|
|
164
|
-
description: 'Manual
|
|
164
|
+
description: 'Manual task context (ID, reference, or title); managed sessions derive it server-side',
|
|
165
165
|
}),
|
|
166
166
|
space: core_1.Flags.string({ description: 'Optional space context for manual tools' }),
|
|
167
167
|
goal: core_1.Flags.string({ description: 'Optional goal context for manual tools' }),
|
|
@@ -234,6 +234,11 @@ class AgentMessageSend extends base_command_1.BaseCommand {
|
|
|
234
234
|
retryable: false,
|
|
235
235
|
});
|
|
236
236
|
}
|
|
237
|
+
// Manual task context accepts the same titles and references as task
|
|
238
|
+
// commands. Managed sessions must leave the claim-derived context alone.
|
|
239
|
+
if (!sessionContext && payload.destination.kind === 'app_owner_dm' && payload.context?.taskId) {
|
|
240
|
+
payload.context.taskId = await this.resolveTaskReference(payload.context.taskId);
|
|
241
|
+
}
|
|
237
242
|
const segmentationAdvisory = messageSegmentationAdvisory({
|
|
238
243
|
destination: payload.destination,
|
|
239
244
|
text: payload.content.text,
|
|
@@ -155,6 +155,12 @@ export declare function noOutputFailureMessage(input: {
|
|
|
155
155
|
text?: string;
|
|
156
156
|
conversationId?: string | null;
|
|
157
157
|
}): string | null;
|
|
158
|
+
/**
|
|
159
|
+
* What a failed run says for itself. The reason is whatever the terminal event
|
|
160
|
+
* carries (see `terminalFailureMessage`); only a failure that carries none gets
|
|
161
|
+
* the generic sentence.
|
|
162
|
+
*/
|
|
163
|
+
export declare function agentRunFailureMessage(result: Pick<AgenticStreamResult, 'lastEvent'>): string;
|
|
158
164
|
export declare function noStreamJsonPayload(input: {
|
|
159
165
|
result: AgenticStreamResult;
|
|
160
166
|
conversationId?: string;
|
|
@@ -222,6 +228,7 @@ export default class AgentsChat extends BaseCommand {
|
|
|
222
228
|
'thread-root': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
223
229
|
'no-stream': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
224
230
|
quick: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
231
|
+
incremental: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
225
232
|
jsonl: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
226
233
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
227
234
|
'repair-wait': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -9,6 +9,7 @@ exports.handoverInterruptMessage = handoverInterruptMessage;
|
|
|
9
9
|
exports.interruptAction = interruptAction;
|
|
10
10
|
exports.inspectTurnCommand = inspectTurnCommand;
|
|
11
11
|
exports.noOutputFailureMessage = noOutputFailureMessage;
|
|
12
|
+
exports.agentRunFailureMessage = agentRunFailureMessage;
|
|
12
13
|
exports.noStreamJsonPayload = noStreamJsonPayload;
|
|
13
14
|
exports.chatStreamHeaderLines = chatStreamHeaderLines;
|
|
14
15
|
exports.daemonPinFields = daemonPinFields;
|
|
@@ -259,6 +260,14 @@ function noOutputFailureMessage(input) {
|
|
|
259
260
|
return (`The turn ended with no output (status: ${input.status}). ` +
|
|
260
261
|
`It may have failed on the runtime. Inspect it with: ${inspectTurnCommand(input.conversationId)}`);
|
|
261
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* What a failed run says for itself. The reason is whatever the terminal event
|
|
265
|
+
* carries (see `terminalFailureMessage`); only a failure that carries none gets
|
|
266
|
+
* the generic sentence.
|
|
267
|
+
*/
|
|
268
|
+
function agentRunFailureMessage(result) {
|
|
269
|
+
return (0, agentic_stream_1.terminalFailureMessage)(result.lastEvent) ?? 'Agent run failed';
|
|
270
|
+
}
|
|
262
271
|
function noStreamJsonPayload(input) {
|
|
263
272
|
const { result, conversationId, agentId, baseURL, threadRootMessageId } = input;
|
|
264
273
|
return {
|
|
@@ -281,9 +290,9 @@ function noStreamJsonPayload(input) {
|
|
|
281
290
|
? {
|
|
282
291
|
failureReason: result.lastEvent?.reason ??
|
|
283
292
|
result.lastEvent?.code ??
|
|
284
|
-
result.lastEvent
|
|
293
|
+
(0, agentic_stream_1.terminalFailureMessage)(result.lastEvent) ??
|
|
285
294
|
'agent_run_failed',
|
|
286
|
-
error: result
|
|
295
|
+
error: agentRunFailureMessage(result),
|
|
287
296
|
terminalEvent: result.lastEvent,
|
|
288
297
|
}
|
|
289
298
|
: {}),
|
|
@@ -370,10 +379,20 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
370
379
|
'agent’s runtime, tools, session, or working directory and cannot perform work — ' +
|
|
371
380
|
'it is for inline text assistance. Use --no-stream for a real turn.',
|
|
372
381
|
}),
|
|
382
|
+
incremental: core_1.Flags.boolean({
|
|
383
|
+
description: 'With --jsonl, make `text.delta` a real delta: it carries only `delta`, the characters ' +
|
|
384
|
+
'it adds, instead of the whole answer so far, and leaves out the envelopes that ' +
|
|
385
|
+
'`session.output` already carries. A rewrite that is not an append arrives as ' +
|
|
386
|
+
'`replace`, the new full text. `run.result` still holds the whole answer. Without it ' +
|
|
387
|
+
'a long answer written as JSON lines grows with the square of its length.',
|
|
388
|
+
dependsOn: ['jsonl'],
|
|
389
|
+
}),
|
|
373
390
|
jsonl: core_1.Flags.boolean({
|
|
374
391
|
description: 'Emit one JSON event per line while streaming. Every line is a complete JSON value. ' +
|
|
375
392
|
'Assistant text arrives as `text.delta` whose `text` is the CUMULATIVE answer so far, ' +
|
|
376
|
-
'not a delta — take the last one, or `run.result` at the end.
|
|
393
|
+
'not a delta — take the last one, or `run.result` at the end. Each `text.delta` also ' +
|
|
394
|
+
'carries `delta`, the characters it adds, when it only appends to the one before; ' +
|
|
395
|
+
'with --incremental it carries nothing else of the text (see that flag). The same text is ' +
|
|
377
396
|
'mirrored inside `session.output` envelopes for consumers that want the raw stream, ' +
|
|
378
397
|
'so folding both doubles the answer: pick ONE lane. A widget the agent wrote ' +
|
|
379
398
|
'(a block of CSS, HTML and JavaScript the apps draw) is its text description in ' +
|
|
@@ -392,7 +411,11 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
392
411
|
'and local-harness runs alike. A `session.notice` with `notice: ' +
|
|
393
412
|
'"harness-session-reset"` means the local harness could not resume its previous ' +
|
|
394
413
|
'session and started a new one, which does not see earlier turns of the ' +
|
|
395
|
-
'conversation; `message` says why.
|
|
414
|
+
'conversation; `message` says why. `notice: "model-request-retrying"` means the ' +
|
|
415
|
+
'model rejected or could not answer a request and the harness is retrying it: ' +
|
|
416
|
+
'`message` names the cause (for example the model rejecting the credentials on ' +
|
|
417
|
+
'this machine, HTTP 403) and the attempt, a few times per retry episode, so a ' +
|
|
418
|
+
'run that looks quiet is not. A `permission.resolved` says ' +
|
|
396
419
|
'how a local harness permission request was decided: `decidedBy` in words, and ' +
|
|
397
420
|
'`basis` — `person` (with `surface`), `mode` (with `mode`), `policy` or ' +
|
|
398
421
|
'`session-grant` — beside the wire `by`. When a platform update restarts the server ' +
|
|
@@ -404,7 +427,9 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
404
427
|
'the machine finished; `run.failed` with `handover.outcome: "machine_failed"` and the ' +
|
|
405
428
|
'machine\'s reason when it did not; or `run.failed` with `handover.outcome: "expired"` ' +
|
|
406
429
|
'and the original failure when --repair-wait ran out (exit 1 for both). Ctrl-C during ' +
|
|
407
|
-
'the wait emits `run.detached` with `handedOver: true` and exits 130.'
|
|
430
|
+
'the wait emits `run.detached` with `handedOver: true` and exits 130. Whenever a run ' +
|
|
431
|
+
'fails, `run.failed` carries `message`, the reason in words as the platform gave it (the ' +
|
|
432
|
+
'same sentence a terminal prints after `Error:`), beside the short `reason`.',
|
|
408
433
|
}),
|
|
409
434
|
json: core_1.Flags.boolean({
|
|
410
435
|
description: 'Emit the final one-shot response as JSON (use with --no-stream)',
|
|
@@ -788,6 +813,7 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
788
813
|
sessionId: started.sessionId,
|
|
789
814
|
conversationId,
|
|
790
815
|
jsonl: flags.jsonl,
|
|
816
|
+
incrementalText: flags.incremental,
|
|
791
817
|
quiet,
|
|
792
818
|
approveTools: flags['approve-tools'],
|
|
793
819
|
reconcileTerminal,
|
|
@@ -966,7 +992,7 @@ class AgentsChat extends base_command_1.BaseCommand {
|
|
|
966
992
|
process.exitCode = 1;
|
|
967
993
|
}
|
|
968
994
|
else if (result.status === 'failed') {
|
|
969
|
-
this.error(
|
|
995
|
+
this.error(agentRunFailureMessage(result), { exit: 1 });
|
|
970
996
|
}
|
|
971
997
|
else if (quiet) {
|
|
972
998
|
// Non-streaming human output: the answer the turn produced.
|
|
@@ -100,6 +100,9 @@ class FollowupsAct extends base_command_1.BaseCommand {
|
|
|
100
100
|
this.log(JSON.stringify(response, null, 2));
|
|
101
101
|
return;
|
|
102
102
|
}
|
|
103
|
+
const producerNotice = (0, followups_1.producerDowngradeNotice)(response);
|
|
104
|
+
if (producerNotice)
|
|
105
|
+
this.log(producerNotice);
|
|
103
106
|
const row = response.followup;
|
|
104
107
|
if (response.reused) {
|
|
105
108
|
this.log(`Already armed: ${row?.id} — the same act exists and was not duplicated.`);
|
|
@@ -126,6 +126,9 @@ class FollowupsCheckin extends base_command_1.BaseCommand {
|
|
|
126
126
|
this.log(JSON.stringify(response, null, 2));
|
|
127
127
|
return;
|
|
128
128
|
}
|
|
129
|
+
const producerNotice = (0, followups_1.producerDowngradeNotice)(response);
|
|
130
|
+
if (producerNotice)
|
|
131
|
+
this.log(producerNotice);
|
|
129
132
|
const row = response.followup;
|
|
130
133
|
if (response.reused) {
|
|
131
134
|
this.log(reusedMessage(row, subject, flags.why));
|
|
@@ -102,6 +102,9 @@ class FollowupsRemind extends base_command_1.BaseCommand {
|
|
|
102
102
|
this.log(JSON.stringify(response, null, 2));
|
|
103
103
|
return;
|
|
104
104
|
}
|
|
105
|
+
const producerNotice = (0, followups_1.producerDowngradeNotice)(response);
|
|
106
|
+
if (producerNotice)
|
|
107
|
+
this.log(producerNotice);
|
|
105
108
|
const row = response.followup;
|
|
106
109
|
if (response.reused && response.rescheduled) {
|
|
107
110
|
this.log(`Moved: ${row?.id} now fires at ${row?.nextRunAt ?? at} — the same reminder already existed, so it was rescheduled rather than duplicated.`);
|
|
@@ -42,7 +42,7 @@ class FollowupsShow extends base_command_1.BaseCommand {
|
|
|
42
42
|
['says', row.content],
|
|
43
43
|
['why', row.why],
|
|
44
44
|
['intent', row.intentKey],
|
|
45
|
-
['producer', row.producer],
|
|
45
|
+
['producer', row.producerLabel ? `${row.producer} (${row.producerLabel})` : row.producer],
|
|
46
46
|
['gate', row.gate ? (GATE_LABEL[row.gate] ?? row.gate) : undefined],
|
|
47
47
|
['terminal', row.terminal ? `${row.terminal} (${row.terminalReason ?? '—'})` : undefined],
|
|
48
48
|
[
|
|
@@ -237,6 +237,9 @@ class FollowupsWatch extends base_command_1.BaseCommand {
|
|
|
237
237
|
this.log(JSON.stringify(response, null, 2));
|
|
238
238
|
return;
|
|
239
239
|
}
|
|
240
|
+
const producerNotice = (0, followups_1.producerDowngradeNotice)(response);
|
|
241
|
+
if (producerNotice)
|
|
242
|
+
this.log(producerNotice);
|
|
240
243
|
const row = response.followup;
|
|
241
244
|
if (response.reused) {
|
|
242
245
|
this.log(`Already armed: ${row?.id} — an identical watch exists and was not duplicated.`);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class StoreGalleryAdmissionsApprove extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
kind: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
revision: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
digest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'images-reviewed': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
note: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
5
|
+
const base_command_1 = require("../../../base-command");
|
|
6
|
+
class StoreGalleryAdmissionsApprove extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Approve the exact frozen gallery revision inspected by a curator';
|
|
8
|
+
static args = { id: core_1.Args.string({ description: 'Gallery review request ID', required: true, ignoreStdin: true }) };
|
|
9
|
+
static flags = {
|
|
10
|
+
kind: core_1.Flags.string({ options: ['action', 'service'], required: true }),
|
|
11
|
+
revision: core_1.Flags.integer({ required: true, min: 0, description: 'Revision from the review details' }),
|
|
12
|
+
digest: core_1.Flags.string({ required: true, description: 'Digest from the review details' }),
|
|
13
|
+
'images-reviewed': core_1.Flags.boolean({ description: 'Confirm you inspected every image in this frozen revision' }),
|
|
14
|
+
note: core_1.Flags.string({ description: 'Decision note' }),
|
|
15
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
this.requireAuth();
|
|
19
|
+
const { args, flags } = await this.parse(StoreGalleryAdmissionsApprove);
|
|
20
|
+
try {
|
|
21
|
+
if (!flags['images-reviewed'])
|
|
22
|
+
throw new Error('Inspect every image, then pass --images-reviewed to confirm.');
|
|
23
|
+
const result = await data_provider_1.dataService.approveStoreGalleryAdmission(flags.kind, args.id, {
|
|
24
|
+
revision: flags.revision, digest: flags.digest, imagesReviewed: true, ...(flags.note ? { note: flags.note } : {}),
|
|
25
|
+
});
|
|
26
|
+
if (flags.json)
|
|
27
|
+
this.log(JSON.stringify(result, null, 2));
|
|
28
|
+
else
|
|
29
|
+
this.log(`Approved gallery revision ${flags.revision}.`);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
this.handleApiError(err);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.default = StoreGalleryAdmissionsApprove;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class StoreGalleryAdmissionsList extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
state: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
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 list_output_1 = require("../../../lib/list-output");
|
|
7
|
+
class StoreGalleryAdmissionsList extends base_command_1.BaseCommand {
|
|
8
|
+
static description = 'List frozen Store gallery revisions awaiting curator review';
|
|
9
|
+
static flags = {
|
|
10
|
+
state: core_1.Flags.string({ options: ['pending_review', 'refused'], default: 'pending_review', description: 'Review state to list' }),
|
|
11
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
12
|
+
};
|
|
13
|
+
async run() {
|
|
14
|
+
this.requireAuth();
|
|
15
|
+
const { flags } = await this.parse(StoreGalleryAdmissionsList);
|
|
16
|
+
try {
|
|
17
|
+
const reviews = [];
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
let cursor;
|
|
20
|
+
do {
|
|
21
|
+
const page = await data_provider_1.dataService.getStoreGalleryAdmissions({
|
|
22
|
+
state: flags.state,
|
|
23
|
+
...(cursor ? { cursor } : {}),
|
|
24
|
+
});
|
|
25
|
+
reviews.push(...page.reviews);
|
|
26
|
+
cursor = page.nextCursor || undefined;
|
|
27
|
+
if (cursor && seen.has(cursor))
|
|
28
|
+
throw new Error('Gallery admission queue returned a repeated cursor');
|
|
29
|
+
if (cursor)
|
|
30
|
+
seen.add(cursor);
|
|
31
|
+
} while (cursor);
|
|
32
|
+
if (flags.json) {
|
|
33
|
+
this.printJsonResult((0, list_output_1.listResult)({ data: reviews, reviews, nextCursor: null }));
|
|
34
|
+
}
|
|
35
|
+
else if (!reviews.length) {
|
|
36
|
+
this.log(flags.state === 'refused' ? 'No refused gallery reviews.' : 'Nothing waiting for gallery review.');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
for (const review of reviews) {
|
|
40
|
+
this.log(`${review.entityType}\t${review.id}\t${review.entityId}\trevision ${review.revision}\t${review.digest}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
this.handleApiError(err);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.default = StoreGalleryAdmissionsList;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
/** The server grants only curators access; do not print or persist a bearer URL. */
|
|
3
|
+
export default class StoreGalleryAdmissionsPreview extends BaseCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
imageId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
kind: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_crypto_1 = require("node:crypto");
|
|
4
|
+
const promises_1 = require("node:fs/promises");
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const data_provider_1 = require("@skrr-ai/data-provider");
|
|
7
|
+
const base_command_1 = require("../../../base-command");
|
|
8
|
+
/** The server grants only curators access; do not print or persist a bearer URL. */
|
|
9
|
+
class StoreGalleryAdmissionsPreview extends base_command_1.BaseCommand {
|
|
10
|
+
static description = 'Download one frozen review image for inspection';
|
|
11
|
+
static args = {
|
|
12
|
+
id: core_1.Args.string({ description: 'Gallery review request ID', required: true, ignoreStdin: true }),
|
|
13
|
+
imageId: core_1.Args.string({ description: 'Image ID from show', required: true, ignoreStdin: true }),
|
|
14
|
+
};
|
|
15
|
+
static flags = {
|
|
16
|
+
kind: core_1.Flags.string({ options: ['action', 'service'], required: true }),
|
|
17
|
+
output: core_1.Flags.string({ description: 'New local file to write (will not overwrite)', required: true }),
|
|
18
|
+
json: core_1.Flags.boolean({ description: 'Output a file receipt as JSON' }),
|
|
19
|
+
};
|
|
20
|
+
async run() {
|
|
21
|
+
this.requireAuth();
|
|
22
|
+
const { args, flags } = await this.parse(StoreGalleryAdmissionsPreview);
|
|
23
|
+
try {
|
|
24
|
+
if (flags.output === '-')
|
|
25
|
+
throw new Error('Choose a local file path for --output.');
|
|
26
|
+
const kind = flags.kind;
|
|
27
|
+
const { review } = await data_provider_1.dataService.getStoreGalleryAdmission(kind, args.id);
|
|
28
|
+
const image = review.images?.find((item) => item.id === args.imageId);
|
|
29
|
+
if (!image || !/^[a-f0-9]{64}$/i.test(image.sha256)) {
|
|
30
|
+
throw new Error('Image or verified SHA-256 is missing from this review.');
|
|
31
|
+
}
|
|
32
|
+
const bytes = Buffer.from(await data_provider_1.dataService.downloadStoreGalleryAdmissionImage(kind, args.id, args.imageId));
|
|
33
|
+
const digest = (0, node_crypto_1.createHash)('sha256').update(bytes).digest('hex');
|
|
34
|
+
if (digest !== image.sha256.toLowerCase())
|
|
35
|
+
throw new Error('Image bytes do not match the frozen review digest.');
|
|
36
|
+
await (0, promises_1.writeFile)(flags.output, bytes, { flag: 'wx', mode: 0o600 });
|
|
37
|
+
const receipt = { requestId: args.id, kind, revision: review.revision, digest: review.digest, imageId: args.imageId, sha256: digest, path: flags.output, bytes: bytes.length };
|
|
38
|
+
if (flags.json)
|
|
39
|
+
this.log(JSON.stringify(receipt));
|
|
40
|
+
else
|
|
41
|
+
this.log(`Wrote ${bytes.length} bytes to ${flags.output} (sha256:${digest}). Review revision ${review.revision}, digest ${review.digest}.`);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
this.handleApiError(err);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.default = StoreGalleryAdmissionsPreview;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class StoreGalleryAdmissionsRefuse extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
kind: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
revision: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
digest: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
note: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
class StoreGalleryAdmissionsRefuse extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Refuse a frozen gallery revision with a publisher-facing reason';
|
|
8
|
+
static args = { id: core_1.Args.string({ description: 'Gallery review request ID', required: true, ignoreStdin: true }) };
|
|
9
|
+
static flags = {
|
|
10
|
+
kind: core_1.Flags.string({ options: ['action', 'service'], required: true }),
|
|
11
|
+
revision: core_1.Flags.integer({ required: true, min: 0, description: 'Revision from the review details' }),
|
|
12
|
+
digest: core_1.Flags.string({ required: true, description: 'Digest from the review details' }),
|
|
13
|
+
note: core_1.Flags.string({ required: true, description: 'Reason the publisher can act on (at least 8 characters)' }),
|
|
14
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
this.requireAuth();
|
|
18
|
+
const { args, flags } = await this.parse(StoreGalleryAdmissionsRefuse);
|
|
19
|
+
try {
|
|
20
|
+
if (flags.note.trim().length < 8)
|
|
21
|
+
throw new Error('A refusal needs a note of at least 8 characters.');
|
|
22
|
+
const result = await data_provider_1.dataService.refuseStoreGalleryAdmission(flags.kind, args.id, {
|
|
23
|
+
revision: flags.revision, digest: flags.digest, note: flags.note.trim(),
|
|
24
|
+
});
|
|
25
|
+
if (flags.json)
|
|
26
|
+
this.log(JSON.stringify(result, null, 2));
|
|
27
|
+
else
|
|
28
|
+
this.log(`Refused gallery revision ${flags.revision}.`);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
this.handleApiError(err);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.default = StoreGalleryAdmissionsRefuse;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base-command';
|
|
2
|
+
export default class StoreGalleryAdmissionsShow extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
kind: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
class StoreGalleryAdmissionsShow extends base_command_1.BaseCommand {
|
|
7
|
+
static description = 'Inspect a frozen gallery review and its image digests';
|
|
8
|
+
static args = { id: core_1.Args.string({ description: 'Gallery review request ID', required: true, ignoreStdin: true }) };
|
|
9
|
+
static flags = {
|
|
10
|
+
kind: core_1.Flags.string({ options: ['action', 'service'], required: true }),
|
|
11
|
+
json: core_1.Flags.boolean({ description: 'Output as JSON' }),
|
|
12
|
+
};
|
|
13
|
+
async run() {
|
|
14
|
+
this.requireAuth();
|
|
15
|
+
const { args, flags } = await this.parse(StoreGalleryAdmissionsShow);
|
|
16
|
+
try {
|
|
17
|
+
const result = await data_provider_1.dataService.getStoreGalleryAdmission(flags.kind, args.id);
|
|
18
|
+
if (flags.json) {
|
|
19
|
+
this.log(JSON.stringify(result, null, 2));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const r = result.review;
|
|
23
|
+
this.log(`${r.entityType}\t${r.id}\t${r.entityId}\t${r.status}`);
|
|
24
|
+
this.log(`Revision: ${r.revision}\nDigest: ${r.digest}`);
|
|
25
|
+
// Service reviews include frozen listing context. Show the context that
|
|
26
|
+
// belongs to this submission, not the mutable current listing, so the
|
|
27
|
+
// reviewer can judge the images against what was actually submitted.
|
|
28
|
+
if (r.listing) {
|
|
29
|
+
this.log(`Title: ${r.listing.title}`);
|
|
30
|
+
if (r.listing.description)
|
|
31
|
+
this.log(`Description: ${r.listing.description}`);
|
|
32
|
+
this.log(`Price: ${r.listing.price}`);
|
|
33
|
+
}
|
|
34
|
+
if (r.artifactVersionId)
|
|
35
|
+
this.log(`Artifact version: ${r.artifactVersionId}`);
|
|
36
|
+
if (r.offerVersionId)
|
|
37
|
+
this.log(`Offer version: ${r.offerVersionId}`);
|
|
38
|
+
if (r.note)
|
|
39
|
+
this.log(`Decision note: ${r.note}`);
|
|
40
|
+
if (!r.images?.length)
|
|
41
|
+
this.log(r.status === 'pending' || r.status === 'pending_review'
|
|
42
|
+
? 'No images in this revision. Approval removes the current gallery.'
|
|
43
|
+
: 'No images in this revision.');
|
|
44
|
+
for (const image of r.images || []) {
|
|
45
|
+
this.log(`Image ${image.id}\tsha256:${image.sha256}${image.mimeType ? `\t${image.mimeType}` : ''}${image.alt ? `\t${image.alt}` : ''}`);
|
|
46
|
+
}
|
|
47
|
+
if (r.images?.length)
|
|
48
|
+
this.log('Use store gallery-admissions preview with an image ID and --output to inspect its bytes.');
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
this.handleApiError(err);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.default = StoreGalleryAdmissionsShow;
|
|
@@ -752,10 +752,18 @@ class TasksList extends base_command_1.BaseCommand {
|
|
|
752
752
|
}
|
|
753
753
|
const r = response;
|
|
754
754
|
const items = r?.data ?? [];
|
|
755
|
+
if (flags.q && (r?.degraded || r?.incomplete || r?.truncated || r?.search?.candidates_may_be_truncated || r?.search?.comment_search_incomplete)) {
|
|
756
|
+
this.warn('Search may be incomplete. Inspect --json diagnostics.');
|
|
757
|
+
}
|
|
758
|
+
if (flags.q && r?.search?.semantics === 'case_insensitive_substring') {
|
|
759
|
+
this.warn('Search is using literal database matching; typo tolerance may be unavailable.');
|
|
760
|
+
}
|
|
755
761
|
if (items.length === 0) {
|
|
756
762
|
this.log(emptyTasksMessage(flags, this.config.bin));
|
|
757
763
|
for (const line of (0, list_output_1.warningLines)(prefixWarnings))
|
|
758
764
|
this.log(line);
|
|
765
|
+
if (r?.next_cursor)
|
|
766
|
+
this.log(`Next page: --cursor ${r.next_cursor}`);
|
|
759
767
|
return;
|
|
760
768
|
}
|
|
761
769
|
const rows = items.map((t) => {
|