@typeship-ax/cli 0.23.1 → 0.24.0
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/AGENTS.md +2 -2
- package/README.md +2 -2
- package/api.md +2 -2
- package/dist/arguments.d.ts +9 -2
- package/dist/arguments.d.ts.map +1 -1
- package/dist/arguments.js +17 -6
- package/dist/cli-agent.d.ts +42 -1
- package/dist/cli-agent.d.ts.map +1 -1
- package/dist/cli-agent.js +187 -18
- package/dist/cli.js +341 -76
- package/dist/fields.d.ts +8 -1
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +91 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/ops.d.ts +5 -0
- package/dist/ops.d.ts.map +1 -1
- package/dist/ops.js +66 -6
- package/dist/resources/deliveries.d.ts +1 -1
- package/dist/resources/deliveries.d.ts.map +1 -1
- package/dist/resources/deliveries.js +1 -1
- package/dist/resources/drafts.d.ts +1 -1
- package/dist/resources/drafts.d.ts.map +1 -1
- package/dist/resources/drafts.js +1 -1
- package/dist/resources/generations.d.ts +2 -2
- package/dist/resources/generations.d.ts.map +1 -1
- package/dist/resources/generations.js +2 -2
- package/dist/resources/releases.d.ts +1 -1
- package/dist/resources/releases.d.ts.map +1 -1
- package/dist/resources/releases.js +1 -1
- package/dist/resources/spec-revisions.d.ts +1 -1
- package/dist/resources/spec-revisions.d.ts.map +1 -1
- package/dist/resources/spec-revisions.js +1 -1
- package/dist/resources/targets.d.ts +1 -1
- package/dist/resources/targets.d.ts.map +1 -1
- package/dist/resources/targets.js +1 -1
- package/dist/table.d.ts +28 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +167 -0
- package/dist/type-docs.d.ts +61 -0
- package/dist/type-docs.d.ts.map +1 -0
- package/dist/type-docs.js +174 -0
- package/package.json +1 -1
- package/src/arguments.ts +19 -7
- package/src/cli-agent.ts +196 -17
- package/src/cli.ts +330 -76
- package/src/fields.ts +81 -5
- package/src/index.ts +3 -3
- package/src/ops.ts +69 -6
- package/src/resources/deliveries.ts +2 -2
- package/src/resources/drafts.ts +2 -2
- package/src/resources/generations.ts +4 -4
- package/src/resources/releases.ts +2 -2
- package/src/resources/spec-revisions.ts +2 -2
- package/src/resources/targets.ts +2 -2
- package/src/table.ts +167 -0
- package/src/type-docs.ts +205 -0
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Typeship: agent guide
|
|
2
2
|
|
|
3
|
-
Instructions for coding agents that call the Typeship API through this CLI (API version 1.0.0, package version 0.
|
|
3
|
+
Instructions for coding agents that call the Typeship API through this CLI (API version 1.0.0, package version 0.24.0).
|
|
4
4
|
|
|
5
5
|
Resolve an OpenAPI or GraphQL Spec, diagnose it, and keep every
|
|
6
6
|
selected CLI, MCP, and SDK Target current.
|
|
@@ -27,7 +27,7 @@ petstore Spec is a runnable sample.
|
|
|
27
27
|
## Using the CLI
|
|
28
28
|
- `typeship <resource> <command>` calls an API operation; `typeship docs search <term> --json` finds operations and guides as structured data; `typeship docs <resource> <command>` gives a concise contract and example (add `--schema` for full schemas or `--json` for the machine contract).
|
|
29
29
|
- Path parameters are positional; other inputs are flags. JSON goes to stdout and exit codes are 0/1/2. Errors are one JSON envelope on stderr: `{status, issues: [{code, message}], next_steps, detail}`; branch on `issues[].code`. Every operation classified as destructive requires `--force` (or `--yes`).
|
|
30
|
-
- `typeship agent-guide --format json` explains the conventions; `typeship help --json`
|
|
30
|
+
- `typeship agent-guide --format json` explains the conventions; `typeship help --json` indexes the commands and `typeship help <resource> <command> --json` gives one command's flags; `typeship doctor` checks the setup. Read `typeship init --help` before setup: it can store credentials and update agent instructions. Choose the scope the task requires.
|
|
31
31
|
|
|
32
32
|
## Safety
|
|
33
33
|
- Read credentials from the environment or a secret store. Never hard-code them, print them, or put them in URLs or command arguments.
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Resolve an OpenAPI or GraphQL Spec, diagnose it, and keep every selected CLI, MC
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
9
|
```sh
|
|
10
|
-
npm install --global @typeship-ax/cli@0.
|
|
10
|
+
npm install --global @typeship-ax/cli@0.24.0
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Requires Node.js 20+.
|
|
@@ -20,7 +20,7 @@ The package ships `typeship`, a command for every API operation. API commands wr
|
|
|
20
20
|
typeship login # stores a credential (or set TYPESHIP_TOKEN)
|
|
21
21
|
typeship organization get
|
|
22
22
|
typeship projects list --all # every page, one item per line
|
|
23
|
-
typeship help --json # command names
|
|
23
|
+
typeship help --json # resources and command names; help <resource> <command> --json adds flags
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
CLI conventions:
|
package/api.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Typeship — CLI reference
|
|
2
2
|
|
|
3
|
-
API version 1.0.0. Package version 0.
|
|
3
|
+
API version 1.0.0. Package version 0.24.0. Generated by Typeship.
|
|
4
4
|
|
|
5
|
-
Run `typeship help --json` for the command index. Path arguments are positional; flags use the names shown below. Arrays accept repeated flags, comma-separated values, or a JSON array; object values use JSON.
|
|
5
|
+
Run `typeship help --json` for the command index, and `typeship help <resource> <command> --json` for one command's flags. Path arguments are positional; flags use the names shown below. Arrays accept repeated flags, comma-separated values, or a JSON array; object values use JSON.
|
|
6
6
|
|
|
7
7
|
API commands write JSON to stdout. Exit codes: `0` success, `1` request failure, `2` invalid usage. In agent mode, errors are JSON on stderr with `status`, `issues`, and `next_steps`; branch on `issues[].code`. Destructive operations require `--force` without an interactive terminal.
|
|
8
8
|
|
package/dist/arguments.d.ts
CHANGED
|
@@ -39,9 +39,16 @@ export declare function coerceValue(value: unknown, schema: Record<string, unkno
|
|
|
39
39
|
export declare function checkValue(value: unknown, schema: Record<string, unknown>, path: string, issues: ArgumentIssue[], options?: {
|
|
40
40
|
skipPattern?: boolean;
|
|
41
41
|
depth?: number;
|
|
42
|
+
meName?: string;
|
|
42
43
|
}): unknown;
|
|
44
|
+
/** A name that holds one user or a list of them: assignee, assigneeId,
|
|
45
|
+
* assignees, subscriberIds, owner, user_id. */
|
|
43
46
|
export declare function userShapedReference(name: string): boolean;
|
|
44
|
-
/** "me" given for a user-shaped argument or property, resolved
|
|
45
|
-
*
|
|
47
|
+
/** "me" given for a user-shaped argument or property, resolved through the
|
|
48
|
+
* identity tool. */
|
|
46
49
|
export declare function isMeReference(name: string, value: string): boolean;
|
|
50
|
+
/** What "me" becomes for a user-shaped name: the caller's id for an ID
|
|
51
|
+
* name (assigneeId, subscriberIds, user_id), otherwise their login
|
|
52
|
+
* (GitHub's owner and assignees take logins). */
|
|
53
|
+
export declare function meIdentityField(name: string): "id" | "login";
|
|
47
54
|
//# sourceMappingURL=arguments.d.ts.map
|
package/dist/arguments.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MAAsD,CAAC;AAgBpG;kEACkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAU7E;AASD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAInH;AAgFD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,
|
|
1
|
+
{"version":3,"file":"arguments.d.ts","sourceRoot":"","sources":["../src/arguments.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,kBAAkB,CAAC;IACnE,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MAAsD,CAAC;AAgBpG;kEACkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAU7E;AASD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAInH;AAgFD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GACvE,OAAO,CAyET;AAED;+CAC+C;AAC/C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED;oBACoB;AACpB,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAElE;AAED;;iDAEiD;AACjD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAE5D"}
|
package/dist/arguments.js
CHANGED
|
@@ -181,7 +181,10 @@ export function checkValue(value, schema, path, issues, options = {}) {
|
|
|
181
181
|
let out = shallow.value;
|
|
182
182
|
if (depth >= MAX_CHECK_DEPTH)
|
|
183
183
|
return out;
|
|
184
|
-
|
|
184
|
+
// "me" for a user-shaped property (or an item of one) is resolved to an
|
|
185
|
+
// ID or login later, so it skips the pattern the resolved value must meet.
|
|
186
|
+
const skipPattern = options.skipPattern || (typeof out === "string" && options.meName !== undefined && isMeReference(options.meName, out));
|
|
187
|
+
if (typeof out === "string" && typeof schema.pattern === "string" && !skipPattern) {
|
|
185
188
|
let pattern;
|
|
186
189
|
try {
|
|
187
190
|
pattern = new RegExp(schema.pattern, "u");
|
|
@@ -199,7 +202,7 @@ export function checkValue(value, schema, path, issues, options = {}) {
|
|
|
199
202
|
// Array items: check each against the items schema when it has one.
|
|
200
203
|
if (Array.isArray(out) && schema.items && typeof schema.items === "object" && !Array.isArray(schema.items)) {
|
|
201
204
|
const itemSchema = schema.items;
|
|
202
|
-
out = out.map((item, i) => checkValue(item, itemSchema, path + "[" + i + "]", issues, { depth: depth + 1 }));
|
|
205
|
+
out = out.map((item, i) => checkValue(item, itemSchema, path + "[" + i + "]", issues, { depth: depth + 1, meName: options.meName }));
|
|
203
206
|
}
|
|
204
207
|
// Object properties: the same checks one level down, keyed by dotted path.
|
|
205
208
|
if (out && typeof out === "object" && !Array.isArray(out) && schema.properties && typeof schema.properties === "object") {
|
|
@@ -230,7 +233,7 @@ export function checkValue(value, schema, path, issues, options = {}) {
|
|
|
230
233
|
}
|
|
231
234
|
const propSchema = properties[name];
|
|
232
235
|
next[name] = propSchema && typeof propSchema === "object"
|
|
233
|
-
? checkValue(entry, propSchema, child(name), issues, { depth: depth + 1,
|
|
236
|
+
? checkValue(entry, propSchema, child(name), issues, { depth: depth + 1, meName: name })
|
|
234
237
|
: entry;
|
|
235
238
|
}
|
|
236
239
|
for (const name of Array.isArray(schema.required) ? schema.required : []) {
|
|
@@ -243,12 +246,20 @@ export function checkValue(value, schema, path, issues, options = {}) {
|
|
|
243
246
|
}
|
|
244
247
|
return out;
|
|
245
248
|
}
|
|
249
|
+
/** A name that holds one user or a list of them: assignee, assigneeId,
|
|
250
|
+
* assignees, subscriberIds, owner, user_id. */
|
|
246
251
|
export function userShapedReference(name) {
|
|
247
|
-
const normalized = name.toLowerCase().replace(/[^a-z0-9]/g, "").replace(/ids?$/, "");
|
|
252
|
+
const normalized = name.toLowerCase().replace(/[^a-z0-9]/g, "").replace(/ids?$/, "").replace(/s$/, "");
|
|
248
253
|
return ["user", "assignee", "owner", "member", "actor", "creator", "account", "profile", "subscriber"].includes(normalized);
|
|
249
254
|
}
|
|
250
|
-
/** "me" given for a user-shaped argument or property, resolved
|
|
251
|
-
*
|
|
255
|
+
/** "me" given for a user-shaped argument or property, resolved through the
|
|
256
|
+
* identity tool. */
|
|
252
257
|
export function isMeReference(name, value) {
|
|
253
258
|
return value.trim().toLowerCase() === "me" && userShapedReference(name);
|
|
254
259
|
}
|
|
260
|
+
/** What "me" becomes for a user-shaped name: the caller's id for an ID
|
|
261
|
+
* name (assigneeId, subscriberIds, user_id), otherwise their login
|
|
262
|
+
* (GitHub's owner and assignees take logins). */
|
|
263
|
+
export function meIdentityField(name) {
|
|
264
|
+
return /ids?$/i.test(name.replace(/[^A-Za-z0-9]/g, "")) ? "id" : "login";
|
|
265
|
+
}
|
package/dist/cli-agent.d.ts
CHANGED
|
@@ -165,10 +165,18 @@ export interface AgentContext {
|
|
|
165
165
|
hasMcp: boolean;
|
|
166
166
|
builtins: string[];
|
|
167
167
|
}
|
|
168
|
-
/** One line per command, pipe-delimited: the compact index that goes into AGENTS.md. */
|
|
169
168
|
/** string, number, usd|eur, string[], usd|eur[], object, json — the type as a reader expects it. */
|
|
170
169
|
export declare function flagTypeLabel(f: CommandFlagSummary): string;
|
|
170
|
+
/** One line per command, pipe-delimited: the compact index that goes into AGENTS.md. */
|
|
171
171
|
export declare function compactIndex(commands: CommandSummary[]): string;
|
|
172
|
+
/** Bytes of command index the guide and AGENTS.md carry before they switch to one line per resource. */
|
|
173
|
+
export declare const COMMAND_INDEX_BUDGET = 8000;
|
|
174
|
+
/**
|
|
175
|
+
* One line per resource with its first command names, for an API whose
|
|
176
|
+
* per-command index would not fit COMMAND_INDEX_BUDGET. Resources past the
|
|
177
|
+
* budget are counted, not listed; help --json has them all.
|
|
178
|
+
*/
|
|
179
|
+
export declare function resourceIndex(bin: string, commands: CommandSummary[]): string;
|
|
172
180
|
/** The AGENTS.md block body. */
|
|
173
181
|
export declare function agentBlock(ctx: AgentContext, commands: CommandSummary[]): string;
|
|
174
182
|
/** What `agent-guide --format json` returns. */
|
|
@@ -232,4 +240,37 @@ export declare function summarizeDoctor(checks: DoctorCheck[]): {
|
|
|
232
240
|
};
|
|
233
241
|
/** Every OAuth scope an operation's security requirements name, in order. */
|
|
234
242
|
export declare function requiredScopes(security: Record<string, string[]>[] | undefined): string[];
|
|
243
|
+
/** What --dry-run prints: the request an API command would send, with
|
|
244
|
+
* every credential replaced by "<redacted>". Nothing in it was sent. */
|
|
245
|
+
export interface RequestPreview {
|
|
246
|
+
dry_run: true;
|
|
247
|
+
sent: false;
|
|
248
|
+
message: string;
|
|
249
|
+
request: {
|
|
250
|
+
method: string;
|
|
251
|
+
url: string;
|
|
252
|
+
path: string;
|
|
253
|
+
query: Record<string, string | string[]>;
|
|
254
|
+
headers: Record<string, string>;
|
|
255
|
+
body?: unknown;
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
export declare const REDACTED = "<redacted>";
|
|
259
|
+
/**
|
|
260
|
+
* The request a dry run captured, as --dry-run shows it. `sensitiveNames`
|
|
261
|
+
* are the header and query names the API's security schemes bind; `secrets`
|
|
262
|
+
* are the resolved credential values, redacted wherever they appear (a
|
|
263
|
+
* token pasted into a body field, a key in a URL).
|
|
264
|
+
*/
|
|
265
|
+
export declare function requestPreview(input: {
|
|
266
|
+
method: string;
|
|
267
|
+
url: string;
|
|
268
|
+
headers: Record<string, string>;
|
|
269
|
+
body?: unknown;
|
|
270
|
+
}, options?: {
|
|
271
|
+
sensitiveNames?: string[];
|
|
272
|
+
secrets?: string[];
|
|
273
|
+
}): Promise<RequestPreview>;
|
|
274
|
+
/** --dry-run for a person: the request line, then query, headers and body. */
|
|
275
|
+
export declare function formatRequestPreview(preview: RequestPreview): string;
|
|
235
276
|
//# sourceMappingURL=cli-agent.d.ts.map
|
package/dist/cli-agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-agent.d.ts","sourceRoot":"","sources":["../src/cli-agent.ts"],"names":[],"mappings":"AAgBA;;;GAGG;AACH,MAAM,MAAM,SAAS,GACjB,SAAS,GACT,cAAc,GACd,oBAAoB,GACpB,YAAY,GACZ,WAAW,GACX,iBAAiB,GACjB,cAAc,GACd,cAAc,GACd,cAAc,GACd,eAAe,GACf,mBAAmB,GACnB,cAAc,GACd,cAAc,GACd,gBAAgB,GAChB,8BAA8B,GAC9B,uBAAuB,GACvB,eAAe,GACf,iBAAiB,GACjB,cAAc,GACd,kBAAkB,GAClB,kBAAkB,GAClB,aAAa,CAAC;AAElB,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,qGAAqG;IACrG,MAAM,EAAE,OAAO,GAAG,iBAAiB,CAAC;IACpC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,QAAQ,CAQvD;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,IAAI,EAAE,SAAS,GAAG,CAAC,GAAG,CAAC,CAalD;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GACzI,aAAa,
|
|
1
|
+
{"version":3,"file":"cli-agent.d.ts","sourceRoot":"","sources":["../src/cli-agent.ts"],"names":[],"mappings":"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"}
|
package/dist/cli-agent.js
CHANGED
|
@@ -69,7 +69,9 @@ export function classifyApiError(error, context) {
|
|
|
69
69
|
? e.body.request_id ?? e.body.requestId
|
|
70
70
|
: undefined;
|
|
71
71
|
const requestId = e.response?.requestId ?? (typeof bodyRequestId === "string" ? bodyRequestId : undefined);
|
|
72
|
-
|
|
72
|
+
// An in-band GraphQL error keeps the vendor's code next to the normalized one.
|
|
73
|
+
const vendorCode = e.name === "GraphQLRequestError" ? graphqlVendorCode(error) : undefined;
|
|
74
|
+
const detail = { status, ...(e.name ? { error: e.name } : {}), ...(vendorCode ? { vendor_code: vendorCode } : {}), ...(requestId ? { request_id: requestId } : {}), ...(e.body !== undefined ? { body: e.body } : {}) };
|
|
73
75
|
const same = apiMessage !== undefined && (apiMessage.toLowerCase() === base.toLowerCase() || base.toLowerCase().includes(apiMessage.toLowerCase()) || apiMessage.toLowerCase().includes(base.toLowerCase()));
|
|
74
76
|
const message = apiMessage === undefined ? base : same ? apiMessage : apiMessage + " (" + base + ")";
|
|
75
77
|
const upgradeUrl = extractUrl(e.body, ["upgrade_url", "upgradeUrl", "signup_url", "claim_url"]);
|
|
@@ -93,15 +95,25 @@ export function classifyApiError(error, context) {
|
|
|
93
95
|
return { status: "action_required", code: "RATE_LIMITED", message, detail, nextSteps: ["Wait, then run the same command again."] };
|
|
94
96
|
return { code: "CALL_FAILED", message, detail, nextSteps: ["The API reported a failure in a successful response; detail.body says why."] };
|
|
95
97
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
const unauthenticated = () => context.hadCredential
|
|
99
|
+
? { code: "AUTH_INVALID", message, detail, nextSteps: ["The credential was rejected. Check it is current: '" + context.bin + " auth check', then '" + context.bin + " login --help' to store a new one."] }
|
|
100
|
+
: { status: "action_required", code: "NO_AUTH", message, detail, nextSteps: ["No credential was sent. Set the auth env var, pass --token, or run '" + context.bin + " login'.", "'" + context.bin + " auth check' shows what the CLI would send."] };
|
|
101
|
+
const forbidden = () => scopes.length ? scopeFailure() : { code: "AUTH_INVALID", message, detail, nextSteps: ["The credential lacks access to this operation."] };
|
|
102
|
+
// An in-band GraphQL error (HTTP 200): classified by the vendor's code.
|
|
103
|
+
if (e.name === "GraphQLRequestError") {
|
|
104
|
+
switch (vendorCode === undefined ? undefined : graphqlErrorClass(vendorCode)) {
|
|
105
|
+
case "not_found": return { code: "NOT_FOUND", message, detail, nextSteps: ["Check the id in the arguments; list the resource first to find the right one."] };
|
|
106
|
+
case "unauthenticated": return unauthenticated();
|
|
107
|
+
case "forbidden": return forbidden();
|
|
108
|
+
case "bad_input": return { code: "INVALID_REQUEST", message, detail, nextSteps: ["The API rejected an argument or the selection; the errors in detail.body name it (message, path). Fix that and run the command again."] };
|
|
109
|
+
case "rate_limited": return { status: "action_required", code: "RATE_LIMITED", message, detail, nextSteps: [rateLimitNextStep(undefined, "run the same command again")] };
|
|
110
|
+
default: return { code: "CALL_FAILED", message, detail };
|
|
111
|
+
}
|
|
100
112
|
}
|
|
101
|
-
if (status ===
|
|
102
|
-
return
|
|
113
|
+
if (status === 401)
|
|
114
|
+
return unauthenticated();
|
|
103
115
|
if (status === 403)
|
|
104
|
-
return
|
|
116
|
+
return forbidden();
|
|
105
117
|
if (status === 402) {
|
|
106
118
|
return { status: "action_required", code: "PLAN_LIMIT", message, detail, nextSteps: [upgradeUrl ? "Lift the limit at " + upgradeUrl + ", then run the same command again." : "The account's plan stops here; upgrade it, then run the same command again.", "Do not retry the same call as is."] };
|
|
107
119
|
}
|
|
@@ -187,6 +199,31 @@ export function rateLimitNextStep(retryAt, then) {
|
|
|
187
199
|
? "Rate limited: wait until " + isoSeconds(retryAt) + ", then " + then + "."
|
|
188
200
|
: "Rate limited: back off, then " + then + "; the SDK already honored any Retry-After within its ceiling.";
|
|
189
201
|
}
|
|
202
|
+
/** The vendor's own code on an in-band GraphQL error: the first error's
|
|
203
|
+
* extensions.code, or its type (GitHub). */
|
|
204
|
+
function graphqlVendorCode(error) {
|
|
205
|
+
const first = error?.errors?.[0];
|
|
206
|
+
const code = first?.extensions?.code ?? first?.type;
|
|
207
|
+
return typeof code === "string" && code !== "" ? code : undefined;
|
|
208
|
+
}
|
|
209
|
+
/** GraphQL error codes whose meaning is settled (Apollo's standard codes,
|
|
210
|
+
* GitHub's types, Linear's codes), by recovery class. Any other code is
|
|
211
|
+
* passed through as is, with no guessed next step. The MCP server's
|
|
212
|
+
* classification uses the same table. */
|
|
213
|
+
function graphqlErrorClass(code) {
|
|
214
|
+
const c = code.toUpperCase();
|
|
215
|
+
if (c === "NOT_FOUND")
|
|
216
|
+
return "not_found";
|
|
217
|
+
if (c === "UNAUTHENTICATED" || c === "AUTHENTICATION_ERROR")
|
|
218
|
+
return "unauthenticated";
|
|
219
|
+
if (c === "FORBIDDEN")
|
|
220
|
+
return "forbidden";
|
|
221
|
+
if (c === "BAD_USER_INPUT" || c === "GRAPHQL_VALIDATION_FAILED" || c === "GRAPHQL_PARSE_FAILED" || c === "INPUT_ERROR")
|
|
222
|
+
return "bad_input";
|
|
223
|
+
if (c === "RATE_LIMITED" || c === "RATELIMITED")
|
|
224
|
+
return "rate_limited";
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
190
227
|
/** Error codes APIs report inside a 2xx body (Slack's `error`), mapped to
|
|
191
228
|
* the stable codes when their meaning is unambiguous. */
|
|
192
229
|
export function payloadFailureCode(code) {
|
|
@@ -458,7 +495,6 @@ export function agentInstructionsFile(cwd) {
|
|
|
458
495
|
return claude;
|
|
459
496
|
return agents;
|
|
460
497
|
}
|
|
461
|
-
/** One line per command, pipe-delimited: the compact index that goes into AGENTS.md. */
|
|
462
498
|
/** string, number, usd|eur, string[], usd|eur[], object, json — the type as a reader expects it. */
|
|
463
499
|
export function flagTypeLabel(f) {
|
|
464
500
|
const inline = (values) => values && values.join("|").length <= 24 ? values.join("|") : values ? "enum" : undefined;
|
|
@@ -466,6 +502,7 @@ export function flagTypeLabel(f) {
|
|
|
466
502
|
return (inline(f.items?.enum) ?? f.items?.type ?? "json") + "[]";
|
|
467
503
|
return inline(f.enum) ?? f.type;
|
|
468
504
|
}
|
|
505
|
+
/** One line per command, pipe-delimited: the compact index that goes into AGENTS.md. */
|
|
469
506
|
export function compactIndex(commands) {
|
|
470
507
|
return commands
|
|
471
508
|
.map((c) => {
|
|
@@ -474,10 +511,39 @@ export function compactIndex(commands) {
|
|
|
474
511
|
})
|
|
475
512
|
.join("\n");
|
|
476
513
|
}
|
|
514
|
+
/** Bytes of command index the guide and AGENTS.md carry before they switch to one line per resource. */
|
|
515
|
+
export const COMMAND_INDEX_BUDGET = 8_000;
|
|
516
|
+
const RESOURCE_INDEX_NAMES = 12;
|
|
517
|
+
/**
|
|
518
|
+
* One line per resource with its first command names, for an API whose
|
|
519
|
+
* per-command index would not fit COMMAND_INDEX_BUDGET. Resources past the
|
|
520
|
+
* budget are counted, not listed; help --json has them all.
|
|
521
|
+
*/
|
|
522
|
+
export function resourceIndex(bin, commands) {
|
|
523
|
+
const byResource = new Map();
|
|
524
|
+
for (const c of commands)
|
|
525
|
+
byResource.set(c.resource, [...(byResource.get(c.resource) ?? []), c.command]);
|
|
526
|
+
const lines = [];
|
|
527
|
+
let bytes = 0;
|
|
528
|
+
let listed = 0;
|
|
529
|
+
for (const [resource, names] of byResource) {
|
|
530
|
+
const more = names.length - RESOURCE_INDEX_NAMES;
|
|
531
|
+
const line = resource + ": " + names.slice(0, RESOURCE_INDEX_NAMES).join(", ") + (more > 0 ? ", … +" + more + " more" : "");
|
|
532
|
+
if (bytes + line.length + 1 > COMMAND_INDEX_BUDGET)
|
|
533
|
+
break;
|
|
534
|
+
lines.push(line);
|
|
535
|
+
bytes += line.length + 1;
|
|
536
|
+
listed++;
|
|
537
|
+
}
|
|
538
|
+
if (listed < byResource.size)
|
|
539
|
+
lines.push("… " + (byResource.size - listed) + " more resources: " + bin + " help --json");
|
|
540
|
+
return lines.join("\n");
|
|
541
|
+
}
|
|
477
542
|
/** The AGENTS.md block body. */
|
|
478
543
|
export function agentBlock(ctx, commands) {
|
|
479
544
|
const auth = ctx.authEnvVars.length ? ctx.authEnvVars.join(", ") : "(none)";
|
|
480
|
-
const
|
|
545
|
+
const docsIndex = ctx.docsIndexUrl ?? (ctx.docsUrl ? ctx.docsUrl.replace(/\/+$/, "") + "/llms.txt" : null);
|
|
546
|
+
const index = compactIndex(commands);
|
|
481
547
|
return [
|
|
482
548
|
"## " + ctx.bin + " CLI (" + ctx.apiTitle + ")",
|
|
483
549
|
"",
|
|
@@ -487,16 +553,14 @@ export function agentBlock(ctx, commands) {
|
|
|
487
553
|
ctx.authNotDeclared
|
|
488
554
|
? "- Auth: not declared by the API Spec. If the API needs a token, set " + auth + " or run `" + ctx.bin + " login`; other headers go in `--header \"Name: value\"` or " + ctx.envPrefix + "_HEADERS. Never write a key into a file in this repo."
|
|
489
555
|
: "- Auth: " + auth + " in the environment, or `" + ctx.bin + " login`. Never write a key into a file in this repo.",
|
|
490
|
-
"- Discover: `" + ctx.bin + " --help
|
|
491
|
-
"- Docs: " + (
|
|
556
|
+
"- Discover: `" + ctx.bin + " help --json` indexes resources and command names; `" + ctx.bin + " help <resource> --json` lists a resource's commands; `" + ctx.bin + " help <resource> <command> --json` gives one command's flags. `" + ctx.bin + " help --json --all` prints every command with every flag at once. Humans: `" + ctx.bin + " --help`, `" + ctx.bin + " <resource> <command> --help`.",
|
|
557
|
+
"- Docs: " + (docsIndex ? "`" + ctx.bin + " docs search <term> --json`; " + docsIndex : "`" + ctx.bin + " docs <resource> <command> --json` (a docs URL was not provided at generate time)") + ".",
|
|
492
558
|
"- Lists: `--all` streams every page as NDJSON. Destructive commands need `--force`.",
|
|
493
559
|
...(ctx.hasMcp ? ["- MCP: `" + ctx.bin + " mcp install --all` registers this API's MCP server with the agent clients on this machine" + (ctx.mcpUrl ? " (hosted: " + ctx.mcpUrl + ")" : "") + "."] : []),
|
|
494
560
|
"",
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
compactIndex(commands),
|
|
499
|
-
"```",
|
|
561
|
+
...(Buffer.byteLength(index) <= COMMAND_INDEX_BUDGET
|
|
562
|
+
? ["Commands (resource command | METHOD path | required flags | summary):", "", "```", index, "```"]
|
|
563
|
+
: ["Commands by resource (" + commands.length + " commands; `" + ctx.bin + " help <resource> --json` lists a resource's commands with summaries):", "", "```", resourceIndex(ctx.bin, commands), "```"]),
|
|
500
564
|
].join("\n");
|
|
501
565
|
}
|
|
502
566
|
/** What `agent-guide --format json` returns. */
|
|
@@ -533,12 +597,13 @@ export function agentGuide(ctx, commands) {
|
|
|
533
597
|
destructive: "Commands classified as destructive need --force (or --yes); without it they return CONFIRMATION_REQUIRED with the exact command to run.",
|
|
534
598
|
flags: "Positional path arguments first, then --flags. Array flags take a comma list, the flag repeated, or a JSON array; object flags take JSON. --data '<json>' merges under field flags (@<file> reads a file, - reads stdin).",
|
|
535
599
|
pagination: "Paginated commands return {items, hasMore, nextPage, nextCommand}: run nextCommand for the next page, or --all walks every page.",
|
|
600
|
+
discovery: "help --json is a bounded index of resources and command names. help <resource> --json pages through one resource's commands (next_command), help <resource> <command> --json is one command's flags, docs <resource> <command> --json its complete schemas, and docs search <term> --json finds commands by topic. help --json --all prints every command with every flag; on a large API it is large.",
|
|
536
601
|
},
|
|
537
602
|
builtins: ctx.builtins,
|
|
538
603
|
next_steps: [
|
|
539
604
|
...(ctx.authEnvVars.length ? ["Set " + ctx.authEnvVars[0] + " in the environment or run '" + ctx.bin + " login'."] : []),
|
|
540
605
|
"Run '" + ctx.bin + " auth check'.",
|
|
541
|
-
"Run '" + ctx.bin + " help --json' for the command index,
|
|
606
|
+
"Run '" + ctx.bin + " help --json' for the command index, then '" + ctx.bin + " help <resource> <command> --json' for the command you need.",
|
|
542
607
|
...(ctx.hasMcp ? ["Run '" + ctx.bin + " mcp install --all' if this session has an MCP-capable client."] : []),
|
|
543
608
|
],
|
|
544
609
|
};
|
|
@@ -662,3 +727,107 @@ export function summarizeDoctor(checks) {
|
|
|
662
727
|
export function requiredScopes(security) {
|
|
663
728
|
return [...new Set((security ?? []).flatMap((requirement) => Object.values(requirement).flat()))];
|
|
664
729
|
}
|
|
730
|
+
export const REDACTED = "<redacted>";
|
|
731
|
+
/** Header and query names that carry credentials, whatever the API calls
|
|
732
|
+
* them: Authorization, Cookie, X-Api-Key, api_key, access_token, a session
|
|
733
|
+
* or signature. */
|
|
734
|
+
const SENSITIVE_NAME = /^(authorization|proxy-authorization|cookie|cookie2|set-cookie)$|api[-_]?key|apikey|token|secret|password|passwd|session|signature|credential|^key$|^auth$/i;
|
|
735
|
+
function redactText(text, secrets) {
|
|
736
|
+
let out = text;
|
|
737
|
+
for (const secret of secrets)
|
|
738
|
+
if (secret.length >= 4)
|
|
739
|
+
out = out.split(secret).join(REDACTED);
|
|
740
|
+
return out;
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* The request a dry run captured, as --dry-run shows it. `sensitiveNames`
|
|
744
|
+
* are the header and query names the API's security schemes bind; `secrets`
|
|
745
|
+
* are the resolved credential values, redacted wherever they appear (a
|
|
746
|
+
* token pasted into a body field, a key in a URL).
|
|
747
|
+
*/
|
|
748
|
+
export async function requestPreview(input, options = {}) {
|
|
749
|
+
const secrets = [...new Set((options.secrets ?? []).filter((s) => typeof s === "string" && s.length >= 4))].sort((a, b) => b.length - a.length);
|
|
750
|
+
const named = new Set((options.sensitiveNames ?? []).map((n) => n.toLowerCase()));
|
|
751
|
+
const sensitive = (name) => named.has(name.toLowerCase()) || SENSITIVE_NAME.test(name);
|
|
752
|
+
const url = new URL(input.url);
|
|
753
|
+
const query = {};
|
|
754
|
+
for (const [name, raw] of url.searchParams) {
|
|
755
|
+
const value = sensitive(name) ? REDACTED : redactText(raw, secrets);
|
|
756
|
+
const previous = query[name];
|
|
757
|
+
query[name] = previous === undefined ? value : Array.isArray(previous) ? [...previous, value] : [previous, value];
|
|
758
|
+
}
|
|
759
|
+
const encodedSecrets = [...secrets, ...secrets.map(encodeURIComponent)];
|
|
760
|
+
const search = [...url.searchParams].map(([name, raw]) => encodeURIComponent(name) + "=" + (sensitive(name) ? REDACTED : redactText(encodeURIComponent(raw), encodedSecrets))).join("&");
|
|
761
|
+
const shownUrl = url.origin + redactText(url.pathname, encodedSecrets) + (search ? "?" + search : "");
|
|
762
|
+
const headers = {};
|
|
763
|
+
for (const [name, value] of Object.entries(input.headers)) {
|
|
764
|
+
headers[name] = sensitive(name) ? REDACTED : redactText(value, secrets);
|
|
765
|
+
}
|
|
766
|
+
const contentType = Object.entries(input.headers).find(([name]) => name.toLowerCase() === "content-type")?.[1] ?? "";
|
|
767
|
+
const body = await previewBody(input.body, contentType, secrets);
|
|
768
|
+
return {
|
|
769
|
+
dry_run: true,
|
|
770
|
+
sent: false,
|
|
771
|
+
message: "Dry run: nothing was sent to the API. This is the request the command would send, with credentials redacted.",
|
|
772
|
+
request: {
|
|
773
|
+
method: input.method,
|
|
774
|
+
url: shownUrl,
|
|
775
|
+
path: redactText(url.pathname, encodedSecrets),
|
|
776
|
+
query,
|
|
777
|
+
headers,
|
|
778
|
+
...(body !== undefined ? { body } : {}),
|
|
779
|
+
},
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
async function previewBody(body, contentType, secrets) {
|
|
783
|
+
if (body === undefined || body === null)
|
|
784
|
+
return undefined;
|
|
785
|
+
const redactValue = (value) => {
|
|
786
|
+
if (typeof value === "string")
|
|
787
|
+
return redactText(value, secrets);
|
|
788
|
+
if (Array.isArray(value))
|
|
789
|
+
return value.map(redactValue);
|
|
790
|
+
if (value && typeof value === "object")
|
|
791
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, SENSITIVE_NAME.test(k) && typeof v === "string" && secrets.some((s) => v.includes(s)) ? REDACTED : redactValue(v)]));
|
|
792
|
+
return value;
|
|
793
|
+
};
|
|
794
|
+
if (typeof body === "string") {
|
|
795
|
+
if (/json/i.test(contentType)) {
|
|
796
|
+
try {
|
|
797
|
+
return redactValue(JSON.parse(body));
|
|
798
|
+
}
|
|
799
|
+
catch { /* shown as text */ }
|
|
800
|
+
}
|
|
801
|
+
return redactText(body, secrets);
|
|
802
|
+
}
|
|
803
|
+
if (typeof FormData !== "undefined" && body instanceof FormData) {
|
|
804
|
+
const parts = [];
|
|
805
|
+
for (const [name, value] of body.entries()) {
|
|
806
|
+
parts.push(typeof value === "string"
|
|
807
|
+
? { name, value: redactText(value, secrets) }
|
|
808
|
+
: { name, filename: value.name, ...(value.type ? { type: value.type } : {}), bytes: value.size });
|
|
809
|
+
}
|
|
810
|
+
return { multipart: parts };
|
|
811
|
+
}
|
|
812
|
+
if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams)
|
|
813
|
+
return redactText(body.toString(), secrets);
|
|
814
|
+
if (typeof Blob !== "undefined" && body instanceof Blob)
|
|
815
|
+
return { binary: true, bytes: body.size, ...(body.type ? { type: body.type } : {}) };
|
|
816
|
+
if (body instanceof Uint8Array || body instanceof ArrayBuffer)
|
|
817
|
+
return { binary: true, bytes: body.byteLength };
|
|
818
|
+
return { stream: true };
|
|
819
|
+
}
|
|
820
|
+
/** --dry-run for a person: the request line, then query, headers and body. */
|
|
821
|
+
export function formatRequestPreview(preview) {
|
|
822
|
+
const { request } = preview;
|
|
823
|
+
const lines = ["Dry run: nothing was sent. Credentials are redacted.", "", request.method + " " + request.url];
|
|
824
|
+
const headers = Object.entries(request.headers);
|
|
825
|
+
if (headers.length)
|
|
826
|
+
lines.push("", "Headers:", ...headers.map(([name, value]) => " " + name + ": " + value));
|
|
827
|
+
if (request.body !== undefined) {
|
|
828
|
+
lines.push("", "Body:");
|
|
829
|
+
const text = typeof request.body === "string" ? request.body : JSON.stringify(request.body, null, 2);
|
|
830
|
+
lines.push(...text.split("\n").map((line) => " " + line));
|
|
831
|
+
}
|
|
832
|
+
return lines.join("\n") + "\n";
|
|
833
|
+
}
|