@vibe-agent-toolkit/cli 0.2.0-rc.4 → 0.2.0-rc.6

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 (92) hide show
  1. package/dist/bin.js +35 -2
  2. package/dist/bin.js.map +1 -1
  3. package/dist/commands/audit.d.ts.map +1 -1
  4. package/dist/commands/audit.js +169 -17
  5. package/dist/commands/audit.js.map +1 -1
  6. package/dist/commands/claude/claude-config.d.ts.map +1 -1
  7. package/dist/commands/claude/claude-config.js +6 -0
  8. package/dist/commands/claude/claude-config.js.map +1 -1
  9. package/dist/commands/claude/org/helpers.d.ts +59 -1
  10. package/dist/commands/claude/org/helpers.d.ts.map +1 -1
  11. package/dist/commands/claude/org/helpers.js +58 -7
  12. package/dist/commands/claude/org/helpers.js.map +1 -1
  13. package/dist/commands/claude/org/index.d.ts.map +1 -1
  14. package/dist/commands/claude/org/index.js +24 -16
  15. package/dist/commands/claude/org/index.js.map +1 -1
  16. package/dist/commands/claude/org/skills.d.ts +428 -0
  17. package/dist/commands/claude/org/skills.d.ts.map +1 -1
  18. package/dist/commands/claude/org/skills.js +1189 -91
  19. package/dist/commands/claude/org/skills.js.map +1 -1
  20. package/dist/commands/claude/org/users.d.ts.map +1 -1
  21. package/dist/commands/claude/org/users.js +3 -1
  22. package/dist/commands/claude/org/users.js.map +1 -1
  23. package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
  24. package/dist/commands/claude/org/workspaces.js +5 -2
  25. package/dist/commands/claude/org/workspaces.js.map +1 -1
  26. package/dist/commands/claude/plugin/install.js +0 -1
  27. package/dist/commands/claude/plugin/install.js.map +1 -1
  28. package/dist/commands/corpus/runner.d.ts.map +1 -1
  29. package/dist/commands/corpus/runner.js +1 -19
  30. package/dist/commands/corpus/runner.js.map +1 -1
  31. package/dist/commands/inventory.js +1 -1
  32. package/dist/commands/inventory.js.map +1 -1
  33. package/dist/commands/resources/check-progress.d.ts +145 -0
  34. package/dist/commands/resources/check-progress.d.ts.map +1 -0
  35. package/dist/commands/resources/check-progress.js +205 -0
  36. package/dist/commands/resources/check-progress.js.map +1 -0
  37. package/dist/commands/resources/check-supervisor.d.ts +465 -0
  38. package/dist/commands/resources/check-supervisor.d.ts.map +1 -0
  39. package/dist/commands/resources/check-supervisor.js +566 -0
  40. package/dist/commands/resources/check-supervisor.js.map +1 -0
  41. package/dist/commands/resources/check.d.ts +454 -0
  42. package/dist/commands/resources/check.d.ts.map +1 -0
  43. package/dist/commands/resources/check.js +1237 -0
  44. package/dist/commands/resources/check.js.map +1 -0
  45. package/dist/commands/resources/index.d.ts.map +1 -1
  46. package/dist/commands/resources/index.js +277 -6
  47. package/dist/commands/resources/index.js.map +1 -1
  48. package/dist/commands/resources/query.d.ts +89 -0
  49. package/dist/commands/resources/query.d.ts.map +1 -0
  50. package/dist/commands/resources/query.js +146 -0
  51. package/dist/commands/resources/query.js.map +1 -0
  52. package/dist/commands/resources/scan.js +1 -1
  53. package/dist/commands/resources/scan.js.map +1 -1
  54. package/dist/commands/skill/review-checklist.d.ts.map +1 -1
  55. package/dist/commands/skill/review-checklist.js +35 -0
  56. package/dist/commands/skill/review-checklist.js.map +1 -1
  57. package/dist/commands/skill/test/configure.d.ts +37 -0
  58. package/dist/commands/skill/test/configure.d.ts.map +1 -1
  59. package/dist/commands/skill/test/configure.js +57 -12
  60. package/dist/commands/skill/test/configure.js.map +1 -1
  61. package/dist/commands/skills/install.js +0 -1
  62. package/dist/commands/skills/install.js.map +1 -1
  63. package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
  64. package/dist/commands/skills/skill-discovery.js +4 -2
  65. package/dist/commands/skills/skill-discovery.js.map +1 -1
  66. package/dist/utils/agent-runner.d.ts.map +1 -1
  67. package/dist/utils/agent-runner.js +7 -3
  68. package/dist/utils/agent-runner.js.map +1 -1
  69. package/dist/utils/command-error.d.ts +56 -1
  70. package/dist/utils/command-error.d.ts.map +1 -1
  71. package/dist/utils/command-error.js +66 -3
  72. package/dist/utils/command-error.js.map +1 -1
  73. package/dist/utils/config-loader.d.ts.map +1 -1
  74. package/dist/utils/config-loader.js +30 -7
  75. package/dist/utils/config-loader.js.map +1 -1
  76. package/dist/utils/issue-severity.d.ts +12 -5
  77. package/dist/utils/issue-severity.d.ts.map +1 -1
  78. package/dist/utils/issue-severity.js +1 -1
  79. package/dist/utils/issue-severity.js.map +1 -1
  80. package/dist/utils/projection-query.d.ts +263 -0
  81. package/dist/utils/projection-query.d.ts.map +1 -0
  82. package/dist/utils/projection-query.js +262 -0
  83. package/dist/utils/projection-query.js.map +1 -0
  84. package/dist/utils/projection-store.d.ts +104 -2
  85. package/dist/utils/projection-store.d.ts.map +1 -1
  86. package/dist/utils/projection-store.js +126 -4
  87. package/dist/utils/projection-store.js.map +1 -1
  88. package/dist/utils/vat-bin-path.d.ts +36 -0
  89. package/dist/utils/vat-bin-path.d.ts.map +1 -0
  90. package/dist/utils/vat-bin-path.js +49 -0
  91. package/dist/utils/vat-bin-path.js.map +1 -0
  92. package/package.json +25 -14
@@ -1,4 +1,341 @@
1
+ import type { MultipartFile, MultipartResult, OrgApiClient } from '@vibe-agent-toolkit/claude-marketplace';
2
+ import type { ValidationConfig } from '@vibe-agent-toolkit/schema';
1
3
  import { Command } from 'commander';
4
+ import type { OrgCommandFailure } from './helpers.js';
5
+ export interface SkillUploadResult {
6
+ id: string;
7
+ displayTitle: string;
8
+ version: string;
9
+ createdAt: string;
10
+ }
11
+ interface UploadLogger {
12
+ info: (msg: string) => void;
13
+ /**
14
+ * REQUIRED, not optional. An optional `warn` invites `logger.warn?.(…)`,
15
+ * which drops the message wherever a caller supplied only `info` — and a
16
+ * warning that vanishes depending on its caller is the exact shape this
17
+ * command keeps being audited for.
18
+ */
19
+ warn: (msg: string) => void;
20
+ }
21
+ /** Read `POST /v1/skills` — the shape measured against the live API. */
22
+ export declare function readCreateSkillResponse(raw: unknown): SkillUploadResult;
23
+ /** The document a delete command publishes. */
24
+ export interface SkillDeleteResult {
25
+ readonly id: string;
26
+ readonly deleted: boolean;
27
+ }
28
+ /**
29
+ * Read a DELETE response into the result a delete command prints.
30
+ *
31
+ * 🔑 Same class of problem as {@link readSkillUploadResponse} — the client's
32
+ * `<T>` is an assertion, not a check — but the OPPOSITE verdict on an empty
33
+ * body, and deliberately so. The client used to reject a 2xx carrying no body
34
+ * with a parse error, which reported a 204 DELETE that SUCCEEDED as a failure;
35
+ * that is fixed, and the value now handed to this reader for such a response is
36
+ * `undefined`. Refusing it here, the way an upload response is refused, would
37
+ * reinstate the same lie one layer up — and reading `.id` off it, which is what
38
+ * the two call sites did, is a `TypeError` in place of a report.
39
+ *
40
+ * So an empty body is read as the success it is: the status already said the
41
+ * resource is gone, the id is the one this process asked for, and there is
42
+ * nothing else to learn. Measured live behaviour today is a JSON body carrying
43
+ * `type: skill_deleted`, so the empty case is LATENT rather than a live
44
+ * regression — but it is one 204 away, and a latent `TypeError` is not a
45
+ * contract.
46
+ *
47
+ * `deleted` is false only when the body affirmatively names a DIFFERENT
48
+ * outcome, which is the one case where the API is saying something this command
49
+ * must not paper over — and {@link reportDelete} is what makes the run END that
50
+ * way rather than merely say so in a field nothing reads.
51
+ *
52
+ * ⚠️ `expectedTypes` is a LIST because only one member of it is measured.
53
+ * `skill_deleted` came back from a live `DELETE /v1/skills/{id}`;
54
+ * `skill_version_deleted` is the plausible spelling for the version endpoint and
55
+ * has never been seen. A single guessed string would make every version delete
56
+ * report `deleted: false` — and now exit 1 — if the vendor spells it differently
57
+ * by one character. Accepting either keeps the check honest about what it knows:
58
+ * a body naming something that is neither is a real divergence worth failing on.
59
+ */
60
+ export declare function readDeleteResponse(raw: unknown, requestedId: string, expectedTypes: readonly string[]): SkillDeleteResult;
61
+ /** The success types measured against the live `DELETE /v1/skills/{id}`. */
62
+ export declare const SKILL_DELETED_TYPES: readonly string[];
63
+ /**
64
+ * The success types a version delete may answer with — see
65
+ * {@link readDeleteResponse} for why this is two and not one.
66
+ */
67
+ export declare const SKILL_VERSION_DELETED_TYPES: readonly string[];
68
+ /**
69
+ * A delete's document, tagged as a FAILED run when the API said the thing was
70
+ * not deleted.
71
+ *
72
+ * 🔑 Without this, `deleted: false` was computed, printed under
73
+ * `status: success`, and exited 0 — the exact "the run completed and its outcome
74
+ * is wrong" shape that {@link orgCommandFailure} was added in this same change to
75
+ * fix for `--from-npm`, in the one branch that never got wired to it. A CI
76
+ * wrapper spelled `vat claude org skills delete X || fail` reported green while
77
+ * the skill was still there.
78
+ *
79
+ * The document is still PUBLISHED — the id and the verdict are what the operator
80
+ * needs — and only the exit code changes. Throwing instead would end non-zero and
81
+ * discard the report.
82
+ */
83
+ export declare function reportDelete(raw: unknown, requestedId: string, expectedTypes: readonly string[]): SkillDeleteResult | OrgCommandFailure;
84
+ /** The document a version delete publishes: which version, of which skill. */
85
+ export interface SkillVersionDeleteResult extends SkillDeleteResult {
86
+ readonly version: string;
87
+ }
88
+ /**
89
+ * A version delete's document — the same verdict as {@link reportDelete}, about
90
+ * a subject that can actually be identified.
91
+ *
92
+ * 🚨 **The version-delete document used to name no version at all, and its `id`
93
+ * meant two different things depending on the response.** It went through
94
+ * `reportDelete(raw, skillId, …)`, so `readDeleteResponse` returned the API's
95
+ * ECHOED id when there was a body — the VERSION identifier — and fell back to
96
+ * the requested id — the SKILL identifier — on a 204. Two runs of the same
97
+ * command therefore published `id` fields from two different namespaces, and
98
+ * neither run's document said which of a skill's versions had been destroyed.
99
+ * An audit trail of an irreversible operation that cannot name what it destroyed
100
+ * is not an audit trail.
101
+ *
102
+ * Both fields are now local knowledge, which is the whole point: this process
103
+ * asked to delete `version` of `skillId` and the API confirmed a deletion, so
104
+ * nothing about the subject's identity has to be recovered from the response
105
+ * shape. The response is still read — for the VERDICT, which is the one thing
106
+ * only the API knows.
107
+ */
108
+ export declare function reportVersionDelete(raw: unknown, skillId: string, version: string): SkillVersionDeleteResult | OrgCommandFailure;
109
+ /**
110
+ * Add the versions a `--all` run destroyed to its report, preserving whatever
111
+ * verdict {@link reportDelete} reached.
112
+ *
113
+ * Unwrapping and re-wrapping rather than spreading into the tagged value: the
114
+ * failure tag sits BESIDE the document, so a naive `{ ...result, deletedVersions }`
115
+ * on a failure would produce an object carrying `orgCommandFailed` next to the
116
+ * skill's fields and publish the tag as part of the operator's document.
117
+ */
118
+ export declare function mergeDeleteReport(result: SkillDeleteResult | OrgCommandFailure, deletedVersions: readonly string[]): object;
119
+ /** Read `POST /v1/skills/{id}/versions`. */
120
+ export declare function readSkillVersionResponse(raw: unknown): SkillUploadResult;
121
+ /**
122
+ * Build the multipart request body for an upload, refusing it before anything is
123
+ * sent when THAT BODY is OVER the API's upload ceiling.
124
+ *
125
+ * 🔑 **The ceiling is INCLUSIVE, and that is measured rather than reasoned.** A
126
+ * request body of exactly {@link API_SKILL_MAX_UPLOAD_BYTES} bytes is ACCEPTED;
127
+ * one byte more is refused `413`:
128
+ *
129
+ * | raw file bytes | + framing | = body | live API |
130
+ * |---|---|---|---|
131
+ * | 31,456,735 | 545 | **31,457,280** | `status: success` |
132
+ * | 31,456,736 | 545 | 31,457,281 | `413` |
133
+ *
134
+ * So the comparison here is `>`, not `>=`. An earlier version of this code used
135
+ * `>=` on the argument that firing AT the ceiling was the conservative reading —
136
+ * an argument that was never measured, and the measurement above refutes it. It
137
+ * is not conservative: it refuses a body the API takes, and the operator has no
138
+ * way to tell that VAT and not Anthropic said no.
139
+ *
140
+ * ⚠️ **The build-time lane deliberately differs, and must not be "harmonised"
141
+ * with this one.** `checkPackagedSizeLimit` fires when FILE BYTES reach the same
142
+ * number — `>=` — because framing is never zero, so files totalling exactly the
143
+ * limit always produce a request LARGER than the limit and therefore a real 413.
144
+ * Two lanes, two measures, two rules: **file bytes `>=` refuse; request bytes `>`
145
+ * refuse.** Both are right about the quantity each can see.
146
+ *
147
+ * THE one gate every upload passes through, whichever shape it started as. The
148
+ * check used to live inside the directory-packaging step alone, so
149
+ * `skills install big-skill.zip` — the one input that is by construction a
150
+ * single large binary, and the shape the check was written for — reached the
151
+ * wire unmeasured.
152
+ *
153
+ * 🔑 **It weighs the BODY, not the sum of the file bytes.** The API measures the
154
+ * request, and the request is this buffer. Summing `file.content.length` — what
155
+ * this did — ignores the per-part framing `buildMultipartFormData` adds: a
156
+ * 51-byte boundary line, a `Content-Disposition` of 61 bytes plus the filename, a
157
+ * 42-byte content-type-and-blank-line and a 2-byte trailing CRLF, so 156 bytes
158
+ * plus the filename PER FILE, plus a 53-byte terminator. A 1,000-file bundle
159
+ * therefore carries ~180 KiB that the old measure could not see, and a bundle
160
+ * whose content sat just under the ceiling passed the pre-flight and then earned
161
+ * the 413 this check exists to prevent — 11 seconds for 30 MB, measured.
162
+ *
163
+ * No headroom constant closes that gap, and none is added: the exact number is
164
+ * available for free by building the body first and asking it how long it is.
165
+ * The body is then RETURNED, so the bytes that were weighed are the bytes that go
166
+ * out; a gate that only inspected its inputs would be one refactor away from
167
+ * measuring something the caller no longer sends.
168
+ *
169
+ * The build-time `PACKAGED_SIZE_EXCEEDS_API_LIMIT` cannot do this — there is no
170
+ * request at build time — so it weighs files on disk and says so. The two
171
+ * messages name what each measured rather than pretending to be the same number.
172
+ */
173
+ export declare function buildUploadBodyOrRefuse(fields: Record<string, string>, files: readonly MultipartFile[], bundleRoot?: string): MultipartResult;
174
+ /**
175
+ * A vendor refusal this CLI can answer with a specific next command.
176
+ *
177
+ * `matches` are ALL required, and are deliberately more than one: a single word
178
+ * like `version` appears in refusals that have nothing to do with this case, so
179
+ * each entry names both the subject the API is talking about and the verdict it
180
+ * reached about it.
181
+ */
182
+ interface VendorRefusalRemedy {
183
+ /** Every pattern must match the API's message for the remedy to apply. */
184
+ readonly matches: readonly RegExp[];
185
+ /** Appended to the vendor's sentence — never substituted for it. */
186
+ readonly remedy: string;
187
+ }
188
+ /**
189
+ * A failed request, re-thrown with the command that answers it when — and only
190
+ * when — the API said one of the specific things listed by the caller.
191
+ *
192
+ * **What is matched, exactly:** an {@link ApiRequestError} whose `statusCode` is
193
+ * 400 and whose message satisfies every pattern of one {@link
194
+ * VendorRefusalRemedy}. Both live wordings are measured, not guessed:
195
+ * `400 Skill cannot reuse an existing display_title` and
196
+ * `400 Cannot delete skill with existing versions. Delete all versions first.`
197
+ *
198
+ * **How it fails safe:** anything that does not match is returned UNTOUCHED, so
199
+ * an unrelated 400 keeps the API's exact words and gets no misleading remedy. If
200
+ * the vendor rewords a refusal, the operator loses a hint — they never gain a
201
+ * wrong one. The remedy is appended, so the vendor's sentence survives in full.
202
+ *
203
+ * One mechanism, several refusals, and each call site passes only the refusals
204
+ * that are REACHABLE from it — a second copy of this matcher per case is how the
205
+ * two would come to disagree about what "fail safe" means.
206
+ */
207
+ export declare function withRemedy(error: unknown, candidates: readonly VendorRefusalRemedy[]): unknown;
208
+ /**
209
+ * The skill still has versions, so it cannot be deleted.
210
+ *
211
+ * `--all` leads, because it IS the one-step path: the `--all` branch of this
212
+ * command fetches every version and deletes them before deleting the skill. The
213
+ * by-hand sequence follows for an operator who wants to see what is there first.
214
+ * Naming only `versions delete` would send them round a loop they can already
215
+ * ask the CLI to run.
216
+ */
217
+ export declare const EXISTING_VERSIONS_REFUSAL: VendorRefusalRemedy;
218
+ /** Only the CREATE path can earn a duplicate-title refusal — see {@link uploadSkillDir}. */
219
+ export declare function withDuplicateTitleRemedy(error: unknown): unknown;
220
+ /**
221
+ * The version's SKILL.md declares a different `name` than the skill it is being
222
+ * added to.
223
+ *
224
+ * The server enforces name consistency per `skill_id` (measured), which is why
225
+ * `versions add` cannot silently re-root a skill's file tree and why this is the
226
+ * one refusal that endpoint can earn. The remedy names both fixes, because which
227
+ * one is right depends on what the operator meant: keep the skill and put its
228
+ * name back, or publish the renamed tree as the separate skill it now is.
229
+ *
230
+ * ⚠️ The vendor's exact wording here has NOT been measured, only the fact of the
231
+ * refusal. `withRemedy` fails safe on no match — the operator loses a hint, never
232
+ * gains a wrong one — so a guessed pattern is the conservative thing to ship.
233
+ */
234
+ export declare const VERSION_NAME_MISMATCH_REFUSAL: VendorRefusalRemedy;
235
+ /** Only the VERSION path can earn a name-consistency refusal — see {@link uploadSkillVersionDir}. */
236
+ export declare function withVersionRootRemedy(error: unknown): unknown;
237
+ /**
238
+ * A failure that got NO answer from the server, re-thrown saying what was
239
+ * actually sent and what a retry would risk.
240
+ *
241
+ * ⛔ **The trigger is a RECORDED FACT, never the error's class.** This used to
242
+ * read `if (error instanceof ApiRequestError) return error;` — "a completed
243
+ * exchange always arrives as an `ApiRequestError`, so anything else must be a
244
+ * dropped connection". The first half is true and the converse is not, and the
245
+ * converse is what shipped: `buildSkillsHeaders()` throws a plain `Error` before
246
+ * a socket is ever opened, so
247
+ * `ANTHROPIC_API_KEY= vat claude org skills install <dir>` told a first-time
248
+ * operator, on top of the real "no key" message, that a connection had closed,
249
+ * that VAT had sent 6.8 KiB (the length of a buffer that never left the process),
250
+ * and that the outcome was unknown — then sent them to a recovery command that
251
+ * fails with the identical missing-key error. Three false statements and a loop.
252
+ *
253
+ * So the gate is POSITIVE and evidential: annotate only an
254
+ * {@link ApiTransportError}, which exists only once the transport has been
255
+ * reached and carries `bytesSent` read off the socket at failure time. Anything
256
+ * else — a missing credential, a bad URL, a response VAT refused to read —
257
+ * passes through with its own message untouched.
258
+ *
259
+ * Two outcomes, because the byte count decides which is TRUE:
260
+ *
261
+ * - **Nothing left the machine** (`bytesSent === 0`: DNS never resolved, the
262
+ * connection was refused, the handshake failed). The outcome is not unknown,
263
+ * it is known: nothing happened. Saying "check what exists" here would send
264
+ * an operator to look for a skill that was never sent.
265
+ * - **Some bytes went out and no status came back.** Now the outcome genuinely
266
+ * is unknown, and the part the operator cannot see is how far it got. The
267
+ * client never replays a POST — one that failed with no status may still have
268
+ * taken effect — so the retry is theirs, and it can leave two skills behind.
269
+ *
270
+ * **No threshold.** There is no constant here for "close to the ceiling" and
271
+ * there must not be: an invented margin is a number nobody can re-derive. The
272
+ * bytes sent, the body size and the ceiling are printed and the reader draws
273
+ * their own conclusion.
274
+ */
275
+ export declare function explainAnsweredNothing(error: unknown, bodyBytes: number): unknown;
276
+ /**
277
+ * Resolve a `<source>` CLI argument to an absolute path.
278
+ *
279
+ * 🪤 The test used to be `source.startsWith('/')`, which is false for
280
+ * `D:\builds\skill` — so a Windows operator's absolute path was joined onto the
281
+ * working directory and reported back as `Source not found: <cwd>/D:/builds/skill`.
282
+ * {@link isAbsoluteAnyPlatform} answers for POSIX roots, drive letters and UNC
283
+ * paths on EVERY host, so the behaviour is the same wherever it runs and a
284
+ * POSIX-only CI can see the drive-letter case at all.
285
+ */
286
+ export declare function resolveSourceArgument(source: string): string;
287
+ /** What {@link inspectZipArchive} can tell a caller about an archive. */
288
+ export interface ZipInspection {
289
+ /** The API-enforced quantity: the sum of every entry's declared size. */
290
+ readonly uncompressedBytes: number;
291
+ /** The `name` declared by the SKILL.md nearest the archive root, if any. */
292
+ readonly declaredName: string | undefined;
293
+ /**
294
+ * Entry names carrying a {@link NEVER_UPLOADED_DIR_NAMES} path segment —
295
+ * `evals/` above all. The directory lane REFUSES these; this is what lets the
296
+ * ZIP lane reach the same verdict about the same content.
297
+ */
298
+ readonly neverUploaded: readonly string[];
299
+ }
300
+ /**
301
+ * What a ZIP will weigh AFTER the API expands it, read from the archive's own
302
+ * central directory — plus the name its inner SKILL.md declares, and any answer
303
+ * key it carries.
304
+ *
305
+ * 🔑 **The API expands a ZIP and applies the ceiling to the UNCOMPRESSED total,
306
+ * not to the archive.** Measured against the live API by an adopter: a
307
+ * 10,707,463-byte archive of a 47.85 MiB tree — comfortably inside the request
308
+ * ceiling as bytes on the wire — came back
309
+ * `400: Zip file uncompressed size exceeds 30MB`. So the body check every other
310
+ * shape passes through is structurally blind here: compression is exactly the
311
+ * thing that makes the measured quantity stop predicting the enforced one. A
312
+ * ZIP is therefore the one input that could pass every local gate and still be
313
+ * refused remotely, which is the same defect class as the ZIP path once
314
+ * skipping the size check altogether.
315
+ *
316
+ * ⚠️ **The boundary itself is UNMEASURED on this lane.** One refusal at 47.85
317
+ * MiB is all the evidence there is; nobody has bracketed where the uncompressed
318
+ * rule actually cuts, or confirmed it is the same constant as the request lane.
319
+ * So this refuses only on `>` — strictly the looser choice — and a bundle near
320
+ * the line is still sent for the API to judge. Do not tighten this to `>=`, or
321
+ * quote it as a measured ceiling, without bracketing it the way
322
+ * {@link API_SKILL_MAX_UPLOAD_BYTES} was bracketed.
323
+ *
324
+ * ⛔ Sizes come from entry HEADERS, which an archive can lie about. That is
325
+ * fine: a lie can only change whether VAT refuses early, never whether the API
326
+ * does.
327
+ *
328
+ * ⚠️ **Reading an entry is not free, and the docstring here used to claim it
329
+ * was** — "no zip-slip or zip-bomb surface is opened — the entries are read, not
330
+ * written" was true of the enumeration half and FALSE of the one `getData()`
331
+ * call, which inflates `header.size` bytes into memory. Worse, it ran BEFORE the
332
+ * caller's uncompressed-total gate, so the ceiling this function exists to
333
+ * enforce could not protect the inflation this function performed. Nothing is
334
+ * written to disk — that part stands — but the decompression is now ordered
335
+ * after the total is known and bounded by {@link MAX_INSPECTED_SKILL_MD_BYTES},
336
+ * so an archive declaring a 4 GiB SKILL.md is enumerated and never inflated.
337
+ */
338
+ export declare function inspectZipArchive(zipPath: string): Promise<ZipInspection | undefined>;
2
339
  interface CollectedUploadFiles {
3
340
  files: Array<{
4
341
  relativePath: string;
@@ -19,6 +356,97 @@ interface CollectedUploadFiles {
19
356
  * no caller can obtain an upload set with the exclusion skipped.
20
357
  */
21
358
  export declare function collectSkillUploadFiles(skillDir: string): Promise<CollectedUploadFiles>;
359
+ /**
360
+ * Warn about references in the bundle that cannot resolve once it is published.
361
+ *
362
+ * 🚨 **Until this existed, `install` validated NOTHING.** It weighed the request
363
+ * and sent it; every check VAT owns — the non-portable reference family, the
364
+ * unqualified MCP tool names, the non-portable command family — ran in
365
+ * `vat audit` and `vat skills build` and never on the one path where content
366
+ * leaves the machine. An adopter found the consequence directly: of 54 built
367
+ * skills, 10 referenced paths outside their own directory, one of them exec'ing
368
+ * a script under a SIBLING skill. Under the Skills API each skill is its own
369
+ * top-level tree with no siblings, so those uploaded with a green tick and could
370
+ * not possibly run. "It uploaded" is not "it works", and the publish command was
371
+ * the only lane in a position to say so before the bytes left.
372
+ *
373
+ * ⚠️ **Warns, never refuses.** These are `warning`-severity codes and the
374
+ * operator may have reasons VAT cannot see; turning a publish into an exit 2 on
375
+ * a heuristic is a worse failure than the one being reported. Blocking belongs
376
+ * to `vat skills build` and `vat audit`, which run before this and can gate CI.
377
+ *
378
+ * Costs nothing extra: it reads the buffers already collected for the upload, so
379
+ * no file is opened twice and nothing is walked again.
380
+ *
381
+ * 🚨 **The three collectors are RAW issue producers, and raw issues are not what
382
+ * an adopter agreed to see.** Everywhere else in VAT they pass through
383
+ * {@link runValidationFramework}, which applies `validation.allow` waivers and
384
+ * `validation.severity` overrides. Printed unfiltered, this lane contradicted
385
+ * VAT's own documented remedy: `MCP_TOOL_NAME_UNQUALIFIED` tells authors to
386
+ * "waive that one identifier with a `validation.allow` entry", and an author who
387
+ * did exactly that got a green `vat skills build` and then the same warning on
388
+ * every publish with nothing left to silence it with.
389
+ *
390
+ * ⚠️ The `location` is the BUNDLE-relative path, not the API-keyed
391
+ * `<declared-name>/<path>` spelling. An allow glob matches `ValidationIssue.location`,
392
+ * which is contractually project/bundle-relative, so the keyed spelling could not
393
+ * have matched an entry even once allows were applied — the same divergence
394
+ * {@link bundleRelativeName} exists to strip out of the oversize message.
395
+ *
396
+ * ⛔ The run-level ALLOW_UNUSED sweep is deliberately NOT drained here. This lane
397
+ * runs three validator families out of the whole registry, so every allow entry
398
+ * for any other code would be reported as dead — advising the author to delete
399
+ * the entry that makes their build green.
400
+ */
401
+ export declare function warnUnportableReferences(files: readonly MultipartFile[], bundleRoot: string | undefined, validation: ValidationConfig | undefined, logger: UploadLogger): void;
402
+ /**
403
+ * List candidate package directories in node_modules (scoped + unscoped).
404
+ *
405
+ * Exported for testing: this and {@link findSkillsDir} decide WHICH tree
406
+ * `--from-npm` publishes to an org, and the whole `--from-npm` path was
407
+ * untested — `packages/cli/src/commands/**` is coverage-excluded, so nothing in
408
+ * any report said so.
409
+ */
410
+ export declare function listNodeModulePackages(nodeModulesDir: string): string[];
411
+ /**
412
+ * Find the dist/skills/ directory in a package. Checks the package itself
413
+ * first, then scans node_modules for sub-packages that contain built skills.
414
+ */
415
+ export declare function findSkillsDir(packageDir: string): string | undefined;
416
+ /** One skill the batch could not publish, and why. */
417
+ export interface SkillUploadFailure {
418
+ readonly skill: string;
419
+ readonly error: string;
420
+ }
421
+ /** The document `install --from-npm` publishes. */
422
+ export interface NpmInstallSummary {
423
+ source: string;
424
+ skillsUploaded: number;
425
+ skillsFailed?: number;
426
+ errors?: readonly SkillUploadFailure[];
427
+ skills: readonly SkillUploadResult[];
428
+ }
429
+ /**
430
+ * The batch's report, tagged as a failure when ANY skill did not publish.
431
+ *
432
+ * 🔑 Partial success is a failure. The old code returned this document plainly,
433
+ * so `executeOrgCommand` stamped `status: success` on it and exited 0 — a run in
434
+ * which all three skills were rejected printed `skillsUploaded: 0 /
435
+ * skillsFailed: 3` under `status: success`, and a CI wrapper written as
436
+ * `vat claude org skills install --from-npm … || fail` published nothing and
437
+ * reported green.
438
+ *
439
+ * Some-succeeded is tagged the same way as none-succeeded, deliberately: the
440
+ * workspace is now in a MIXED state that nobody asked for, which is exactly the
441
+ * case a human has to look at. Calling it green because two of three landed is
442
+ * the same lie, only smaller. What did land stays in the document, so the reader
443
+ * can see how far the run got.
444
+ */
445
+ export declare function summarizeNpmInstall(source: string, results: readonly SkillUploadResult[], errors: readonly SkillUploadFailure[]): NpmInstallSummary | OrgCommandFailure;
446
+ /**
447
+ * Upload a local skill directory or ZIP file. Exported for testing.
448
+ */
449
+ export declare function installFromLocal(source: string, titleOverride: string | undefined, client: OrgApiClient, logger: UploadLogger): Promise<object>;
22
450
  export declare function createOrgSkillsCommand(): Command;
23
451
  export {};
24
452
  //# sourceMappingURL=skills.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/org/skills.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwFpC,UAAU,oBAAoB;IAC7B,KAAK,EAAE,KAAK,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AA8DD;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAI7F;AAsMD,wBAAgB,sBAAsB,IAAI,OAAO,CAoKhD"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/org/skills.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,aAAa,EACb,eAAe,EACf,YAAY,EACb,MAAM,wCAAwC,CAAC;AAEhD,OAAO,KAAK,EAAE,gBAAgB,EAAmB,MAAM,4BAA4B,CAAC;AAUpF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAStD,MAAM,WAAW,iBAAiB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,YAAY;IACrB,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B;;;;;OAKG;IACH,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5B;AA2DD,wEAAwE;AACxE,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAIvE;AAED,+CAA+C;AAC/C,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,kBAAkB,CACjC,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC9B,iBAAiB,CASnB;AAED,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAAsB,CAAC;AAExE;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,SAAS,MAAM,EAA+C,CAAC;AAEzG;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC3B,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,SAAS,MAAM,EAAE,GAC9B,iBAAiB,GAAG,iBAAiB,CAGvC;AAED,8EAA8E;AAC9E,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAClC,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACb,wBAAwB,GAAG,iBAAiB,CAI9C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,EAC7C,eAAe,EAAE,SAAS,MAAM,EAAE,GAChC,MAAM,CAIR;AAED,4CAA4C;AAC5C,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,OAAO,GAAG,iBAAiB,CAIxE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,wBAAgB,uBAAuB,CACtC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,UAAU,CAAC,EAAE,MAAM,GACjB,eAAe,CAWjB;AAwBD;;;;;;;GAOG;AACH,UAAU,mBAAmB;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,mBAAmB,EAAE,GAAG,OAAO,CAU9F;AAuBD;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,EAAE,mBAQvC,CAAC;AAEF,4FAA4F;AAC5F,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEhE;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,6BAA6B,EAAE,mBAQ3C,CAAC;AAEF,qGAAqG;AACrG,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE7D;AA4BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAoBjF;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAI5D;AAYD,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAkC3F;AA4ID,UAAU,oBAAoB;IAC7B,KAAK,EAAE,KAAK,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7D;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,EAAE,CAAC;CACnB;AAiID;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAI7F;AA+ED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,wBAAwB,CACvC,KAAK,EAAE,SAAS,aAAa,EAAE,EAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,UAAU,EAAE,gBAAgB,GAAG,SAAS,EACxC,MAAM,EAAE,YAAY,GAClB,IAAI,CA0BN;AAuED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBvE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAapE;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACvC,MAAM,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACrC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,MAAM,EAAE,SAAS,kBAAkB,EAAE,GACnC,iBAAiB,GAAG,iBAAiB,CAQvC;AA8DD;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,YAAY,GAClB,OAAO,CAAC,MAAM,CAAC,CAgCjB;AAiHD,wBAAgB,sBAAsB,IAAI,OAAO,CA8XhD"}