@typeship-ax/cli 0.6.0 → 0.9.1

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 (121) hide show
  1. package/AGENTS.md +31 -0
  2. package/README.md +26 -9
  3. package/api.json +6861 -3083
  4. package/api.md +508 -277
  5. package/dist/api-identity.d.ts +40 -0
  6. package/dist/api-identity.d.ts.map +1 -0
  7. package/dist/api-identity.js +128 -0
  8. package/dist/auth-profiles.d.ts +30 -0
  9. package/dist/auth-profiles.d.ts.map +1 -0
  10. package/dist/auth-profiles.js +138 -0
  11. package/dist/cli-agent.d.ts +9 -1
  12. package/dist/cli-agent.d.ts.map +1 -1
  13. package/dist/cli-agent.js +26 -9
  14. package/dist/cli.js +600 -582
  15. package/dist/console-login-check.d.ts +21 -0
  16. package/dist/console-login-check.d.ts.map +1 -0
  17. package/dist/console-login-check.js +107 -0
  18. package/dist/console-login-contract.d.ts +45 -0
  19. package/dist/console-login-contract.d.ts.map +1 -0
  20. package/dist/console-login-contract.js +40 -0
  21. package/dist/core/http.d.ts +21 -92
  22. package/dist/core/http.d.ts.map +1 -1
  23. package/dist/core/http.js +143 -221
  24. package/dist/core/pagination.d.ts.map +1 -1
  25. package/dist/core/pagination.js +6 -34
  26. package/dist/credential-storage.d.ts +24 -0
  27. package/dist/credential-storage.d.ts.map +1 -0
  28. package/dist/credential-storage.js +207 -0
  29. package/dist/dates.d.ts +0 -2
  30. package/dist/dates.d.ts.map +1 -1
  31. package/dist/dates.js +0 -1
  32. package/dist/docs.d.ts +36 -0
  33. package/dist/docs.d.ts.map +1 -0
  34. package/dist/docs.js +258 -0
  35. package/dist/errors.d.ts +42 -34
  36. package/dist/errors.d.ts.map +1 -1
  37. package/dist/errors.js +30 -20
  38. package/dist/index.d.ts +27 -12
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +40 -14
  41. package/dist/named-credentials.d.ts +21 -0
  42. package/dist/named-credentials.d.ts.map +1 -0
  43. package/dist/named-credentials.js +86 -0
  44. package/dist/oauth-login.d.ts +39 -0
  45. package/dist/oauth-login.d.ts.map +1 -0
  46. package/dist/oauth-login.js +171 -0
  47. package/dist/oauth-request.d.ts +21 -0
  48. package/dist/oauth-request.d.ts.map +1 -0
  49. package/dist/oauth-request.js +119 -0
  50. package/dist/oauth-session.d.ts +106 -0
  51. package/dist/oauth-session.d.ts.map +1 -0
  52. package/dist/oauth-session.js +244 -0
  53. package/dist/ops.d.ts +18 -0
  54. package/dist/ops.d.ts.map +1 -1
  55. package/dist/ops.js +31 -17
  56. package/dist/polling-login.d.ts +57 -0
  57. package/dist/polling-login.d.ts.map +1 -0
  58. package/dist/polling-login.js +204 -0
  59. package/dist/resources/account.d.ts +4 -4
  60. package/dist/resources/account.d.ts.map +1 -1
  61. package/dist/resources/account.js +1 -0
  62. package/dist/resources/api-keys.d.ts +13 -8
  63. package/dist/resources/api-keys.d.ts.map +1 -1
  64. package/dist/resources/api-keys.js +5 -1
  65. package/dist/resources/definition-revisions.d.ts +58 -0
  66. package/dist/resources/definition-revisions.d.ts.map +1 -0
  67. package/dist/resources/definition-revisions.js +114 -0
  68. package/dist/resources/definitions.d.ts +35 -0
  69. package/dist/resources/definitions.d.ts.map +1 -0
  70. package/dist/resources/definitions.js +60 -0
  71. package/dist/resources/generate.d.ts +18 -7
  72. package/dist/resources/generate.d.ts.map +1 -1
  73. package/dist/resources/generate.js +13 -5
  74. package/dist/resources/generations.d.ts +6 -6
  75. package/dist/resources/generations.d.ts.map +1 -1
  76. package/dist/resources/generations.js +3 -1
  77. package/dist/resources/projects.d.ts +111 -35
  78. package/dist/resources/projects.d.ts.map +1 -1
  79. package/dist/resources/projects.js +125 -15
  80. package/dist/resources/targets.d.ts +97 -0
  81. package/dist/resources/targets.d.ts.map +1 -0
  82. package/dist/resources/targets.js +197 -0
  83. package/dist/schemas.d.ts.map +1 -1
  84. package/dist/schemas.js +135 -62
  85. package/dist/types.d.ts +2072 -267
  86. package/dist/types.d.ts.map +1 -1
  87. package/dist/types.js +20 -3
  88. package/package.json +2 -1
  89. package/src/api-identity.ts +98 -0
  90. package/src/auth-profiles.ts +114 -0
  91. package/src/cli-agent.ts +28 -11
  92. package/src/cli.ts +528 -560
  93. package/src/console-login-check.ts +88 -0
  94. package/src/console-login-contract.ts +65 -0
  95. package/src/core/http.ts +156 -305
  96. package/src/core/pagination.ts +6 -30
  97. package/src/credential-storage.ts +183 -0
  98. package/src/dates.ts +0 -1
  99. package/src/docs.ts +239 -0
  100. package/src/errors.ts +52 -41
  101. package/src/index.ts +49 -14
  102. package/src/named-credentials.ts +74 -0
  103. package/src/oauth-login.ts +184 -0
  104. package/src/oauth-request.ts +90 -0
  105. package/src/oauth-session.ts +258 -0
  106. package/src/ops.ts +56 -17
  107. package/src/polling-login.ts +165 -0
  108. package/src/resources/account.ts +6 -3
  109. package/src/resources/api-keys.ts +27 -7
  110. package/src/resources/definition-revisions.ts +207 -0
  111. package/src/resources/definitions.ts +122 -0
  112. package/src/resources/generate.ts +29 -6
  113. package/src/resources/generations.ts +9 -4
  114. package/src/resources/projects.ts +274 -41
  115. package/src/resources/targets.ts +378 -0
  116. package/src/schemas.ts +135 -62
  117. package/src/types.ts +2273 -322
  118. package/dist/resources/spec-revisions.d.ts +0 -47
  119. package/dist/resources/spec-revisions.d.ts.map +0 -1
  120. package/dist/resources/spec-revisions.js +0 -90
  121. package/src/resources/spec-revisions.ts +0 -150
@@ -0,0 +1,40 @@
1
+ /** Identity comes from the authenticated API response, including opaque-token APIs. */
2
+ export type IdentityKind = "subject" | "account" | "organization";
3
+ export type IdentityPolicy = Partial<Record<IdentityKind, string>>;
4
+ export type ApiIdentity = Partial<Record<IdentityKind, string | null>>;
5
+ export interface VerifiedIdentity {
6
+ values: ApiIdentity;
7
+ checkedAt: string;
8
+ }
9
+ export interface IdentityConfiguration {
10
+ operation: string;
11
+ fields: IdentityPolicy;
12
+ }
13
+ export declare function validateIdentityPointer(pointer: unknown): asserts pointer is string;
14
+ export declare function identityPolicyOf(auth?: {
15
+ identitySubject?: string | null;
16
+ identityAccount?: string | null;
17
+ identityOrganization?: string | null;
18
+ }): IdentityPolicy;
19
+ export declare function readApiIdentity(data: unknown, policy: IdentityPolicy): ApiIdentity;
20
+ export declare function assertApiIdentity(expected: ApiIdentity, actual: ApiIdentity): void;
21
+ /** No redirects, bounded decoded response, and one deadline including body reads. */
22
+ export declare function identityFetch(apiBaseUrl: string): typeof fetch;
23
+ type IdentityResult = {
24
+ ok: boolean;
25
+ data?: unknown;
26
+ error?: {
27
+ status?: number;
28
+ };
29
+ };
30
+ export declare function identityResult(client: unknown, operation: {
31
+ resource: string;
32
+ method: string;
33
+ }): Promise<IdentityResult>;
34
+ export declare function verifyClientIdentity(createClient: (options: Record<string, unknown>) => unknown, options: Record<string, unknown>, operation: {
35
+ resource: string;
36
+ method: string;
37
+ }, policy: IdentityPolicy, expected?: ApiIdentity): Promise<VerifiedIdentity>;
38
+ export declare function verifyApiIdentity(read: (anonymous: boolean) => Promise<IdentityResult>, policy: IdentityPolicy, expected?: ApiIdentity): Promise<VerifiedIdentity>;
39
+ export {};
40
+ //# sourceMappingURL=api-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-identity.d.ts","sourceRoot":"","sources":["../src/api-identity.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAAC;AAClE,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;AACnE,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;AACvE,MAAM,WAAW,gBAAgB;IAAG,MAAM,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAC5E,MAAM,WAAW,qBAAqB;IAAG,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE;AAEpF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,CAInF;AAED,wBAAgB,gBAAgB,CAAC,IAAI,GAAE;IAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAAG,cAAc,CAKtK;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,GAAG,WAAW,CAelF;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAIlF;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,KAAK,CA8B9D;AAED,KAAK,cAAc,GAAG;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AACnF,wBAAsB,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAI9H;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAI9P;AACD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASxK"}
@@ -0,0 +1,128 @@
1
+ export function validateIdentityPointer(pointer) {
2
+ if (typeof pointer !== "string" || !pointer.startsWith("/") || pointer.length > 512 || /[\x00-\x1f\x7f]/.test(pointer) || /~(?:[^01]|$)/.test(pointer)) {
3
+ throw new Error("Identity fields must be JSON Pointers starting with /, at most 512 characters, with ~0 and ~1 escapes.");
4
+ }
5
+ }
6
+ export function identityPolicyOf(auth = {}) {
7
+ const entries = [["subject", auth.identitySubject], ["account", auth.identityAccount], ["organization", auth.identityOrganization]];
8
+ const policy = {};
9
+ for (const [kind, pointer] of entries)
10
+ if (pointer !== undefined && pointer !== null) {
11
+ validateIdentityPointer(pointer);
12
+ policy[kind] = pointer;
13
+ }
14
+ return policy;
15
+ }
16
+ export function readApiIdentity(data, policy) {
17
+ const result = {};
18
+ if (!Object.keys(policy).length)
19
+ throw new Error("Configure at least one identity field before verifying a session.");
20
+ for (const [kind, pointer] of Object.entries(policy)) {
21
+ validateIdentityPointer(pointer);
22
+ let value = data;
23
+ for (const part of pointer.slice(1).split("/").map((part) => part.replaceAll("~1", "/").replaceAll("~0", "~"))) {
24
+ if (!value || typeof value !== "object" || !Object.hasOwn(value, part))
25
+ throw new Error("The API identity response is missing a configured field. Check the identity field mapping.");
26
+ value = value[part];
27
+ }
28
+ if (value === null && kind === "organization")
29
+ result[kind] = null;
30
+ else if ((typeof value === "string" && value.length > 0 && value.length <= 512 && !/[\x00-\x1f\x7f]/.test(value)) || (typeof value === "number" && Number.isSafeInteger(value)))
31
+ result[kind] = String(value);
32
+ else
33
+ throw new Error("The API identity field must return a nonempty ID string or safe integer. Only an organization may be null.");
34
+ }
35
+ return result;
36
+ }
37
+ export function assertApiIdentity(expected, actual) {
38
+ if (!Object.keys(expected).length || Object.entries(expected).some(([key, value]) => !Object.hasOwn(actual, key) || actual[key] !== value)) {
39
+ throw new Error("The authenticated account, subject or organization does not match this login. Sign in again with the intended account and organization.");
40
+ }
41
+ }
42
+ /** No redirects, bounded decoded response, and one deadline including body reads. */
43
+ export function identityFetch(apiBaseUrl) {
44
+ const base = new URL(apiBaseUrl);
45
+ if ((base.protocol !== "https:" && !(base.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(base.hostname))) || base.username || base.password || base.search || base.hash)
46
+ throw new Error("Identity verification requires an HTTPS API URL; loopback HTTP is allowed for development.");
47
+ const basePath = base.pathname.replace(/\/+$/, "");
48
+ return async (input, init) => {
49
+ const url = new URL(input instanceof Request ? input.url : String(input));
50
+ if (url.origin !== base.origin || (url.pathname !== basePath && !url.pathname.startsWith(basePath + "/")) || url.username || url.password || url.hash)
51
+ throw new Error("The identity read must stay on the configured API.");
52
+ const abort = new AbortController();
53
+ const timeout = setTimeout(() => abort.abort(), 10_000);
54
+ try {
55
+ const signal = init?.signal ? AbortSignal.any([init.signal, abort.signal]) : abort.signal;
56
+ const response = await fetch(input, { ...init, redirect: "error", signal });
57
+ const reader = response.body?.getReader();
58
+ const chunks = [];
59
+ let size = 0;
60
+ if (reader) {
61
+ try {
62
+ while (true) {
63
+ const chunk = await reader.read();
64
+ if (chunk.done)
65
+ break;
66
+ size += chunk.value.byteLength;
67
+ if (size > 1_048_576) {
68
+ abort.abort();
69
+ throw new Error();
70
+ }
71
+ chunks.push(chunk.value);
72
+ }
73
+ }
74
+ finally {
75
+ reader.releaseLock();
76
+ }
77
+ }
78
+ const bytes = new Uint8Array(size);
79
+ let offset = 0;
80
+ for (const chunk of chunks) {
81
+ bytes.set(chunk, offset);
82
+ offset += chunk.byteLength;
83
+ }
84
+ return new Response([204, 205, 304].includes(response.status) ? null : bytes, { status: response.status, statusText: response.statusText, headers: response.headers });
85
+ }
86
+ catch {
87
+ throw new Error("The API identity read failed. Check the API URL, connectivity and response size before signing in again.");
88
+ }
89
+ finally {
90
+ clearTimeout(timeout);
91
+ }
92
+ };
93
+ }
94
+ export async function identityResult(client, operation) {
95
+ const target = client[operation.resource];
96
+ if (!target?.[operation.method])
97
+ throw new Error("The configured identity operation is not available in this package.");
98
+ return target[operation.method]();
99
+ }
100
+ export function verifyClientIdentity(createClient, options, operation, policy, expected) {
101
+ if (typeof options.baseUrl !== "string")
102
+ throw new Error("Configure the API base URL before verifying identity.");
103
+ const shared = { baseUrl: options.baseUrl, environment: options.environment, fetch: identityFetch(options.baseUrl), maxRetries: 0, timeoutMs: 10_000 };
104
+ return verifyApiIdentity((anonymous) => identityResult(createClient(anonymous ? shared : { ...options, ...shared }), operation), policy, expected);
105
+ }
106
+ export async function verifyApiIdentity(read, policy, expected) {
107
+ let anonymous, authenticated;
108
+ try {
109
+ anonymous = await read(true);
110
+ }
111
+ catch {
112
+ throw new Error("Could not verify that the identity read rejects anonymous access.");
113
+ }
114
+ if (anonymous.ok || ![401, 403].includes(anonymous.error?.status ?? 0))
115
+ throw new Error("The identity read must reject anonymous access with 401 or 403 before login can be verified.");
116
+ try {
117
+ authenticated = await read(false);
118
+ }
119
+ catch {
120
+ throw new Error("The API identity read failed with the new credential. Check the API configuration and granted permissions.");
121
+ }
122
+ if (!authenticated.ok)
123
+ throw new Error("The API did not accept the new login credential for its identity read. Check the audience, scopes and account access.");
124
+ const values = readApiIdentity(authenticated.data, policy);
125
+ if (expected)
126
+ assertApiIdentity(expected, values);
127
+ return { values, checkedAt: new Date().toISOString() };
128
+ }
@@ -0,0 +1,30 @@
1
+ export interface ProfileConfig {
2
+ baseUrl?: string;
3
+ environment?: string;
4
+ docsUrl?: string;
5
+ }
6
+ export interface ProfileContext {
7
+ name: string;
8
+ directory: string;
9
+ source: "flag" | "environment" | "selected" | "default";
10
+ }
11
+ export declare function profileName(value: string): string;
12
+ export declare function profileDirectory(root: string, name: string): string;
13
+ export declare function resolveProfile(root: string, options?: {
14
+ flag?: string;
15
+ environment?: string;
16
+ allowMissing?: boolean;
17
+ }): ProfileContext;
18
+ export declare function selectProfile(root: string, name: string): void;
19
+ export declare function readProfileConfig(directory: string): ProfileConfig;
20
+ export declare function updateProfileConfig(directory: string, change: (current: ProfileConfig) => ProfileConfig): Promise<void>;
21
+ export declare function listProfiles(root: string): {
22
+ name: string;
23
+ config: ProfileConfig;
24
+ hasSavedCredentials: boolean;
25
+ }[];
26
+ /** Removing a profile requires logout first. Hold the settings and both storage
27
+ * locks so a concurrent login cannot be deleted underneath its transaction. */
28
+ export declare function removeProfile(root: string, name: string): Promise<void>;
29
+ export declare function profileFlag(args: string[]): string | undefined;
30
+ //# sourceMappingURL=auth-profiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-profiles.d.ts","sourceRoot":"","sources":["../src/auth-profiles.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAAG,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE;AAC3F,MAAM,WAAW,cAAc;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,SAAS,CAAA;CAAE;AAE5H,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAqBD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAOnE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,cAAc,CAa1I;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAI9D;AAED,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAIlE;AAED,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7H;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,EAAE,CAYlH;AAED;+EAC+E;AAC/E,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc7E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAS9D"}
@@ -0,0 +1,138 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { FileCredentialStore } from "./oauth-session.js";
5
+ export function profileName(value) {
6
+ if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(value) || /^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/.test(value))
7
+ throw new Error("Profile names use 1–64 lowercase letters, numbers, hyphens or underscores and cannot be reserved OS names.");
8
+ return value;
9
+ }
10
+ function json(path) {
11
+ try {
12
+ const value = JSON.parse(readFileSync(path, "utf8"));
13
+ if (!value || typeof value !== "object" || Array.isArray(value))
14
+ throw new Error();
15
+ return value;
16
+ }
17
+ catch (error) {
18
+ if (error.code === "ENOENT")
19
+ return null;
20
+ throw new Error("Cannot read profile settings. Repair the settings file before retrying.");
21
+ }
22
+ }
23
+ function write(directory, file, value) {
24
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
25
+ const temporary = join(directory, ".profile-" + randomBytes(16).toString("hex") + ".tmp");
26
+ try {
27
+ writeFileSync(temporary, JSON.stringify(value, null, 2) + "\n", { flag: "wx", mode: 0o600, flush: true });
28
+ renameSync(temporary, join(directory, file));
29
+ }
30
+ finally {
31
+ rmSync(temporary, { force: true });
32
+ }
33
+ }
34
+ export function profileDirectory(root, name) {
35
+ const directory = join(root, "profiles", profileName(name));
36
+ try {
37
+ const entry = lstatSync(directory);
38
+ if (entry.isSymbolicLink() || !entry.isDirectory())
39
+ throw new Error("A profile must be a directory, not a link or another file.");
40
+ }
41
+ catch (error) {
42
+ if (error.code !== "ENOENT")
43
+ throw error;
44
+ }
45
+ return directory;
46
+ }
47
+ export function resolveProfile(root, options = {}) {
48
+ let name, source;
49
+ if (options.flag !== undefined) {
50
+ name = profileName(options.flag);
51
+ source = "flag";
52
+ }
53
+ else if (options.environment !== undefined) {
54
+ name = profileName(options.environment);
55
+ source = "environment";
56
+ }
57
+ else {
58
+ const settings = json(join(root, "profiles.json"));
59
+ if (settings && typeof settings.selected !== "string")
60
+ throw new Error("The selected profile setting is invalid. Pass --profile default to recover.");
61
+ name = settings ? profileName(settings.selected) : "default";
62
+ source = settings ? "selected" : "default";
63
+ }
64
+ const directory = profileDirectory(root, name);
65
+ if (name !== "default" && !options.allowMissing && !existsSync(directory))
66
+ throw new Error("Profile '" + name + "' does not exist. Run login --profile " + name + " or configure that profile first.");
67
+ return { name, directory, source };
68
+ }
69
+ export function selectProfile(root, name) {
70
+ const directory = profileDirectory(root, name);
71
+ if (name !== "default" && !existsSync(directory))
72
+ throw new Error("Profile '" + name + "' does not exist. Log in or configure it before selecting it.");
73
+ write(root, "profiles.json", { selected: name });
74
+ }
75
+ export function readProfileConfig(directory) {
76
+ const value = json(join(directory, "config.json")) ?? {};
77
+ for (const [key, field] of Object.entries(value))
78
+ if (!["baseUrl", "environment", "docsUrl"].includes(key) || typeof field !== "string")
79
+ throw new Error("Profile settings contain an unknown field or a non-string value.");
80
+ return value;
81
+ }
82
+ export async function updateProfileConfig(directory, change) {
83
+ await new FileCredentialStore(join(directory, "config.json")).withLock(async () => { write(directory, "config.json", change(readProfileConfig(directory))); });
84
+ }
85
+ export function listProfiles(root) {
86
+ const names = new Set(["default"]);
87
+ try {
88
+ for (const entry of readdirSync(join(root, "profiles"), { withFileTypes: true })) {
89
+ if (!entry.isDirectory() || entry.isSymbolicLink())
90
+ continue;
91
+ try {
92
+ names.add(profileName(entry.name));
93
+ }
94
+ catch { /* unrelated directories are not profiles */ }
95
+ }
96
+ }
97
+ catch (error) {
98
+ if (error.code !== "ENOENT")
99
+ throw error;
100
+ }
101
+ return [...names].sort().map((name) => {
102
+ const directory = profileDirectory(root, name);
103
+ return { name, config: readProfileConfig(directory), hasSavedCredentials: ["credentials.enc", "credentials.json"].some((file) => existsSync(join(directory, file))) };
104
+ });
105
+ }
106
+ /** Removing a profile requires logout first. Hold the settings and both storage
107
+ * locks so a concurrent login cannot be deleted underneath its transaction. */
108
+ export async function removeProfile(root, name) {
109
+ const directory = profileDirectory(root, name);
110
+ if (!existsSync(directory))
111
+ throw new Error("Profile '" + name + "' does not exist.");
112
+ const paths = ["config.json", "credentials.enc", "credentials.json"].map((file) => join(directory, file));
113
+ await new FileCredentialStore(paths[0]).withLock(async () => {
114
+ await new FileCredentialStore(paths[1]).withLock(async () => {
115
+ await new FileCredentialStore(paths[2]).withLock(async () => {
116
+ if (paths.slice(1).some((path) => existsSync(path)))
117
+ throw new Error("Log out of both credential stores for profile '" + name + "' before removing it. Use logout --profile " + name + ".");
118
+ const selected = json(join(root, "profiles.json"));
119
+ if (selected?.selected === name)
120
+ selectProfile(root, "default");
121
+ rmSync(directory, { recursive: true });
122
+ });
123
+ });
124
+ });
125
+ }
126
+ export function profileFlag(args) {
127
+ let value;
128
+ for (let i = 0; i < args.length; i++) {
129
+ if (args[i] === "--profile") {
130
+ value = args[++i];
131
+ if (value === undefined || value.startsWith("--"))
132
+ throw new Error("--profile requires a profile name.");
133
+ }
134
+ else if (args[i].startsWith("--profile="))
135
+ value = args[i].slice("--profile=".length);
136
+ }
137
+ return value === undefined ? undefined : profileName(value);
138
+ }
@@ -2,7 +2,7 @@
2
2
  * Stable codes an agent can branch on. The message is for people; the code
3
3
  * is the contract. Additive only.
4
4
  */
5
- export type IssueCode = "NO_AUTH" | "AUTH_INVALID" | "PLAN_LIMIT" | "NOT_FOUND" | "INVALID_REQUEST" | "SPEC_INVALID" | "RATE_LIMITED" | "SERVER_ERROR" | "NETWORK_ERROR" | "VALIDATION_FAILED" | "TTY_REQUIRED" | "CONFIRMATION_REQUIRED" | "INVALID_USAGE" | "UNKNOWN_COMMAND" | "UNKNOWN_FLAG" | "MISSING_ARGUMENT" | "COMMAND_FAILED";
5
+ export type IssueCode = "NO_AUTH" | "AUTH_INVALID" | "PLAN_LIMIT" | "NOT_FOUND" | "INVALID_REQUEST" | "SPEC_INVALID" | "RATE_LIMITED" | "SERVER_ERROR" | "NETWORK_ERROR" | "VALIDATION_FAILED" | "TTY_REQUIRED" | "CONFIRMATION_REQUIRED" | "INVALID_USAGE" | "UNKNOWN_COMMAND" | "UNKNOWN_FLAG" | "MISSING_ARGUMENT" | "CALL_FAILED";
6
6
  export interface Issue {
7
7
  code: IssueCode;
8
8
  message: string;
@@ -129,6 +129,14 @@ export interface AgentContext {
129
129
  envPrefix: string;
130
130
  authEnvVars: string[];
131
131
  docsUrl: string | null;
132
+ docsIndexUrl?: string | null;
133
+ generatedOperationCount?: number;
134
+ omittedOperations?: {
135
+ command: string;
136
+ tool: string;
137
+ method: string;
138
+ path: string;
139
+ }[];
132
140
  /** The API's hosted MCP endpoint, when it has one. */
133
141
  mcpUrl: string | null;
134
142
  /** Skills repository (owner/name) an agent can install with npx skills add. */
@@ -1 +1 @@
1
- {"version":3,"file":"cli-agent.d.ts","sourceRoot":"","sources":["../src/cli-agent.ts"],"names":[],"mappings":"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"}
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
@@ -59,7 +59,11 @@ export function classifyApiError(error, context) {
59
59
  const body = e.body;
60
60
  const apiCode = body?.errors?.[0]?.code;
61
61
  const apiMessage = body?.errors?.[0]?.message ?? (typeof body?.message === "string" ? body.message : undefined) ?? (typeof body?.error === "string" ? body.error : undefined);
62
- const detail = { status, ...(e.name ? { error: e.name } : {}), ...(e.body !== undefined ? { body: e.body } : {}) };
62
+ const bodyRequestId = e.body && typeof e.body === "object" && !Array.isArray(e.body)
63
+ ? e.body.request_id ?? e.body.requestId
64
+ : undefined;
65
+ const requestId = e.response?.requestId ?? (typeof bodyRequestId === "string" ? bodyRequestId : undefined);
66
+ const detail = { status, ...(e.name ? { error: e.name } : {}), ...(requestId ? { request_id: requestId } : {}), ...(e.body !== undefined ? { body: e.body } : {}) };
63
67
  const same = apiMessage !== undefined && (apiMessage.toLowerCase() === base.toLowerCase() || base.toLowerCase().includes(apiMessage.toLowerCase()) || apiMessage.toLowerCase().includes(base.toLowerCase()));
64
68
  const message = apiMessage === undefined ? base : same ? apiMessage : apiMessage + " (" + base + ")";
65
69
  const upgradeUrl = extractUrl(e.body, ["upgrade_url", "upgradeUrl", "signup_url", "claim_url"]);
@@ -84,8 +88,8 @@ export function classifyApiError(error, context) {
84
88
  if (status === 400 || status === 422 || status === 409 || status === 413)
85
89
  return { code: "INVALID_REQUEST", message, detail, nextSteps: ["Read detail.body for the field the API named; run the command with --help for its flags."] };
86
90
  if (status >= 500)
87
- return { code: "SERVER_ERROR", message, detail, nextSteps: ["Retry once with backoff. If it persists, report the request id in detail.body."] };
88
- return { code: "COMMAND_FAILED", message, detail };
91
+ return { code: "SERVER_ERROR", message, detail, nextSteps: ["Retry once with backoff. If it persists, report detail.request_id."] };
92
+ return { code: "CALL_FAILED", message, detail };
89
93
  }
90
94
  /** A file lookup needs path guidance, not the generic advice for a missing
91
95
  * resource id. Prefer the API's own index when its message names one. */
@@ -129,11 +133,11 @@ function extractRetryAfter(e) {
129
133
  export function agentMode(input) {
130
134
  if (input.flagMode === "agent")
131
135
  return true;
132
- if (input.flagMode === "human" || input.flagMode === "interactive")
136
+ if (input.flagMode === "human")
133
137
  return false;
134
138
  if (input.envMode === "agent")
135
139
  return true;
136
- if (input.envMode === "human" || input.envMode === "interactive")
140
+ if (input.envMode === "human")
137
141
  return false;
138
142
  return !input.stdoutIsTTY && !input.stdinIsTTY;
139
143
  }
@@ -357,14 +361,16 @@ export function compactIndex(commands) {
357
361
  /** The AGENTS.md block body. */
358
362
  export function agentBlock(ctx, commands) {
359
363
  const auth = ctx.authEnvVars.length ? ctx.authEnvVars.join(", ") : "(none)";
364
+ const index = ctx.docsIndexUrl ?? (ctx.docsUrl ? ctx.docsUrl.replace(/\/+$/, "") + "/llms.txt" : null);
360
365
  return [
361
366
  "## " + ctx.bin + " CLI (" + ctx.apiTitle + ")",
362
367
  "",
363
368
  "Generated by typeship. API commands write JSON on stdout; discovery commands take --json. Errors are JSON on stderr ({status, issues[{code,message}], next_steps}), exit 0/1/2. Non-interactive under an agent: no prompts, no browsers.",
364
369
  "",
370
+ ...((ctx.omittedOperations?.length ?? 0) > 0 ? ["- Plan limit: generated " + (ctx.generatedOperationCount ?? commands.length) + " of " + ((ctx.generatedOperationCount ?? commands.length) + ctx.omittedOperations.length) + " operations. Omitted: " + ctx.omittedOperations.map((op) => "`" + op.tool + "` (" + op.method + " " + op.path + ")").join(", ") + ". These return `PLAN_LIMIT`; upgrade and regenerate before use."] : []),
365
371
  "- Auth: " + auth + " in the environment, or `" + ctx.bin + " login`. Never write a key into a file in this repo.",
366
372
  "- Discover: `" + ctx.bin + " --help`, `" + ctx.bin + " <resource> <command> --help`, `" + ctx.bin + " help --json` (machine-readable), `" + ctx.bin + " agent-guide --format json`.",
367
- "- Docs: " + (ctx.docsUrl ? "`" + ctx.bin + " docs search <term> --json`; " + ctx.docsUrl + "/llms.txt" : "`" + ctx.bin + " docs <resource> <command> --json`") + ".",
373
+ "- Docs: " + (index ? "`" + ctx.bin + " docs search <term> --json`; " + index : "`" + ctx.bin + " docs <resource> <command> --json` (a docs URL was not provided at generate time)") + ".",
368
374
  "- Lists: `--all` streams every page as NDJSON. Destructive commands need `--force`.",
369
375
  ...(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 + ")" : "") + "."] : []),
370
376
  "",
@@ -378,6 +384,14 @@ export function agentBlock(ctx, commands) {
378
384
  /** What `agent-guide --format json` returns. */
379
385
  export function agentGuide(ctx, commands) {
380
386
  const first = commands.find((c) => c.method === "GET" && c.flags.every((f) => !f.required)) ?? commands[0];
387
+ const docsIndexUrl = ctx.docsIndexUrl ?? (ctx.docsUrl ? ctx.docsUrl.replace(/\/+$/, "") + "/llms.txt" : null);
388
+ let docsFullUrl = ctx.docsUrl ? ctx.docsUrl.replace(/\/+$/, "") + "/llms-full.txt" : null;
389
+ if (docsIndexUrl) {
390
+ try {
391
+ docsFullUrl = new URL("llms-full.txt", docsIndexUrl).toString();
392
+ }
393
+ catch { /* validated at generation */ }
394
+ }
381
395
  return {
382
396
  name: ctx.bin,
383
397
  package: ctx.pkg,
@@ -386,8 +400,9 @@ export function agentGuide(ctx, commands) {
386
400
  generated_by: "typeship",
387
401
  guide: agentBlock(ctx, commands),
388
402
  first_command: first ? ctx.bin + " " + first.resource + " " + first.command : ctx.bin + " --help",
389
- docs_index_url: ctx.docsUrl ? ctx.docsUrl.replace(/\/+$/, "") + "/llms.txt" : null,
390
- docs_full_url: ctx.docsUrl ? ctx.docsUrl.replace(/\/+$/, "") + "/llms-full.txt" : null,
403
+ docs_index_url: docsIndexUrl,
404
+ docs_full_url: docsFullUrl,
405
+ ...((ctx.omittedOperations?.length ?? 0) > 0 ? { coverage: { generated_operations: ctx.generatedOperationCount ?? commands.length, total_operations: (ctx.generatedOperationCount ?? commands.length) + ctx.omittedOperations.length, omitted_operations: ctx.omittedOperations } } : {}),
391
406
  hosted_mcp_url: ctx.mcpUrl,
392
407
  local_mcp: ctx.hasMcp ? ctx.bin + "-mcp (stdio) or '" + ctx.bin + " mcp install --all'" : null,
393
408
  skills_install: ctx.skillsRepo ? "npx skills add " + ctx.skillsRepo : null,
@@ -446,7 +461,9 @@ export function bundleProperty(outputSchema) {
446
461
  * each item while preserving that envelope, just as it does for pages. */
447
462
  export function collectionProperty(outputSchema) {
448
463
  const props = outputSchema?.properties;
449
- const names = props ? Object.keys(props) : [];
464
+ // Response metadata is not part of the collection's domain shape. APIs
465
+ // such as typeship put request_id beside the array on every JSON response.
466
+ const names = props ? Object.keys(props).filter((name) => name !== "request_id" && name !== "requestId") : [];
450
467
  if (!props || names.length !== 1)
451
468
  return null;
452
469
  const name = names[0];