@skrr-ai/cli 0.1.120 → 0.1.122

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 (80) hide show
  1. package/dist/base-command.js +11 -2
  2. package/dist/commands/actions/publish.js +4 -0
  3. package/dist/commands/agent/message/context.d.ts +1 -0
  4. package/dist/commands/agent/message/context.js +3 -2
  5. package/dist/commands/agent/message/send.js +6 -1
  6. package/dist/commands/search/agents.js +5 -1
  7. package/dist/commands/search/all.js +74 -22
  8. package/dist/commands/search/skills.d.ts +1 -0
  9. package/dist/commands/search/skills.js +12 -1
  10. package/dist/commands/search/spaces.d.ts +8 -1
  11. package/dist/commands/search/spaces.js +50 -12
  12. package/dist/commands/search/tasks.d.ts +13 -2
  13. package/dist/commands/search/tasks.js +78 -14
  14. package/dist/commands/search/teams.js +5 -1
  15. package/dist/commands/search/workspace.d.ts +19 -0
  16. package/dist/commands/search/workspace.js +126 -0
  17. package/dist/commands/skills/browse.d.ts +1 -0
  18. package/dist/commands/skills/browse.js +8 -1
  19. package/dist/commands/skills/search.d.ts +1 -0
  20. package/dist/commands/skills/search.js +12 -1
  21. package/dist/commands/spaces/list.d.ts +1 -0
  22. package/dist/commands/spaces/list.js +12 -3
  23. package/dist/commands/spaces/search.d.ts +1 -0
  24. package/dist/commands/spaces/search.js +9 -0
  25. package/dist/commands/store/gallery-admissions/approve.d.ts +16 -0
  26. package/dist/commands/store/gallery-admissions/approve.js +36 -0
  27. package/dist/commands/store/gallery-admissions/list.d.ts +9 -0
  28. package/dist/commands/store/gallery-admissions/list.js +49 -0
  29. package/dist/commands/store/gallery-admissions/preview.d.ts +15 -0
  30. package/dist/commands/store/gallery-admissions/preview.js +48 -0
  31. package/dist/commands/store/gallery-admissions/refuse.d.ts +15 -0
  32. package/dist/commands/store/gallery-admissions/refuse.js +35 -0
  33. package/dist/commands/store/gallery-admissions/show.d.ts +12 -0
  34. package/dist/commands/store/gallery-admissions/show.js +55 -0
  35. package/dist/commands/tasks/list.js +8 -0
  36. package/dist/commands/tasks/search.d.ts +1 -0
  37. package/dist/commands/tasks/search.js +9 -0
  38. package/dist/generated/agent-guides.json +11 -11
  39. package/dist/lib/api-error-reason.d.ts +2 -0
  40. package/dist/lib/api-error-reason.js +14 -0
  41. package/dist/lib/api-fetch.js +3 -0
  42. package/dist/lib/command-miss.js +1 -0
  43. package/dist/lib/search-display.d.ts +7 -0
  44. package/dist/lib/search-display.js +31 -0
  45. package/dist/lib/skill-store-pagination.d.ts +8 -0
  46. package/dist/lib/skill-store-pagination.js +35 -0
  47. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.d.ts +10 -0
  48. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/credentialEnvelopeBridge.js +147 -0
  49. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonConsentProof.d.ts +20 -0
  50. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonConsentProof.js +72 -0
  51. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/desktopDaemonProof.d.ts +21 -0
  52. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/desktopDaemonProof.js +96 -0
  53. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.d.ts +2 -3
  54. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/deviceIdentityBridge.js +102 -20
  55. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/independentMachineReservation.d.ts +27 -0
  56. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/independentMachineReservation.js +161 -0
  57. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/independentMachineScopes.d.ts +26 -0
  58. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/independentMachineScopes.js +41 -0
  59. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.d.ts +2 -1
  60. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/index.js +15 -0
  61. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/kek/macos.js +20 -4
  62. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.d.ts +10 -0
  63. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/credentialEnvelopeBridge.js +172 -1
  64. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonConsentProof.d.ts +20 -0
  65. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonConsentProof.js +43 -0
  66. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/desktopDaemonProof.d.ts +21 -0
  67. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/desktopDaemonProof.js +62 -0
  68. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.d.ts +2 -3
  69. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/deviceIdentityBridge.js +133 -25
  70. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/independentMachineReservation.d.ts +27 -0
  71. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/independentMachineReservation.js +132 -0
  72. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/independentMachineScopes.d.ts +26 -0
  73. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/independentMachineScopes.js +15 -0
  74. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.d.ts +2 -1
  75. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/index.js +2 -1
  76. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/kek/macos.js +28 -15
  77. package/dist/node_modules/@skrr-ai/auth-core/package.json +31 -1
  78. package/dist/node_modules/@skrr-ai/data-provider/index.js +7728 -7666
  79. package/oclif.manifest.json +1180 -101
  80. package/package.json +1 -1
@@ -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) => {
@@ -0,0 +1 @@
1
+ export { default } from '../search/tasks';
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = void 0;
7
+ // Both spellings share one implementation and result contract.
8
+ var tasks_1 = require("../search/tasks");
9
+ Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(tasks_1).default; } });
@@ -691,7 +691,7 @@
691
691
  "id": "delivery-statuses",
692
692
  "title": "Delivery statuses",
693
693
  "readWhen": "a send answered and you need to know what its status means",
694
- "tokens": 723,
694
+ "tokens": 726,
695
695
  "aliases": [],
696
696
  "explains": [
697
697
  "agent_not_authorized_for_session",
@@ -709,7 +709,7 @@
709
709
  ]
710
710
  }
711
711
  ],
712
- "hash": "dbdf1cf8629e980d7946574d0fb3b06dedc0a96a77c89d016f653b01eb6a8d9a",
712
+ "hash": "da48eab97c0c8b0102894a1256266cd67df3611313caec27ffff1ef2c2ec87ae",
713
713
  "tokens": 544
714
714
  },
715
715
  "routedIndex": {
@@ -2027,7 +2027,7 @@
2027
2027
  "routed": false,
2028
2028
  "aliases": [],
2029
2029
  "body": "## Concept model\n\nAn **Agent Update** is a deliberate owner-facing message. It is conversation, not\nrecord: what durably changed belongs to the work's own records, and the message\npoints at it.\n\n## Agent Updates\n\nProactively message the owner whenever it would improve their ability to steer the work, understand\na meaningful change, or stay confidently involved. Adapt to the task, uncertainty and stakes, the\nuser's engagement, what you have already communicated, and any per-agent style direction. Do not\nfollow a fixed schedule or manufacture status chatter.\n\n- Choose the semantic kind: `milestone` for a meaningful completed stage, `status` for a\n useful non-blocking checkpoint, `decision` for a concrete choice, `blocker` when user action is needed to\n continue, and one `result` for the terminal outcome (including failure).\n- Declare the attention intent with `--attention ambient|notify|interrupt`: `ambient` stays in\n the durable timeline by default, `notify` is worth seeing soon, and `interrupt` is reserved for\n work that is blocked or genuinely time-sensitive. The system and the user choose delivery channels and native\n presentation; attention never directly selects an Android channel, iOS interruption level, sound, or critical\n alert, and never bypasses notification preferences, quiet hours, Focus, or rate limits.\n- Say what is newly true and what it changes for the work. Include the next step, decision, or\n uncertainty when it would help the user; do not force every message into a fixed template.\n- Write like a capable teammate giving a busy owner a real, in-the-moment briefing — not like a\n system log, a customer-service script, or a task template. Open on the thing itself, never on a\n subject line (\"Status on the refactor:\", \"Quick update:\"). In the user's language, lead with the\n fresh fact, decision, or risk; then make clear why it matters and what happens next. Where the\n evidence is available, ground the update in one or two useful specifics: the affected thing, the\n evidence, the timing, or the trade-off.\n Use plain, varied sentences and only the confidence the evidence earns. Keep them short: where a\n dash would staple two clauses into one, use two sentences instead. Be warm and direct, but\n never manufacture familiarity, emotion, certainty, or colour that is not true. Avoid AI-shaped\n filler such as \"I am pleased to report\", \"completed / in progress / next step\" recaps,\n \"I will continue to monitor\", \"feel free to let me know\", ceremonial thanks, and vague claims\n such as \"the optimization is complete\". Say the thing instead: \"The migration is in; the\n slowest query fell from 2.8s to 420ms. I am running the full regression now and will flag any\n breakage before merge.\" Treat that as a standard of specificity, not a rigid script. Do not make\n a message longer merely to sound human.\n- Task context and card presentation are separate. A managed session's task context is derived\n server-side, but a message shows no Task Card unless you explicitly choose `--attach-task-card`\n (or `presentation.taskCard: true`). Use a card when it materially helps the user open or follow the\n live task; omit it for ordinary conversational updates.\n- In a hand-started session, use `skrr agent message context --agent <id>` when recent\n updates, read state, or a user's reply would help your judgment. It supplies observations, not a\n schedule or a command to send.\n- In a skrr-managed session, do not pass task, run, or session identity: skrr derives it.\n In a hand-started session, add `--task <task-id>` only when you know the correct task; it is\n declared context.\n- Prefer one message for one thought. For a conversational owner DM — such as a pitch, invitation,\n question, or progress update — when a draft exceeds roughly 320 characters or contains two independent thoughts,\n normally use a 2–4 message human-scale sequence with `--part \"<next thought>\"` and one explicit semantic\n `--idempotency-key`. Do not fragment a single thought merely to send more messages, and never split text\n mechanically: choose the semantic boundaries yourself. If one part does not reach the user, the remaining parts\n are deliberately not sent — the user would otherwise read your thoughts out of order.\n- An idempotency key names ONE update for this agent permanently, so make it specific to this run\n (for example `<task-id>:verify-complete`). Reuse it only to retry that same update: reused with\n the same text it is dropped as a duplicate, and with different text it is rejected.\n- A non-`delivered` status (`held`, `approval_required`, `duplicate`, `dropped`) is a policy\n outcome, not an error. It is never a reason to bypass this command with a direct DM or Slack\n call — this is the only sanctioned agent-to-user path.\n\n## Authority\n\n| Actor | May do | Only a person may do |\n| --- | --- | --- |\n| Agent | Decide to message; declare kind, attention intent, task context and a task card | Choose the delivery channel or native presentation; release a held or approval-gated intent |\n| Person | Everything an Agent may do | — |\n\n## Live state\n\n- `skrr agent message context --agent <id>` — recent updates, read state and owner engagement, as observations for the decision above.\n\n## Related guides\n\n- `tasks` — the records an update points at, and the durable version of what changed.\n- `agents` — which Agent a session speaks as; its `identity` section owns the agent-context refusals.",
2030
- "hash": "40d317231d49b148679d13df5c33673a8bcdafd8053602f3e050e618315f78c9",
2030
+ "hash": "2ca0bfacfd5ac8edcfe5e36ca344d8698f02874e2786646c4f03bea28ca623d9",
2031
2031
  "tokens": 1359,
2032
2032
  "sections": [
2033
2033
  {
@@ -2073,7 +2073,7 @@
2073
2073
  "id": "delivery-statuses",
2074
2074
  "title": "Delivery statuses",
2075
2075
  "readWhen": "a send answered and you need to know what its status means",
2076
- "tokens": 723,
2076
+ "tokens": 726,
2077
2077
  "aliases": [],
2078
2078
  "explains": [
2079
2079
  "agent_not_authorized_for_session",
@@ -8053,7 +8053,7 @@
8053
8053
  "id": "delivery-statuses",
8054
8054
  "title": "Delivery statuses",
8055
8055
  "readWhen": "a send answered and you need to know what its status means",
8056
- "tokens": 723,
8056
+ "tokens": 726,
8057
8057
  "aliases": [],
8058
8058
  "explains": [
8059
8059
  "agent_not_authorized_for_session",
@@ -8130,7 +8130,7 @@
8130
8130
  "id": "delivery-statuses",
8131
8131
  "title": "Delivery statuses",
8132
8132
  "readWhen": "a send answered and you need to know what its status means",
8133
- "tokens": 723,
8133
+ "tokens": 726,
8134
8134
  "aliases": [],
8135
8135
  "explains": [
8136
8136
  "agent_not_authorized_for_session",
@@ -8206,7 +8206,7 @@
8206
8206
  "id": "delivery-statuses",
8207
8207
  "title": "Delivery statuses",
8208
8208
  "readWhen": "a send answered and you need to know what its status means",
8209
- "tokens": 723,
8209
+ "tokens": 726,
8210
8210
  "aliases": [],
8211
8211
  "explains": [
8212
8212
  "agent_not_authorized_for_session",
@@ -8244,9 +8244,9 @@
8244
8244
  "delivery_mode_ask_first",
8245
8245
  "delivery_policy_unavailable"
8246
8246
  ],
8247
- "body": "Read this when a send answered and you need to know what its status means.\n\n| Status | Meaning |\n| --- | --- |\n| `submitted` | recorded, not yet dispatched — still owned by the platform |\n| `held` | policy withheld it for now; it may still be delivered — `reason` says why |\n| `re_evaluation` | being re-checked against policy — still owned by the platform |\n| `approval_required` | waiting on the person’s approval; `initiativeId` names what they act on |\n| `authorized` | cleared for dispatch — still owned by the platform |\n| `dispatching` | being delivered right now |\n| `delivered` | reached the user |\n| `transport_failed` | delivery errored; `retryable` and `retryAfter` say whether to try again |\n| `dropped` | will not be delivered — read `reason` and change the request before resending |\n| `expired` | outlived its window before delivery |\n| `cancelled` | withdrawn before delivery |\n| `duplicate` | the idempotency key already carried this identical update — the earlier send stands |\n| `accepted` | an earlier send already delivered this update |\n| `failed` | the transport could not deliver; `retryable` says whether a retry can help |\n| `queued_offline` | held by the local daemon until it can reach the platform — still in flight |\n| `refused` | a guard declined the send; `reason` names it |\n| `unknown` | the transport could not certify the outcome |\n\nA `held`, `approval_required` or `dropped` result carries `reason`; an approval\ncarries `initiativeId` for the person to act on; a transport failure carries\n`retryable` and `retryAfter`. The exit code is `0` while the platform still owns\nthe outcome — `3` is retryable non-delivery, `4` terminal.\n\n## Refusals\n\n| Code | Cause | Fix |\n| --- | --- | --- |\n| `agent_not_authorized_for_session` | The send names an agent the session is not bound to | Drop `--agent`, or send as the agent the session runs |\n| `session_claim_required` | No session or claim authorizes the send | Run inside the managed session, or sign in and send as the person |\n| `context_task_not_authorized_for_session` | The declared `--task` is not this session's | Omit `--task`; a managed session derives it |\n| `task_context_forbidden` | The declared task is not accessible to the sender | Omit `--task`, or name a task you can see |\n| `main_chat_disabled` | The owner's main chat is off | Tell the person; do not route around it |\n| `destination_not_allowed` | Workspace policy excludes this destination | Send to an allowed destination, or ask the person to change policy |\n| `delivery_mode_off` | The owner's delivery mode delivers nothing | Do not resend; say it in the conversation instead |\n| `delivery_mode_suggestions_only` | Policy keeps the update as a suggestion | Leave it — the person sees it in-product |\n| `delivery_mode_ask_first` | Policy wants the person's approval first | Wait for the approval; do not resend |\n| `delivery_policy_unavailable` | Policy could not be read, so the send failed closed | Retry once; if it repeats, tell the person |",
8248
- "hash": "9275d762097f417bca3fc2f5b8d643036cd818af68438ed72cd6374cb134df99",
8249
- "tokens": 723,
8247
+ "body": "Read this when a send answered and you need to know what its status means.\n\n| Status | Meaning |\n| --- | --- |\n| `submitted` | recorded, not yet dispatched — still owned by the platform |\n| `held` | policy withheld it for now; it may still be delivered — `reason` says why |\n| `re_evaluation` | being re-checked against policy — still owned by the platform |\n| `approval_required` | waiting on the person’s approval; `initiativeId` names what they act on |\n| `authorized` | cleared for dispatch — still owned by the platform |\n| `dispatching` | being delivered right now |\n| `delivered` | reached the user |\n| `transport_failed` | delivery errored; `retryable` and `retryAfter` say whether to try again |\n| `dropped` | will not be delivered — read `reason` and change the request before resending |\n| `expired` | outlived its window before delivery |\n| `cancelled` | withdrawn before delivery |\n| `duplicate` | the idempotency key already carried this identical update — the earlier send stands |\n| `accepted` | an earlier send already delivered this update |\n| `failed` | the transport could not deliver; `retryable` says whether a retry can help |\n| `queued_offline` | held by the local daemon until it can reach the platform — still in flight |\n| `refused` | a guard declined the send; `reason` names it |\n| `unknown` | the transport could not certify the outcome |\n\nA `held`, `approval_required` or `dropped` result carries `reason`; an approval\ncarries `initiativeId` for the person to act on; a transport failure carries\n`retryable` and `retryAfter`. The exit code is `0` while the platform still owns\nthe outcome — `3` is retryable non-delivery, `4` terminal.\n\n## Refusals\n\n| Code | Cause | Fix |\n| --- | --- | --- |\n| `agent_not_authorized_for_session` | The send names an agent the session is not bound to | Drop `--agent`, or send as the agent the session runs |\n| `session_claim_required` | No session or claim authorizes the send | Run inside the managed session, or sign in and send as the person |\n| `context_task_not_authorized_for_session` | The declared `--task` is not this session's | Omit `--task`; a managed session derives it |\n| `task_context_forbidden` | The declared task was not found or is not accessible in this workspace | Check the task and workspace, or omit `--task` |\n| `main_chat_disabled` | The owner's main chat is off | Tell the person; do not route around it |\n| `destination_not_allowed` | Workspace policy excludes this destination | Send to an allowed destination, or ask the person to change policy |\n| `delivery_mode_off` | The owner's delivery mode delivers nothing | Do not resend; say it in the conversation instead |\n| `delivery_mode_suggestions_only` | Policy keeps the update as a suggestion | Leave it — the person sees it in-product |\n| `delivery_mode_ask_first` | Policy wants the person's approval first | Wait for the approval; do not resend |\n| `delivery_policy_unavailable` | Policy could not be read, so the send failed closed | Retry once; if it repeats, tell the person |",
8248
+ "hash": "ccd29be3e464db42898f221deca9c8f831c1929d0370d05a0c333def57172a3d",
8249
+ "tokens": 726,
8250
8250
  "sections": [
8251
8251
  {
8252
8252
  "id": "writing",
@@ -8291,7 +8291,7 @@
8291
8291
  "id": "delivery-statuses",
8292
8292
  "title": "Delivery statuses",
8293
8293
  "readWhen": "a send answered and you need to know what its status means",
8294
- "tokens": 723,
8294
+ "tokens": 726,
8295
8295
  "aliases": [],
8296
8296
  "explains": [
8297
8297
  "agent_not_authorized_for_session",
@@ -0,0 +1,2 @@
1
+ /** The reason-only refusal used by session-scoped API routes. */
2
+ export declare function reasonOnlyCode(body: unknown): string | undefined;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reasonOnlyCode = reasonOnlyCode;
4
+ /** The reason-only refusal used by session-scoped API routes. */
5
+ function reasonOnlyCode(body) {
6
+ if (!body || typeof body !== 'object' || Array.isArray(body))
7
+ return undefined;
8
+ const value = body;
9
+ if (value.ok !== false || typeof value.reason !== 'string')
10
+ return undefined;
11
+ const reason = value.reason.trim();
12
+ return reason.length <= 160 && /^[A-Za-z][A-Za-z0-9]*(?:[_-][A-Za-z0-9]+)+$/.test(reason)
13
+ ? reason : undefined;
14
+ }
@@ -31,6 +31,7 @@ exports.hasHumanSession = hasHumanSession;
31
31
  * switch to `dataService.*` without touching the wire contract.
32
32
  */
33
33
  const config_1 = require("./config");
34
+ const api_error_reason_1 = require("./api-error-reason");
34
35
  // ADD-CLI8 — `readFromBackend` is only used inside `hasHumanSession()`
35
36
  // (see below), NOT by `apiFetch`. Kept as a module-scope import
36
37
  // rather than inlined into `hasHumanSession` because (a) ES modules
@@ -282,6 +283,8 @@ async function apiFetch(pathOrUrl, opts = {}) {
282
283
  const parsed = JSON.parse(text);
283
284
  if (typeof parsed.code === 'string')
284
285
  code = parsed.code;
286
+ else
287
+ code = (0, api_error_reason_1.reasonOnlyCode)(parsed);
285
288
  }
286
289
  catch {
287
290
  /* non-JSON body */
@@ -105,6 +105,7 @@ function describeTaskCommandRedirect(config, parts, typedWords) {
105
105
  if (lower[0] === 'tasks' &&
106
106
  lower[1] === 'search' &&
107
107
  hasTopic(config, 'tasks') &&
108
+ config.findCommand('tasks:search') === undefined &&
108
109
  config.findCommand(exports.TASK_COMMAND_MISS_TARGETS.search) !== undefined) {
109
110
  const query = typedWords.slice(2).join(' ').trim();
110
111
  const target = `${config.bin} tasks list --q ${query ? JSON.stringify(query) : '<query>'}`;
@@ -0,0 +1,7 @@
1
+ /** Keep untrusted search content from controlling or reordering a terminal. */
2
+ export declare function searchDisplayText(value: string): string;
3
+ /** Cursor values stay opaque, but must be safe to print and copy into a shell. */
4
+ export declare function isPrintableSearchCursor(value: string): boolean;
5
+ export declare function shellSearchCursor(value: string): string;
6
+ /** A missing or malformed list is an error, not proof of zero matches. */
7
+ export declare function isSearchListPage(value: unknown): boolean;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchDisplayText = searchDisplayText;
4
+ exports.isPrintableSearchCursor = isPrintableSearchCursor;
5
+ exports.shellSearchCursor = shellSearchCursor;
6
+ exports.isSearchListPage = isSearchListPage;
7
+ const node_util_1 = require("node:util");
8
+ /** Keep untrusted search content from controlling or reordering a terminal. */
9
+ function searchDisplayText(value) {
10
+ return (0, node_util_1.stripVTControlCharacters)(value)
11
+ .replace(/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/g, ' ')
12
+ .replace(/\s+/g, ' ')
13
+ .trim();
14
+ }
15
+ /** Cursor values stay opaque, but must be safe to print and copy into a shell. */
16
+ function isPrintableSearchCursor(value) {
17
+ return value.length > 0 && !/[\u0000-\u001f\u007f-\u009f\u202a-\u202e\u2066-\u2069]/.test(value);
18
+ }
19
+ function shellSearchCursor(value) {
20
+ return /^[A-Za-z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
21
+ }
22
+ /** A missing or malformed list is an error, not proof of zero matches. */
23
+ function isSearchListPage(value) {
24
+ if (!value || typeof value !== 'object' || Array.isArray(value))
25
+ return false;
26
+ const page = value;
27
+ return Array.isArray(page.data) && page.data.every((row) => row && typeof row === 'object' && !Array.isArray(row)) &&
28
+ (page.has_more === undefined || typeof page.has_more === 'boolean') &&
29
+ (page.next_cursor === undefined || page.next_cursor === null ||
30
+ (typeof page.next_cursor === 'string' && isPrintableSearchCursor(page.next_cursor)));
31
+ }
@@ -0,0 +1,8 @@
1
+ /** The Store can return an empty page while more candidates remain to inspect. */
2
+ export declare function skillStoreSearchIncomplete(response: unknown): boolean;
3
+ export declare function skillStorePageState(response: unknown, cursor?: string): {
4
+ hasMore: boolean;
5
+ nextCursor?: string;
6
+ invalidCursor: boolean;
7
+ };
8
+ export declare function reportSkillStorePage(response: unknown, cursor: string | undefined, log: (message: string) => void, warn: (message: string) => void): void;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.skillStoreSearchIncomplete = skillStoreSearchIncomplete;
4
+ exports.skillStorePageState = skillStorePageState;
5
+ exports.reportSkillStorePage = reportSkillStorePage;
6
+ /** The Store can return an empty page while more candidates remain to inspect. */
7
+ function skillStoreSearchIncomplete(response) {
8
+ if (!response || Array.isArray(response) || typeof response !== 'object')
9
+ return false;
10
+ const page = response;
11
+ return page.partial === true || page.semanticUnavailable === true;
12
+ }
13
+ function skillStorePageState(response, cursor) {
14
+ if (!response || Array.isArray(response) || typeof response !== 'object') {
15
+ return { hasMore: false, invalidCursor: false };
16
+ }
17
+ const page = response;
18
+ if (page.has_more !== true)
19
+ return { hasMore: false, invalidCursor: false };
20
+ // Server cursors are opaque base64 tokens. Do not print arbitrary terminal
21
+ // control characters from a malformed response, or suggest a cursor loop.
22
+ const next = typeof page.after === 'string' && /^[A-Za-z0-9_+/=-]{1,4096}$/.test(page.after)
23
+ ? page.after
24
+ : undefined;
25
+ if (!next || next === cursor)
26
+ return { hasMore: true, invalidCursor: true };
27
+ return { hasMore: true, nextCursor: next, invalidCursor: false };
28
+ }
29
+ function reportSkillStorePage(response, cursor, log, warn) {
30
+ const page = skillStorePageState(response, cursor);
31
+ if (page.nextCursor)
32
+ log(`Next page: --cursor ${page.nextCursor}`);
33
+ else if (page.invalidCursor)
34
+ warn('More results may exist, but the server did not provide a usable next cursor.');
35
+ }
@@ -54,6 +54,16 @@ export declare function splitKeyConvergencePolicy(): {
54
54
  converge: boolean;
55
55
  reason: 'daemon_key_pinned' | 'daemon_key_refused';
56
56
  };
57
+ /** Open only the existing wrapped DEK. Recovery must never enroll a new key,
58
+ * consolidate profile paths or replace an unreadable envelope. A caller gets
59
+ * an error if the existing file or the platform's read-only unwrap is unsafe
60
+ * or unavailable. This intentionally does not load retired keys; credentials
61
+ * that require one remain unavailable rather than triggering a migration. */
62
+ export declare function initExistingCredEnvelope(profile: string): Promise<void>;
63
+ /** First enrollment for a reserved desktop background profile. Existing or
64
+ * ambiguous state is opened read-only or refused; it is never re-enrolled.
65
+ * The caller must validate the reservation before calling this function. */
66
+ export declare function initNewIndependentCredEnvelope(profile: string): Promise<void>;
57
67
  /**
58
68
  * Initialize the envelope path. Idempotent — second call when state is
59
69
  * non-uninit returns immediately.