@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.
Files changed (69) hide show
  1. package/dist/commands/actions/publish.js +4 -0
  2. package/dist/commands/agent/message/send.js +6 -1
  3. package/dist/commands/agents/chat.d.ts +7 -0
  4. package/dist/commands/agents/chat.js +32 -6
  5. package/dist/commands/followups/act.js +3 -0
  6. package/dist/commands/followups/checkin.js +3 -0
  7. package/dist/commands/followups/remind.js +3 -0
  8. package/dist/commands/followups/show.js +1 -1
  9. package/dist/commands/followups/watch.js +3 -0
  10. package/dist/commands/store/gallery-admissions/approve.d.ts +16 -0
  11. package/dist/commands/store/gallery-admissions/approve.js +36 -0
  12. package/dist/commands/store/gallery-admissions/list.d.ts +9 -0
  13. package/dist/commands/store/gallery-admissions/list.js +49 -0
  14. package/dist/commands/store/gallery-admissions/preview.d.ts +15 -0
  15. package/dist/commands/store/gallery-admissions/preview.js +48 -0
  16. package/dist/commands/store/gallery-admissions/refuse.d.ts +15 -0
  17. package/dist/commands/store/gallery-admissions/refuse.js +35 -0
  18. package/dist/commands/store/gallery-admissions/show.d.ts +12 -0
  19. package/dist/commands/store/gallery-admissions/show.js +55 -0
  20. package/dist/commands/tasks/list.js +8 -0
  21. package/dist/generated/agent-guides.json +11 -11
  22. package/dist/lib/agentic-stream.d.ts +46 -0
  23. package/dist/lib/agentic-stream.js +135 -14
  24. package/dist/lib/auth-failure.js +12 -0
  25. package/dist/lib/command-miss.js +1 -0
  26. package/dist/lib/exec-runtime-binary.d.ts +9 -0
  27. package/dist/lib/exec-runtime-binary.js +15 -1
  28. package/dist/lib/followups.d.ts +13 -0
  29. package/dist/lib/followups.js +8 -0
  30. package/dist/lib/profile-machine-identity-guard.js +2 -1
  31. package/dist/lib/runtime-start-verification.js +6 -1
  32. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +58 -1
  33. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +2 -0
  34. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +60 -0
  35. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -2
  36. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +8 -0
  37. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.d.ts +1 -0
  38. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/index.js +7 -0
  39. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/linux.js +3 -2
  40. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/macos.js +3 -2
  41. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.d.ts +29 -0
  42. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/masterKekService.js +37 -0
  43. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.d.ts +1 -1
  44. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/messages.js +1 -0
  45. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/refresh.js +12 -6
  46. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.d.ts +3 -0
  47. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/telemetryRedaction.js +41 -3
  48. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/types.d.ts +7 -1
  49. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +109 -3
  50. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +2 -0
  51. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +78 -0
  52. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -2
  53. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -2
  54. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.d.ts +1 -0
  55. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/index.js +1 -0
  56. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/linux.js +3 -2
  57. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/macos.js +3 -2
  58. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.d.ts +29 -0
  59. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/masterKekService.js +38 -0
  60. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.d.ts +1 -1
  61. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/messages.js +1 -0
  62. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/refresh.js +31 -6
  63. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.d.ts +3 -0
  64. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/telemetryRedaction.js +40 -3
  65. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/types.d.ts +7 -1
  66. package/dist/node_modules/@skrr-ai/auth-core/package.json +10 -0
  67. package/dist/node_modules/@skrr-ai/data-provider/index.js +7359 -7344
  68. package/oclif.manifest.json +478 -3
  69. 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-tool task context; managed sessions derive this server-side',
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?.message ??
293
+ (0, agentic_stream_1.terminalFailureMessage)(result.lastEvent) ??
285
294
  'agent_run_failed',
286
- error: result.lastEvent?.message ?? 'Agent run failed',
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. The same text is ' +
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. A `permission.resolved` says ' +
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(String(result.lastEvent?.message ?? 'Agent run failed'), { exit: 1 });
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) => {