@labelbox/recursion-cli 0.0.0 → 0.0.42
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/README.md +113 -1
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +38 -0
- package/dist/dispatch.d.ts +15 -0
- package/dist/dispatch.js +122 -0
- package/dist/embed.d.ts +41 -0
- package/dist/embed.js +153 -0
- package/dist/git-host.d.ts +16 -0
- package/dist/git-host.js +190 -0
- package/dist/manifest.d.ts +410 -0
- package/dist/manifest.js +415 -0
- package/dist/permissions.d.ts +31 -0
- package/dist/permissions.js +73 -0
- package/dist/program.d.ts +113 -0
- package/dist/program.js +879 -0
- package/dist/resolve.d.ts +12 -0
- package/dist/resolve.js +43 -0
- package/dist/run.d.ts +39 -0
- package/dist/run.js +80 -0
- package/dist/skills.d.ts +69 -0
- package/dist/skills.js +256 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +22 -0
- package/package.json +50 -4
package/dist/git-host.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
|
+
import process from 'node:process';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { DEFAULT_BASE_URL, supportUrl } from './manifest.js';
|
|
8
|
+
import { envBaseUrl } from './resolve.js';
|
|
9
|
+
const GitRepoClaimSchema = z.object({
|
|
10
|
+
cloneUrl: z.string(),
|
|
11
|
+
defaultBranch: z.string(),
|
|
12
|
+
pushToken: z.string(),
|
|
13
|
+
});
|
|
14
|
+
/** Filename (under `.git/`) the claim's identity is stashed in after
|
|
15
|
+
* `scaffold`, so `submit` can re-claim before every push. `submit` MUST
|
|
16
|
+
* re-claim rather than reuse a token stashed at scaffold time: the backend
|
|
17
|
+
* mints one push token per Aligner under a fixed name and deletes any
|
|
18
|
+
* prior token of that name on every claim (`GitHostClient.mintPushToken`),
|
|
19
|
+
* since the Forgejo username derives from the Aligner alone, not the
|
|
20
|
+
* problem. Without re-claiming, scaffolding a second problem would
|
|
21
|
+
* invalidate the first problem's stashed token and its `submit` would
|
|
22
|
+
* 401/403. */
|
|
23
|
+
const CLAIM_FILE = 'rl-forgejo-claim.json';
|
|
24
|
+
const StashedClaimSchema = z.object({
|
|
25
|
+
organizationId: z.string(),
|
|
26
|
+
problemId: z.string(),
|
|
27
|
+
});
|
|
28
|
+
function resolveBaseUrl(program) {
|
|
29
|
+
const { baseUrl } = program.opts();
|
|
30
|
+
return baseUrl ?? envBaseUrl() ?? DEFAULT_BASE_URL;
|
|
31
|
+
}
|
|
32
|
+
function resolveAuth(program) {
|
|
33
|
+
const { apiKey } = program.opts();
|
|
34
|
+
const { LABELBOX_API_KEY: envApiKey } = process.env;
|
|
35
|
+
const resolved = apiKey ?? envApiKey;
|
|
36
|
+
if (!resolved) {
|
|
37
|
+
throw new Error('missing API key — set LABELBOX_API_KEY or pass --api-key');
|
|
38
|
+
}
|
|
39
|
+
return { apiKey: resolved, baseUrl: resolveBaseUrl(program) };
|
|
40
|
+
}
|
|
41
|
+
/** `POST /v1/organizations/:organizationId/git-repo-claims` — mints a per-Aligner
|
|
42
|
+
* repo + push token for `problemId`. The claiming Aligner is the
|
|
43
|
+
* authenticated caller (the API key), never a client-supplied field. */
|
|
44
|
+
export async function claimGitRepo(args) {
|
|
45
|
+
const url = supportUrl(args.baseUrl, `/organizations/${encodeURIComponent(args.organizationId)}/git-repo-claims`);
|
|
46
|
+
const res = await fetch(url, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
headers: {
|
|
49
|
+
// biome-ignore lint/style/useNamingConvention: HTTP header names are not camelCase.
|
|
50
|
+
Authorization: `Bearer ${args.apiKey}`,
|
|
51
|
+
'Content-Type': 'application/json',
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify({ problemId: args.problemId }),
|
|
54
|
+
});
|
|
55
|
+
if (!res.ok) {
|
|
56
|
+
const text = await res.text().catch(() => '');
|
|
57
|
+
throw new Error(`could not claim a git repo for problem ${args.problemId} — HTTP ${res.status} ${text.slice(0, 200)}`);
|
|
58
|
+
}
|
|
59
|
+
const parsed = GitRepoClaimSchema.safeParse(await res.json());
|
|
60
|
+
if (!parsed.success) {
|
|
61
|
+
throw new Error(`unexpected response shape from ${url}`);
|
|
62
|
+
}
|
|
63
|
+
return parsed.data;
|
|
64
|
+
}
|
|
65
|
+
/** Writes a `GIT_ASKPASS` helper that answers "Username" prompts with a
|
|
66
|
+
* placeholder and "Password" prompts with `token`, via an env var — never
|
|
67
|
+
* the URL or argv, so the token never lands in shell history or `ps`
|
|
68
|
+
* listings. Returns the env overrides to pass to the `git` subprocess and
|
|
69
|
+
* the script's containing directory, for the caller to clean up.
|
|
70
|
+
*
|
|
71
|
+
* `GIT_ASKPASS` must be a single executable file, not a "command args"
|
|
72
|
+
* string — verified live: git silently never invokes a two-word value like
|
|
73
|
+
* `"<node> <script>"` (no error, no fallback prompt — it just doesn't run),
|
|
74
|
+
* so the script needs a `#!/usr/bin/env node` shebang and the exec bit.
|
|
75
|
+
*
|
|
76
|
+
* The script lives in its own `mkdtempSync` directory (not a fixed,
|
|
77
|
+
* guessable path directly under `tmpdir()`) and is written with the `wx`
|
|
78
|
+
* flag, which refuses to follow or overwrite an existing path — closing
|
|
79
|
+
* the local-attacker-pre-plants-a-symlink hardening gap a fixed name would
|
|
80
|
+
* leave open, even though the script itself carries no secret (the token
|
|
81
|
+
* rides in `RL_FORGEJO_TOKEN`, not the script body). */
|
|
82
|
+
function gitCredentialEnv(token) {
|
|
83
|
+
const dir = mkdtempSync(join(tmpdir(), 'rl-forgejo-'));
|
|
84
|
+
const scriptPath = join(dir, 'askpass.cjs');
|
|
85
|
+
writeFileSync(scriptPath, '#!/usr/bin/env node\n' +
|
|
86
|
+
"const p = process.argv[2] || '';\n" +
|
|
87
|
+
"process.stdout.write(/username/i.test(p) ? 'x-access-token' : (process.env.RL_FORGEJO_TOKEN || ''));\n", { flag: 'wx' });
|
|
88
|
+
chmodSync(scriptPath, 0o700);
|
|
89
|
+
return {
|
|
90
|
+
env: {
|
|
91
|
+
...process.env,
|
|
92
|
+
// biome-ignore lint/style/useNamingConvention: environment variable names, not ours to rename
|
|
93
|
+
GIT_ASKPASS: scriptPath,
|
|
94
|
+
// biome-ignore lint/style/useNamingConvention: environment variable names, not ours to rename
|
|
95
|
+
RL_FORGEJO_TOKEN: token,
|
|
96
|
+
},
|
|
97
|
+
cleanupDir: dir,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function runGit(args, cwd, token) {
|
|
101
|
+
const { env, cleanupDir } = gitCredentialEnv(token);
|
|
102
|
+
try {
|
|
103
|
+
// `-c credential.helper=` (empty) disables any configured credential
|
|
104
|
+
// helper (e.g. macOS's osxkeychain, on by default with git-for-mac) for
|
|
105
|
+
// just this invocation — found live: without it, a helper transparently
|
|
106
|
+
// caches/replays a *previous* claim's credential for the same host,
|
|
107
|
+
// silently shadowing GIT_ASKPASS and authenticating as the wrong claim
|
|
108
|
+
// (or failing on an expired one) instead of using the fresh token below.
|
|
109
|
+
const result = spawnSync('git', ['-c', 'credential.helper=', ...args], {
|
|
110
|
+
cwd,
|
|
111
|
+
env,
|
|
112
|
+
stdio: 'inherit',
|
|
113
|
+
});
|
|
114
|
+
if (result.status !== 0) {
|
|
115
|
+
throw new Error(`git ${args.join(' ')} failed (exit ${result.status ?? 'unknown'})`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
rmSync(cleanupDir, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function claimFilePath(repoDir) {
|
|
123
|
+
return join(repoDir, '.git', CLAIM_FILE);
|
|
124
|
+
}
|
|
125
|
+
function stashClaim(repoDir, claim) {
|
|
126
|
+
writeFileSync(claimFilePath(repoDir), JSON.stringify(claim), { mode: 0o600 });
|
|
127
|
+
}
|
|
128
|
+
function readStashedClaim(repoDir) {
|
|
129
|
+
const path = claimFilePath(repoDir);
|
|
130
|
+
if (!existsSync(path)) {
|
|
131
|
+
throw new Error(`no claim found at ${path} — run \`rl scaffold\` in this directory first, or pass --path to point at a scaffolded repo`);
|
|
132
|
+
}
|
|
133
|
+
const parsed = StashedClaimSchema.safeParse(JSON.parse(readFileSync(path, 'utf8')));
|
|
134
|
+
if (!parsed.success) {
|
|
135
|
+
throw new Error(`stashed claim at ${path} has an unexpected shape`);
|
|
136
|
+
}
|
|
137
|
+
return parsed.data;
|
|
138
|
+
}
|
|
139
|
+
/** Register the `scaffold` / `submit` commands on `program`. */
|
|
140
|
+
export function addGitHostCommands(program, helpGroup) {
|
|
141
|
+
program
|
|
142
|
+
.command('scaffold <problemId>')
|
|
143
|
+
.helpGroup(helpGroup)
|
|
144
|
+
.description('Claim a per-Aligner git repo for a coding-task problem and clone it locally')
|
|
145
|
+
.requiredOption('--organization-id <id>', 'Organization the problem belongs to')
|
|
146
|
+
.option('--out <dir>', 'Directory to clone into (default: derived from the repo name)')
|
|
147
|
+
.action(async (problemId, opts) => {
|
|
148
|
+
try {
|
|
149
|
+
const { apiKey, baseUrl } = resolveAuth(program);
|
|
150
|
+
const claim = await claimGitRepo({
|
|
151
|
+
apiKey,
|
|
152
|
+
baseUrl,
|
|
153
|
+
organizationId: opts.organizationId,
|
|
154
|
+
problemId,
|
|
155
|
+
});
|
|
156
|
+
const dir = opts.out ?? basename(claim.cloneUrl).replace(/\.git$/u, '');
|
|
157
|
+
mkdirSync(dir, { recursive: true });
|
|
158
|
+
runGit(['clone', claim.cloneUrl, dir], process.cwd(), claim.pushToken);
|
|
159
|
+
stashClaim(dir, { organizationId: opts.organizationId, problemId });
|
|
160
|
+
process.stdout.write(`Cloned into ${dir} (branch ${claim.defaultBranch}). Ready to work.\n`);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
program
|
|
168
|
+
.command('submit')
|
|
169
|
+
.helpGroup(helpGroup)
|
|
170
|
+
.description('Push local changes in a scaffolded repo back to its claimed remote')
|
|
171
|
+
.option('--path <dir>', 'Path to the scaffolded repo (default: current directory)')
|
|
172
|
+
.action(async (opts) => {
|
|
173
|
+
const dir = opts.path ?? process.cwd();
|
|
174
|
+
try {
|
|
175
|
+
// Re-claims rather than reusing a token stashed at `scaffold` time —
|
|
176
|
+
// see `CLAIM_FILE`'s doc comment: the backend's push token is a
|
|
177
|
+
// single fixed-name credential per Aligner, so scaffolding any other
|
|
178
|
+
// problem since would have invalidated a stashed one.
|
|
179
|
+
const stashed = readStashedClaim(dir);
|
|
180
|
+
const { apiKey, baseUrl } = resolveAuth(program);
|
|
181
|
+
const claim = await claimGitRepo({ apiKey, baseUrl, ...stashed });
|
|
182
|
+
runGit(['push'], dir, claim.pushToken);
|
|
183
|
+
process.stdout.write('Pushed.\n');
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The DEFAULT production base URL: the public API gateway origin. No path
|
|
4
|
+
* suffix — the API version lives in each operation's path (`/v1/...`), so the
|
|
5
|
+
* CLI joins this origin with the manifest's paths verbatim.
|
|
6
|
+
*
|
|
7
|
+
* Keep in sync with `DEFAULT_BASE_URL` in `packages/sdk-ts/src/index.ts`,
|
|
8
|
+
* `PUBLIC_API_BASE_URL` in `packages/sdk-ts/openapi-ts.config.ts`, and
|
|
9
|
+
* `CURL_BASE_URL` in `tools/dx/src/commands/sdk.ts`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_BASE_URL = "https://api.recursion.labelbox.com";
|
|
12
|
+
/**
|
|
13
|
+
* Join a hand-written support-endpoint path onto the base URL, under the API
|
|
14
|
+
* version segment. `path` is version-relative and must start with `/`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function supportUrl(baseUrl: string, path: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* The manifest format the engine understands. Bumped only on a *breaking* schema
|
|
19
|
+
* change (a renamed/removed required field, a changed enum) — additive fields are
|
|
20
|
+
* backward-compatible because the schema strips unknown keys rather than rejecting
|
|
21
|
+
* them, so a newer server never breaks an older CLI by adding data. A mismatch is
|
|
22
|
+
* surfaced with an actionable upgrade message at the validation boundary.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MANIFEST_FORMAT_VERSION = 1;
|
|
25
|
+
export interface ShapeNode {
|
|
26
|
+
name?: string | undefined;
|
|
27
|
+
type: string;
|
|
28
|
+
required?: boolean | undefined;
|
|
29
|
+
description?: string | undefined;
|
|
30
|
+
enum?: string[] | undefined;
|
|
31
|
+
itemEnum?: string[] | undefined;
|
|
32
|
+
default?: string | number | boolean | undefined;
|
|
33
|
+
format?: string | undefined;
|
|
34
|
+
example?: string | number | boolean | undefined;
|
|
35
|
+
nullable?: boolean | undefined;
|
|
36
|
+
minimum?: number | undefined;
|
|
37
|
+
maximum?: number | undefined;
|
|
38
|
+
exclusiveMinimum?: number | undefined;
|
|
39
|
+
exclusiveMaximum?: number | undefined;
|
|
40
|
+
minLength?: number | undefined;
|
|
41
|
+
maxLength?: number | undefined;
|
|
42
|
+
minItems?: number | undefined;
|
|
43
|
+
maxItems?: number | undefined;
|
|
44
|
+
pattern?: string | undefined;
|
|
45
|
+
fields?: ShapeNode[] | undefined;
|
|
46
|
+
items?: ShapeNode | undefined;
|
|
47
|
+
variants?: ShapeNode[] | undefined;
|
|
48
|
+
}
|
|
49
|
+
export declare const ShapeNodeSchema: z.ZodType<ShapeNode>;
|
|
50
|
+
/** The metadata / constraint keys a `ShapeNode` carries beyond its structure. */
|
|
51
|
+
export type ShapeMetaKey = Exclude<keyof ShapeNode, 'name' | 'type' | 'required' | 'description' | 'fields' | 'items' | 'variants'>;
|
|
52
|
+
/** A node's present metadata as ordered `[key, value]` pairs (drives the CLI tags). */
|
|
53
|
+
export declare function shapeMetaEntries(node: ShapeNode): Array<readonly [ShapeMetaKey, string | number | boolean | readonly string[]]>;
|
|
54
|
+
/** A request param: a named shape node plus its HTTP location (for generic dispatch). */
|
|
55
|
+
export declare const ManifestParamSchema: z.ZodObject<{
|
|
56
|
+
type: z.ZodString;
|
|
57
|
+
description: z.ZodOptional<z.ZodString>;
|
|
58
|
+
enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
59
|
+
itemEnum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
60
|
+
default: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
61
|
+
format: z.ZodOptional<z.ZodString>;
|
|
62
|
+
example: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
63
|
+
nullable: z.ZodOptional<z.ZodBoolean>;
|
|
64
|
+
minimum: z.ZodOptional<z.ZodNumber>;
|
|
65
|
+
maximum: z.ZodOptional<z.ZodNumber>;
|
|
66
|
+
exclusiveMinimum: z.ZodOptional<z.ZodNumber>;
|
|
67
|
+
exclusiveMaximum: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
minLength: z.ZodOptional<z.ZodNumber>;
|
|
69
|
+
maxLength: z.ZodOptional<z.ZodNumber>;
|
|
70
|
+
minItems: z.ZodOptional<z.ZodNumber>;
|
|
71
|
+
maxItems: z.ZodOptional<z.ZodNumber>;
|
|
72
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
73
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>>;
|
|
74
|
+
items: z.ZodOptional<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>;
|
|
75
|
+
variants: z.ZodOptional<z.ZodArray<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>>;
|
|
76
|
+
name: z.ZodString;
|
|
77
|
+
required: z.ZodBoolean;
|
|
78
|
+
in: z.ZodEnum<{
|
|
79
|
+
path: "path";
|
|
80
|
+
query: "query";
|
|
81
|
+
body: "body";
|
|
82
|
+
}>;
|
|
83
|
+
}, z.core.$strip>;
|
|
84
|
+
export type ManifestParam = z.infer<typeof ManifestParamSchema>;
|
|
85
|
+
/**
|
|
86
|
+
* One operation, carrying everything the CLI needs to build its command and
|
|
87
|
+
* dispatch generically: the `callPath` (command tree), the `httpMethod` + `path`
|
|
88
|
+
* template + `params[].in` + `bodyKey` (dispatch), and the recursive request/response
|
|
89
|
+
* shapes (`--help`). Mirrors the relevant subset of sdk-ts's `SdkReferenceEntry`.
|
|
90
|
+
*/
|
|
91
|
+
export declare const ManifestOperationSchema: z.ZodObject<{
|
|
92
|
+
operationId: z.ZodString;
|
|
93
|
+
callPath: z.ZodArray<z.ZodString>;
|
|
94
|
+
summary: z.ZodString;
|
|
95
|
+
description: z.ZodOptional<z.ZodString>;
|
|
96
|
+
httpMethod: z.ZodEnum<{
|
|
97
|
+
get: "get";
|
|
98
|
+
post: "post";
|
|
99
|
+
put: "put";
|
|
100
|
+
patch: "patch";
|
|
101
|
+
delete: "delete";
|
|
102
|
+
}>;
|
|
103
|
+
path: z.ZodString;
|
|
104
|
+
bodyKey: z.ZodOptional<z.ZodString>;
|
|
105
|
+
requiredPermissions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
106
|
+
params: z.ZodArray<z.ZodObject<{
|
|
107
|
+
type: z.ZodString;
|
|
108
|
+
description: z.ZodOptional<z.ZodString>;
|
|
109
|
+
enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
110
|
+
itemEnum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
111
|
+
default: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
112
|
+
format: z.ZodOptional<z.ZodString>;
|
|
113
|
+
example: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
114
|
+
nullable: z.ZodOptional<z.ZodBoolean>;
|
|
115
|
+
minimum: z.ZodOptional<z.ZodNumber>;
|
|
116
|
+
maximum: z.ZodOptional<z.ZodNumber>;
|
|
117
|
+
exclusiveMinimum: z.ZodOptional<z.ZodNumber>;
|
|
118
|
+
exclusiveMaximum: z.ZodOptional<z.ZodNumber>;
|
|
119
|
+
minLength: z.ZodOptional<z.ZodNumber>;
|
|
120
|
+
maxLength: z.ZodOptional<z.ZodNumber>;
|
|
121
|
+
minItems: z.ZodOptional<z.ZodNumber>;
|
|
122
|
+
maxItems: z.ZodOptional<z.ZodNumber>;
|
|
123
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
124
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>>;
|
|
125
|
+
items: z.ZodOptional<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>;
|
|
126
|
+
variants: z.ZodOptional<z.ZodArray<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>>;
|
|
127
|
+
name: z.ZodString;
|
|
128
|
+
required: z.ZodBoolean;
|
|
129
|
+
in: z.ZodEnum<{
|
|
130
|
+
path: "path";
|
|
131
|
+
query: "query";
|
|
132
|
+
body: "body";
|
|
133
|
+
}>;
|
|
134
|
+
}, z.core.$strip>>;
|
|
135
|
+
response: z.ZodOptional<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>;
|
|
136
|
+
}, z.core.$strip>;
|
|
137
|
+
export type ManifestOperation = z.infer<typeof ManifestOperationSchema>;
|
|
138
|
+
export declare const ManifestResourceSchema: z.ZodObject<{
|
|
139
|
+
id: z.ZodString;
|
|
140
|
+
title: z.ZodString;
|
|
141
|
+
parent: z.ZodOptional<z.ZodString>;
|
|
142
|
+
order: z.ZodNumber;
|
|
143
|
+
domain: z.ZodOptional<z.ZodString>;
|
|
144
|
+
summary: z.ZodOptional<z.ZodString>;
|
|
145
|
+
description: z.ZodOptional<z.ZodString>;
|
|
146
|
+
object: z.ZodOptional<z.ZodObject<{
|
|
147
|
+
name: z.ZodString;
|
|
148
|
+
fields: z.ZodArray<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>;
|
|
149
|
+
}, z.core.$strip>>;
|
|
150
|
+
operationIds: z.ZodArray<z.ZodString>;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
export type ManifestResource = z.infer<typeof ManifestResourceSchema>;
|
|
153
|
+
export declare const ManifestRelatedSchema: z.ZodObject<{
|
|
154
|
+
requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
155
|
+
type: z.ZodLiteral<"recipe">;
|
|
156
|
+
id: z.ZodString;
|
|
157
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
158
|
+
type: z.ZodLiteral<"state">;
|
|
159
|
+
explanation: z.ZodString;
|
|
160
|
+
predicate: z.ZodOptional<z.ZodString>;
|
|
161
|
+
via: z.ZodOptional<z.ZodObject<{
|
|
162
|
+
type: z.ZodEnum<{
|
|
163
|
+
recipe: "recipe";
|
|
164
|
+
concept: "concept";
|
|
165
|
+
tutorial: "tutorial";
|
|
166
|
+
resource: "resource";
|
|
167
|
+
}>;
|
|
168
|
+
id: z.ZodString;
|
|
169
|
+
}, z.core.$strip>>;
|
|
170
|
+
}, z.core.$strip>]>>>;
|
|
171
|
+
variationOf: z.ZodOptional<z.ZodString>;
|
|
172
|
+
learnMore: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
173
|
+
type: z.ZodEnum<{
|
|
174
|
+
recipe: "recipe";
|
|
175
|
+
concept: "concept";
|
|
176
|
+
tutorial: "tutorial";
|
|
177
|
+
resource: "resource";
|
|
178
|
+
}>;
|
|
179
|
+
id: z.ZodString;
|
|
180
|
+
}, z.core.$strip>>>;
|
|
181
|
+
}, z.core.$strip>;
|
|
182
|
+
export type ManifestRelated = z.infer<typeof ManifestRelatedSchema>;
|
|
183
|
+
export declare const ManifestRecipeSchema: z.ZodObject<{
|
|
184
|
+
id: z.ZodString;
|
|
185
|
+
title: z.ZodString;
|
|
186
|
+
goal: z.ZodString;
|
|
187
|
+
category: z.ZodString;
|
|
188
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
189
|
+
operationId: z.ZodOptional<z.ZodString>;
|
|
190
|
+
}, z.core.$strip>>;
|
|
191
|
+
sdk: z.ZodObject<{
|
|
192
|
+
setup: z.ZodString;
|
|
193
|
+
main: z.ZodString;
|
|
194
|
+
}, z.core.$strip>;
|
|
195
|
+
python: z.ZodOptional<z.ZodObject<{
|
|
196
|
+
setup: z.ZodString;
|
|
197
|
+
main: z.ZodString;
|
|
198
|
+
}, z.core.$strip>>;
|
|
199
|
+
cli: z.ZodObject<{
|
|
200
|
+
setup: z.ZodString;
|
|
201
|
+
main: z.ZodString;
|
|
202
|
+
}, z.core.$strip>;
|
|
203
|
+
curl: z.ZodObject<{
|
|
204
|
+
setup: z.ZodString;
|
|
205
|
+
main: z.ZodString;
|
|
206
|
+
}, z.core.$strip>;
|
|
207
|
+
related: z.ZodOptional<z.ZodObject<{
|
|
208
|
+
requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
209
|
+
type: z.ZodLiteral<"recipe">;
|
|
210
|
+
id: z.ZodString;
|
|
211
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
212
|
+
type: z.ZodLiteral<"state">;
|
|
213
|
+
explanation: z.ZodString;
|
|
214
|
+
predicate: z.ZodOptional<z.ZodString>;
|
|
215
|
+
via: z.ZodOptional<z.ZodObject<{
|
|
216
|
+
type: z.ZodEnum<{
|
|
217
|
+
recipe: "recipe";
|
|
218
|
+
concept: "concept";
|
|
219
|
+
tutorial: "tutorial";
|
|
220
|
+
resource: "resource";
|
|
221
|
+
}>;
|
|
222
|
+
id: z.ZodString;
|
|
223
|
+
}, z.core.$strip>>;
|
|
224
|
+
}, z.core.$strip>]>>>;
|
|
225
|
+
variationOf: z.ZodOptional<z.ZodString>;
|
|
226
|
+
learnMore: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
227
|
+
type: z.ZodEnum<{
|
|
228
|
+
recipe: "recipe";
|
|
229
|
+
concept: "concept";
|
|
230
|
+
tutorial: "tutorial";
|
|
231
|
+
resource: "resource";
|
|
232
|
+
}>;
|
|
233
|
+
id: z.ZodString;
|
|
234
|
+
}, z.core.$strip>>>;
|
|
235
|
+
}, z.core.$strip>>;
|
|
236
|
+
}, z.core.$strip>;
|
|
237
|
+
export type ManifestRecipe = z.infer<typeof ManifestRecipeSchema>;
|
|
238
|
+
export declare const ManifestConceptSchema: z.ZodObject<{
|
|
239
|
+
id: z.ZodString;
|
|
240
|
+
title: z.ZodString;
|
|
241
|
+
domain: z.ZodString;
|
|
242
|
+
related: z.ZodArray<z.ZodString>;
|
|
243
|
+
body: z.ZodString;
|
|
244
|
+
}, z.core.$strip>;
|
|
245
|
+
export type ManifestConcept = z.infer<typeof ManifestConceptSchema>;
|
|
246
|
+
export declare const ManifestTutorialSchema: z.ZodObject<{
|
|
247
|
+
id: z.ZodString;
|
|
248
|
+
title: z.ZodString;
|
|
249
|
+
body: z.ZodNullable<z.ZodString>;
|
|
250
|
+
}, z.core.$strip>;
|
|
251
|
+
export type ManifestTutorial = z.infer<typeof ManifestTutorialSchema>;
|
|
252
|
+
export declare const ManifestDomainSchema: z.ZodObject<{
|
|
253
|
+
id: z.ZodString;
|
|
254
|
+
title: z.ZodString;
|
|
255
|
+
order: z.ZodNumber;
|
|
256
|
+
}, z.core.$strip>;
|
|
257
|
+
export type ManifestDomain = z.infer<typeof ManifestDomainSchema>;
|
|
258
|
+
export declare const ManifestSchema: z.ZodObject<{
|
|
259
|
+
formatVersion: z.ZodNumber;
|
|
260
|
+
hash: z.ZodString;
|
|
261
|
+
operations: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
262
|
+
operationId: z.ZodString;
|
|
263
|
+
callPath: z.ZodArray<z.ZodString>;
|
|
264
|
+
summary: z.ZodString;
|
|
265
|
+
description: z.ZodOptional<z.ZodString>;
|
|
266
|
+
httpMethod: z.ZodEnum<{
|
|
267
|
+
get: "get";
|
|
268
|
+
post: "post";
|
|
269
|
+
put: "put";
|
|
270
|
+
patch: "patch";
|
|
271
|
+
delete: "delete";
|
|
272
|
+
}>;
|
|
273
|
+
path: z.ZodString;
|
|
274
|
+
bodyKey: z.ZodOptional<z.ZodString>;
|
|
275
|
+
requiredPermissions: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
276
|
+
params: z.ZodArray<z.ZodObject<{
|
|
277
|
+
type: z.ZodString;
|
|
278
|
+
description: z.ZodOptional<z.ZodString>;
|
|
279
|
+
enum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
280
|
+
itemEnum: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
281
|
+
default: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
282
|
+
format: z.ZodOptional<z.ZodString>;
|
|
283
|
+
example: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>;
|
|
284
|
+
nullable: z.ZodOptional<z.ZodBoolean>;
|
|
285
|
+
minimum: z.ZodOptional<z.ZodNumber>;
|
|
286
|
+
maximum: z.ZodOptional<z.ZodNumber>;
|
|
287
|
+
exclusiveMinimum: z.ZodOptional<z.ZodNumber>;
|
|
288
|
+
exclusiveMaximum: z.ZodOptional<z.ZodNumber>;
|
|
289
|
+
minLength: z.ZodOptional<z.ZodNumber>;
|
|
290
|
+
maxLength: z.ZodOptional<z.ZodNumber>;
|
|
291
|
+
minItems: z.ZodOptional<z.ZodNumber>;
|
|
292
|
+
maxItems: z.ZodOptional<z.ZodNumber>;
|
|
293
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
294
|
+
fields: z.ZodOptional<z.ZodArray<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>>;
|
|
295
|
+
items: z.ZodOptional<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>;
|
|
296
|
+
variants: z.ZodOptional<z.ZodArray<z.ZodLazy<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>>>;
|
|
297
|
+
name: z.ZodString;
|
|
298
|
+
required: z.ZodBoolean;
|
|
299
|
+
in: z.ZodEnum<{
|
|
300
|
+
path: "path";
|
|
301
|
+
query: "query";
|
|
302
|
+
body: "body";
|
|
303
|
+
}>;
|
|
304
|
+
}, z.core.$strip>>;
|
|
305
|
+
response: z.ZodOptional<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>;
|
|
306
|
+
}, z.core.$strip>>;
|
|
307
|
+
resources: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
308
|
+
id: z.ZodString;
|
|
309
|
+
title: z.ZodString;
|
|
310
|
+
parent: z.ZodOptional<z.ZodString>;
|
|
311
|
+
order: z.ZodNumber;
|
|
312
|
+
domain: z.ZodOptional<z.ZodString>;
|
|
313
|
+
summary: z.ZodOptional<z.ZodString>;
|
|
314
|
+
description: z.ZodOptional<z.ZodString>;
|
|
315
|
+
object: z.ZodOptional<z.ZodObject<{
|
|
316
|
+
name: z.ZodString;
|
|
317
|
+
fields: z.ZodArray<z.ZodType<ShapeNode, unknown, z.core.$ZodTypeInternals<ShapeNode, unknown>>>;
|
|
318
|
+
}, z.core.$strip>>;
|
|
319
|
+
operationIds: z.ZodArray<z.ZodString>;
|
|
320
|
+
}, z.core.$strip>>;
|
|
321
|
+
recipes: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
322
|
+
id: z.ZodString;
|
|
323
|
+
title: z.ZodString;
|
|
324
|
+
goal: z.ZodString;
|
|
325
|
+
category: z.ZodString;
|
|
326
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
327
|
+
operationId: z.ZodOptional<z.ZodString>;
|
|
328
|
+
}, z.core.$strip>>;
|
|
329
|
+
sdk: z.ZodObject<{
|
|
330
|
+
setup: z.ZodString;
|
|
331
|
+
main: z.ZodString;
|
|
332
|
+
}, z.core.$strip>;
|
|
333
|
+
python: z.ZodOptional<z.ZodObject<{
|
|
334
|
+
setup: z.ZodString;
|
|
335
|
+
main: z.ZodString;
|
|
336
|
+
}, z.core.$strip>>;
|
|
337
|
+
cli: z.ZodObject<{
|
|
338
|
+
setup: z.ZodString;
|
|
339
|
+
main: z.ZodString;
|
|
340
|
+
}, z.core.$strip>;
|
|
341
|
+
curl: z.ZodObject<{
|
|
342
|
+
setup: z.ZodString;
|
|
343
|
+
main: z.ZodString;
|
|
344
|
+
}, z.core.$strip>;
|
|
345
|
+
related: z.ZodOptional<z.ZodObject<{
|
|
346
|
+
requires: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
347
|
+
type: z.ZodLiteral<"recipe">;
|
|
348
|
+
id: z.ZodString;
|
|
349
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
350
|
+
type: z.ZodLiteral<"state">;
|
|
351
|
+
explanation: z.ZodString;
|
|
352
|
+
predicate: z.ZodOptional<z.ZodString>;
|
|
353
|
+
via: z.ZodOptional<z.ZodObject<{
|
|
354
|
+
type: z.ZodEnum<{
|
|
355
|
+
recipe: "recipe";
|
|
356
|
+
concept: "concept";
|
|
357
|
+
tutorial: "tutorial";
|
|
358
|
+
resource: "resource";
|
|
359
|
+
}>;
|
|
360
|
+
id: z.ZodString;
|
|
361
|
+
}, z.core.$strip>>;
|
|
362
|
+
}, z.core.$strip>]>>>;
|
|
363
|
+
variationOf: z.ZodOptional<z.ZodString>;
|
|
364
|
+
learnMore: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
365
|
+
type: z.ZodEnum<{
|
|
366
|
+
recipe: "recipe";
|
|
367
|
+
concept: "concept";
|
|
368
|
+
tutorial: "tutorial";
|
|
369
|
+
resource: "resource";
|
|
370
|
+
}>;
|
|
371
|
+
id: z.ZodString;
|
|
372
|
+
}, z.core.$strip>>>;
|
|
373
|
+
}, z.core.$strip>>;
|
|
374
|
+
}, z.core.$strip>>;
|
|
375
|
+
concepts: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
376
|
+
id: z.ZodString;
|
|
377
|
+
title: z.ZodString;
|
|
378
|
+
domain: z.ZodString;
|
|
379
|
+
related: z.ZodArray<z.ZodString>;
|
|
380
|
+
body: z.ZodString;
|
|
381
|
+
}, z.core.$strip>>;
|
|
382
|
+
tutorials: z.ZodArray<z.ZodObject<{
|
|
383
|
+
id: z.ZodString;
|
|
384
|
+
title: z.ZodString;
|
|
385
|
+
body: z.ZodNullable<z.ZodString>;
|
|
386
|
+
}, z.core.$strip>>;
|
|
387
|
+
domains: z.ZodArray<z.ZodObject<{
|
|
388
|
+
id: z.ZodString;
|
|
389
|
+
title: z.ZodString;
|
|
390
|
+
order: z.ZodNumber;
|
|
391
|
+
}, z.core.$strip>>;
|
|
392
|
+
}, z.core.$strip>;
|
|
393
|
+
export type Manifest = z.infer<typeof ManifestSchema>;
|
|
394
|
+
/**
|
|
395
|
+
* Validate a fetched/cached manifest at the I/O boundary and check engine↔manifest
|
|
396
|
+
* format compatibility. A version mismatch is the one case worth an actionable
|
|
397
|
+
* message: the schema itself stays lenient (so additive server changes are safe),
|
|
398
|
+
* and only a deliberate format bump trips this.
|
|
399
|
+
*/
|
|
400
|
+
export declare function parseManifest(value: unknown, source: string): Manifest;
|
|
401
|
+
/**
|
|
402
|
+
* Fetch the command manifest, revalidating the cache on every run:
|
|
403
|
+
* - send `If-None-Match` with the cached ETag → `304` means the cache is provably
|
|
404
|
+
* current (use it); `200` means the surface changed (validate + replace cache).
|
|
405
|
+
* - a network error (incl. a timeout) falls back to the cached copy with a warning;
|
|
406
|
+
* with no cache it errors clearly.
|
|
407
|
+
* The cache therefore can never serve stale data and never needs manual busting — a
|
|
408
|
+
* backend redeploy is picked up automatically on the next command.
|
|
409
|
+
*/
|
|
410
|
+
export declare function fetchManifest(baseUrl: string, apiKey: string): Promise<Manifest>;
|