@vibe-agent-toolkit/cli 0.2.0-rc.5 → 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.
- package/dist/commands/audit.d.ts.map +1 -1
- package/dist/commands/audit.js +146 -12
- package/dist/commands/audit.js.map +1 -1
- package/dist/commands/claude/claude-config.d.ts.map +1 -1
- package/dist/commands/claude/claude-config.js +6 -0
- package/dist/commands/claude/claude-config.js.map +1 -1
- package/dist/commands/claude/org/helpers.d.ts +59 -1
- package/dist/commands/claude/org/helpers.d.ts.map +1 -1
- package/dist/commands/claude/org/helpers.js +58 -7
- package/dist/commands/claude/org/helpers.js.map +1 -1
- package/dist/commands/claude/org/index.d.ts.map +1 -1
- package/dist/commands/claude/org/index.js +24 -16
- package/dist/commands/claude/org/index.js.map +1 -1
- package/dist/commands/claude/org/skills.d.ts +428 -0
- package/dist/commands/claude/org/skills.d.ts.map +1 -1
- package/dist/commands/claude/org/skills.js +1189 -91
- package/dist/commands/claude/org/skills.js.map +1 -1
- package/dist/commands/claude/org/users.d.ts.map +1 -1
- package/dist/commands/claude/org/users.js +3 -1
- package/dist/commands/claude/org/users.js.map +1 -1
- package/dist/commands/claude/org/workspaces.d.ts.map +1 -1
- package/dist/commands/claude/org/workspaces.js +5 -2
- package/dist/commands/claude/org/workspaces.js.map +1 -1
- package/dist/commands/skill/review-checklist.d.ts.map +1 -1
- package/dist/commands/skill/review-checklist.js +35 -0
- package/dist/commands/skill/review-checklist.js.map +1 -1
- package/dist/commands/skill/test/configure.d.ts +37 -0
- package/dist/commands/skill/test/configure.d.ts.map +1 -1
- package/dist/commands/skill/test/configure.js +57 -12
- package/dist/commands/skill/test/configure.js.map +1 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +22 -6
- package/dist/utils/config-loader.js.map +1 -1
- package/package.json +15 -15
|
@@ -98,9 +98,64 @@ export function addPaginationOptions(cmd) {
|
|
|
98
98
|
.option('--after-id <id>', 'Cursor for pagination')
|
|
99
99
|
.option('--debug', 'Enable debug logging');
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* The exit code for a run that COMPLETED and reported failures.
|
|
103
|
+
*
|
|
104
|
+
* Read against the contract every command's `--help` publishes — `0` no
|
|
105
|
+
* error-severity findings, `1` at least one, `2` a system error — this is `1`:
|
|
106
|
+
* the command ran, produced its document, and that document reports something
|
|
107
|
+
* that went wrong. `2` stays for the run that could not happen at all (no
|
|
108
|
+
* credential, no such source), which is what {@link handleCommandError} ends on.
|
|
109
|
+
*
|
|
110
|
+
* 🔑 It exists because a batch command has an ending the old code could not
|
|
111
|
+
* express. `skills install --from-npm` catches each per-skill upload failure and
|
|
112
|
+
* returns normally, so a run in which all three skills were rejected wrote
|
|
113
|
+
* `status: success` beside `skillsFailed: 3` and exited 0 — and a CI wrapper
|
|
114
|
+
* spelled `vat claude org skills install --from-npm … || fail` published nothing
|
|
115
|
+
* and reported green.
|
|
116
|
+
*/
|
|
117
|
+
export const ORG_RUN_FAILED_EXIT_CODE = 1;
|
|
118
|
+
/** Tag `document` as the report of a run that failed. */
|
|
119
|
+
export function orgCommandFailure(document) {
|
|
120
|
+
return { orgCommandFailed: true, document };
|
|
121
|
+
}
|
|
122
|
+
function isOrgCommandFailure(result) {
|
|
123
|
+
return result.orgCommandFailed === true;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Pure: the document and exit code an org command's result ends on.
|
|
127
|
+
*
|
|
128
|
+
* Split out of {@link executeOrgCommand} because it is the whole of the
|
|
129
|
+
* status/exit-code decision and the only part of it that is testable without
|
|
130
|
+
* spawning a process — `executeOrgCommand` itself ends in `process.exit`.
|
|
131
|
+
*/
|
|
132
|
+
export function buildOrgCommandEnding(result, durationMs) {
|
|
133
|
+
const failed = isOrgCommandFailure(result);
|
|
134
|
+
const payload = (failed ? result.document : result);
|
|
135
|
+
return {
|
|
136
|
+
document: {
|
|
137
|
+
status: failed ? 'error' : 'success',
|
|
138
|
+
...payload,
|
|
139
|
+
duration: `${String(durationMs)}ms`,
|
|
140
|
+
},
|
|
141
|
+
exitCode: failed ? ORG_RUN_FAILED_EXIT_CODE : 0,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
101
144
|
/**
|
|
102
145
|
* Execute an org command with standard error handling.
|
|
103
146
|
* Sets up client, logger, timer, and catches errors uniformly.
|
|
147
|
+
*
|
|
148
|
+
* An action may return its document plainly (success, exit 0) or wrapped in
|
|
149
|
+
* {@link orgCommandFailure} (the document is still published, the run exits
|
|
150
|
+
* {@link ORG_RUN_FAILED_EXIT_CODE}). Anything thrown is the system error and
|
|
151
|
+
* ends on {@link handleCommandError}'s exit 2.
|
|
152
|
+
*
|
|
153
|
+
* 🔑 Usage guards belong INSIDE the action, not in the Commander action that
|
|
154
|
+
* calls this. `bin.ts` runs the synchronous `program.parse()`, so a throw from
|
|
155
|
+
* an async action handler is a floating rejection that reaches no catch: Node
|
|
156
|
+
* prints a raw stack trace carrying absolute `$HOME` paths, writes nothing to
|
|
157
|
+
* stdout, and exits 1 — which this CLI's contract reads as "at least one
|
|
158
|
+
* error-severity finding" for a run in which nothing executed.
|
|
104
159
|
*/
|
|
105
160
|
export async function executeOrgCommand(commandName, debug, action) {
|
|
106
161
|
const logger = createLogger(debug ? { debug: true } : {});
|
|
@@ -108,13 +163,9 @@ export async function executeOrgCommand(commandName, debug, action) {
|
|
|
108
163
|
try {
|
|
109
164
|
const client = createOrgApiClientFromEnv();
|
|
110
165
|
const ctx = { client, logger, startTime };
|
|
111
|
-
const
|
|
112
|
-
writeYamlOutput(
|
|
113
|
-
|
|
114
|
-
...result,
|
|
115
|
-
duration: `${String(Date.now() - startTime)}ms`,
|
|
116
|
-
});
|
|
117
|
-
process.exit(0);
|
|
166
|
+
const ending = buildOrgCommandEnding(await action(ctx), Date.now() - startTime);
|
|
167
|
+
writeYamlOutput(ending.document);
|
|
168
|
+
process.exit(ending.exitCode);
|
|
118
169
|
}
|
|
119
170
|
catch (error) {
|
|
120
171
|
handleCommandError(error, logger, startTime, commandName);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../../src/commands/claude/org/helpers.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../../src/commands/claude/org/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/org/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,gBAAgB,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/org/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,wBAAgB,gBAAgB,IAAI,OAAO,CAsD1C"}
|
|
@@ -18,29 +18,37 @@ import { createOrgWorkspacesCommand } from './workspaces.js';
|
|
|
18
18
|
export function createOrgCommand() {
|
|
19
19
|
const command = new Command('org');
|
|
20
20
|
command
|
|
21
|
-
.description('Manage your Anthropic organization (Admin API)')
|
|
21
|
+
.description('Manage your Anthropic organization (Admin API) and workspace skills (Skills API)')
|
|
22
22
|
.helpCommand(false)
|
|
23
23
|
.addHelpText('after', `
|
|
24
24
|
Description:
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
Skills commands also require ANTHROPIC_API_KEY.
|
|
25
|
+
Two surfaces under one group: organization administration via the Anthropic
|
|
26
|
+
Admin API, and workspace skills via the Skills API.
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
Each takes its OWN key, and never the other one. Set the key for the commands
|
|
29
|
+
you are running; neither family needs both.
|
|
30
|
+
|
|
31
|
+
Commands and the key each requires:
|
|
32
|
+
ANTHROPIC_ADMIN_API_KEY (sk-ant-admin-...)
|
|
33
|
+
info Show organization details
|
|
34
|
+
users Manage users (list, get, update, remove)
|
|
35
|
+
invites Manage invites (list, create, delete)
|
|
36
|
+
workspaces Manage workspaces and members
|
|
37
|
+
api-keys Manage API keys (list, update)
|
|
38
|
+
usage Fetch daily token usage report
|
|
39
|
+
cost Fetch USD cost report
|
|
40
|
+
code-analytics Fetch Claude Code metrics
|
|
41
|
+
|
|
42
|
+
ANTHROPIC_API_KEY (a regular workspace key, sk-ant-api03-...)
|
|
43
|
+
skills Manage workspace skills — upload, list, version, delete.
|
|
44
|
+
The admin key is never sent to these endpoints and is not
|
|
45
|
+
needed to run them.
|
|
39
46
|
|
|
40
47
|
Exit Codes:
|
|
41
48
|
0 - Success
|
|
42
|
-
1 -
|
|
43
|
-
|
|
49
|
+
1 - The run happened and the outcome was not clean (e.g. skills install
|
|
50
|
+
--from-npm uploaded some skills and failed others), or a stub command
|
|
51
|
+
2 - The run could not happen: missing key, API failure, unusable input
|
|
44
52
|
|
|
45
53
|
Example:
|
|
46
54
|
$ export ANTHROPIC_ADMIN_API_KEY=sk-ant-admin-...
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/commands/claude/org/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE7D,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IAEnC,OAAO;SACJ,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/commands/claude/org/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAE7D,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IAEnC,OAAO;SACJ,WAAW,CAAC,kFAAkF,CAAC;SAC/F,WAAW,CAAC,KAAK,CAAC;SAClB,WAAW,CAAC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCzB,CAAC,CAAC;IAED,OAAO,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,UAAU,CAAC,0BAA0B,EAAE,CAAC,CAAC;IACjD,OAAO,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC,CAAC;IAC9C,OAAO,CAAC,UAAU,CAAC,qBAAqB,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,UAAU,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,UAAU,CAAC,6BAA6B,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,UAAU,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAE7C,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -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":"
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../../../src/commands/claude/org/skills.ts"],"names":[],"mappings":"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"}
|