@pipelex/sdk 0.3.1 → 0.5.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.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Entry point of the `.mthds` post-edit hook bundle (`check.mjs`).
3
+ *
4
+ * One bundle serves all three harnesses behind `--platform=claude|codex|vibe`
5
+ * (default claude) — the platform decides how the edited file(s) are extracted
6
+ * from the stdin payload and which stdout dialect the decision is encoded in;
7
+ * the pipeline itself is identical:
8
+ *
9
+ * 1. local lint (`@pipelex/tools-wasm` — offline, no credentials) → BLOCK on diagnostics
10
+ * 2. local format (same engine) → write back in place when changed
11
+ * 3. API validate (`POST /v1/validate` via the SDK, `allow_signatures: true`)
12
+ * → BLOCK on an invalid verdict, non-blocking nudge on pending signatures
13
+ *
14
+ * Per-platform input: Claude reads `tool_input.file_path` (one file); Codex
15
+ * parses the `apply_patch` envelope in `tool_input.command` (possibly several
16
+ * files — outcomes are merged, any block wins); Vibe reads the stable
17
+ * `post_tool` payload (`tool_status` gate, path resolved against `cwd`).
18
+ *
19
+ * Failure posture (fail-open, per the networked-hook plan):
20
+ * - no `.mthds` in the payload / unparseable stdin → pass silently
21
+ * - WASM engine fails to load → whole hook unavailable → pass silently
22
+ * - validate unavailable (no `PIPELEX_API_KEY`, network error, timeout, any
23
+ * non-2xx, bundle-gather overflow) → the local lint/format verdicts already
24
+ * applied; the validate stage passes silently
25
+ *
26
+ * The hook always exits 0; a block/deny is expressed on stdout, never via the
27
+ * exit code.
28
+ */
29
+ export {};
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Entry point of the `.mthds` post-edit hook bundle (`check.mjs`).
3
+ *
4
+ * One bundle serves all three harnesses behind `--platform=claude|codex|vibe`
5
+ * (default claude) — the platform decides how the edited file(s) are extracted
6
+ * from the stdin payload and which stdout dialect the decision is encoded in;
7
+ * the pipeline itself is identical:
8
+ *
9
+ * 1. local lint (`@pipelex/tools-wasm` — offline, no credentials) → BLOCK on diagnostics
10
+ * 2. local format (same engine) → write back in place when changed
11
+ * 3. API validate (`POST /v1/validate` via the SDK, `allow_signatures: true`)
12
+ * → BLOCK on an invalid verdict, non-blocking nudge on pending signatures
13
+ *
14
+ * Per-platform input: Claude reads `tool_input.file_path` (one file); Codex
15
+ * parses the `apply_patch` envelope in `tool_input.command` (possibly several
16
+ * files — outcomes are merged, any block wins); Vibe reads the stable
17
+ * `post_tool` payload (`tool_status` gate, path resolved against `cwd`).
18
+ *
19
+ * Failure posture (fail-open, per the networked-hook plan):
20
+ * - no `.mthds` in the payload / unparseable stdin → pass silently
21
+ * - WASM engine fails to load → whole hook unavailable → pass silently
22
+ * - validate unavailable (no `PIPELEX_API_KEY`, network error, timeout, any
23
+ * non-2xx, bundle-gather overflow) → the local lint/format verdicts already
24
+ * applied; the validate stage passes silently
25
+ *
26
+ * The hook always exits 0; a block/deny is expressed on stdout, never via the
27
+ * exit code.
28
+ */
29
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
30
+ import { resolve as resolvePath } from "node:path";
31
+ import { PipelexApiClient } from "../client.js";
32
+ import { decideAfterLint, decideAfterValidate, encodeOutcome, extractCodexMthdsFiles, extractMthdsFilePath, extractVibeMthdsFilePath, mergeOutcomes, } from "./check-core.js";
33
+ import { gatherBundle } from "./bundle-gather.js";
34
+ /** Per-request ceiling on the one network call — well under the hook's overall timeout. */
35
+ const VALIDATE_TIMEOUT_MS = 10_000;
36
+ async function readStdin() {
37
+ const chunks = [];
38
+ for await (const chunk of process.stdin) {
39
+ chunks.push(chunk);
40
+ }
41
+ return Buffer.concat(chunks).toString("utf-8");
42
+ }
43
+ function parsePlatform(argv) {
44
+ for (const arg of argv) {
45
+ if (arg.startsWith("--platform=")) {
46
+ const value = arg.slice("--platform=".length);
47
+ if (value === "claude" || value === "codex" || value === "vibe") {
48
+ return value;
49
+ }
50
+ }
51
+ }
52
+ return "claude";
53
+ }
54
+ /** The absolute paths of edited `.mthds` files that exist on disk, per platform. */
55
+ function resolveTargets(platform, stdinJson) {
56
+ let candidates;
57
+ switch (platform) {
58
+ case "claude": {
59
+ const filePath = extractMthdsFilePath(stdinJson);
60
+ candidates = filePath ? [filePath] : [];
61
+ break;
62
+ }
63
+ case "codex": {
64
+ candidates = extractCodexMthdsFiles(stdinJson).map((raw) => resolvePath(process.cwd(), raw));
65
+ break;
66
+ }
67
+ case "vibe": {
68
+ const extracted = extractVibeMthdsFilePath(stdinJson);
69
+ candidates = extracted
70
+ ? [resolvePath(extracted.cwd ?? process.cwd(), extracted.filePath)]
71
+ : [];
72
+ break;
73
+ }
74
+ }
75
+ // Deleted/renamed-away files have nothing to check (Codex envelopes list
76
+ // paths that may not survive the patch; Claude edits can race a delete).
77
+ return candidates.filter((filePath) => existsSync(filePath));
78
+ }
79
+ /**
80
+ * Load the WASM engine. The one-line "deprecated parameters" warning the
81
+ * wasm-bindgen loader glue prints on first initialize is dropped — it is
82
+ * upstream noise, not a hook diagnostic.
83
+ */
84
+ async function loadEngine() {
85
+ const engine = await import("@pipelex/tools-wasm");
86
+ /* eslint-disable no-console */
87
+ const originalWarn = console.warn;
88
+ console.warn = (...args) => {
89
+ if (typeof args[0] === "string" && args[0].includes("deprecated parameters")) {
90
+ return;
91
+ }
92
+ originalWarn.apply(console, args);
93
+ };
94
+ try {
95
+ await engine.initialize();
96
+ }
97
+ finally {
98
+ console.warn = originalWarn;
99
+ }
100
+ /* eslint-enable no-console */
101
+ return engine;
102
+ }
103
+ /**
104
+ * Run the networked validate stage. Every no-verdict condition maps to
105
+ * `unavailable` — a machine consumer branches on the structured verdict,
106
+ * never on transport.
107
+ */
108
+ async function runValidateStage(filePath) {
109
+ if (!process.env.PIPELEX_API_KEY) {
110
+ return { status: "unavailable" };
111
+ }
112
+ const gathered = gatherBundle(filePath);
113
+ if (!gathered.ok) {
114
+ return { status: "unavailable" };
115
+ }
116
+ try {
117
+ const client = new PipelexApiClient();
118
+ // The client owns the ceiling: on timeout it aborts the fetch itself, so the
119
+ // request does not keep running after the hook has given up on it.
120
+ const result = await client.validateFiles(gathered.files, {
121
+ allowSignatures: true,
122
+ timeoutMs: VALIDATE_TIMEOUT_MS,
123
+ });
124
+ if (result.is_valid === true) {
125
+ return {
126
+ status: "valid",
127
+ pendingSignatures: Array.isArray(result.pending_signatures)
128
+ ? result.pending_signatures
129
+ : [],
130
+ };
131
+ }
132
+ if (result.is_valid === false) {
133
+ return {
134
+ status: "invalid",
135
+ message: result.message,
136
+ validationErrors: Array.isArray(result.validation_errors) ? result.validation_errors : [],
137
+ renderedMarkdown: result.rendered_markdown,
138
+ };
139
+ }
140
+ return { status: "unavailable" }; // no discriminant — no verdict
141
+ }
142
+ catch {
143
+ return { status: "unavailable" };
144
+ }
145
+ }
146
+ /** Synchronous fd-1 write — the process exits right after, an async write could truncate. */
147
+ function emit(outcome, platform) {
148
+ const encoded = encodeOutcome(outcome, platform);
149
+ if (encoded) {
150
+ writeFileSync(1, encoded);
151
+ }
152
+ }
153
+ /** Synchronous fd-2 write, for the same reason. */
154
+ function warn(message) {
155
+ writeFileSync(2, `[mthds-hook] ${message}\n`);
156
+ }
157
+ /** The full pipeline on one edited file: lint → format write-back → validate. */
158
+ async function checkOneFile(engine, filePath) {
159
+ let content;
160
+ try {
161
+ content = readFileSync(filePath, "utf-8");
162
+ }
163
+ catch {
164
+ return { kind: "pass" }; // file gone since the existence check — nothing to gate
165
+ }
166
+ // Stage 1 — local lint
167
+ const lintStage = {
168
+ status: "diagnostics",
169
+ diagnostics: engine.lintMthds(content).diagnostics,
170
+ };
171
+ const lintOutcome = decideAfterLint(filePath, lintStage);
172
+ if (lintOutcome.kind !== "pass") {
173
+ return lintOutcome;
174
+ }
175
+ // Stage 2 — local format, write back in place (mirrors `plxt fmt`)
176
+ try {
177
+ const formatted = engine.formatMthds(content);
178
+ if (formatted.changed) {
179
+ writeFileSync(filePath, formatted.formatted);
180
+ }
181
+ }
182
+ catch (err) {
183
+ const message = err instanceof Error ? err.message : String(err);
184
+ warn(`Warning: format failed: ${message}`);
185
+ }
186
+ // Stage 3 — API validate
187
+ return decideAfterValidate(filePath, await runValidateStage(filePath));
188
+ }
189
+ async function main() {
190
+ const platform = parsePlatform(process.argv.slice(2));
191
+ const filePaths = resolveTargets(platform, await readStdin());
192
+ if (filePaths.length === 0) {
193
+ return;
194
+ }
195
+ let engine;
196
+ try {
197
+ engine = await loadEngine();
198
+ }
199
+ catch {
200
+ return; // engine unavailable — whole hook fails open
201
+ }
202
+ const outcomes = [];
203
+ for (const filePath of filePaths) {
204
+ outcomes.push(await checkOneFile(engine, filePath));
205
+ }
206
+ emit(mergeOutcomes(outcomes), platform);
207
+ }
208
+ main()
209
+ .catch((err) => {
210
+ // Fail open: an unexpected hook fault must never block the write.
211
+ const message = err instanceof Error ? err.message : String(err);
212
+ warn(`Hook error (fail-open): ${message}`);
213
+ })
214
+ .finally(() => {
215
+ // The WASM engine (and any raced-out fetch) can hold the event loop open;
216
+ // the decision is already flushed (synchronous fd writes), so end the
217
+ // process deterministically.
218
+ process.exit(0);
219
+ });
220
+ //# sourceMappingURL=claude-mthds-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-mthds-check.js","sourceRoot":"","sources":["../../src/hooks/claude-mthds-check.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,13 +7,15 @@
7
7
  * errors. Consumers should import everything they need from `@pipelex/sdk`.
8
8
  */
9
9
  /** Package version. Kept in sync with `package.json` — enforced by `tests/index.test.ts`. */
10
- export declare const SDK_VERSION = "0.3.1";
10
+ export declare const SDK_VERSION = "0.5.0";
11
11
  export * from "mthds/protocol";
12
12
  export { PipelexApiClient, DEFAULT_API_BASE_URL } from "./client.js";
13
13
  export type { MthdsFile, ValidateFilesOptions, PipelexApiClientOptions } from "./client.js";
14
14
  export { PipelexExecuteResult } from "./execute-result.js";
15
- export type { DictStuff, DictWorkingMemory, DictPipeOutput, DictRunResultExecute, DryRunStatus, ValidatedPipeEntry, PipelexValidationReport, PipelexInvalidReport, PipelexValidationResult, ValidationErrorCategory, ValidationErrorItem, ConceptRepresentationFormat, BuildInputsRequest, BuildOutputRequest, BuildRunnerRequest, ConceptRequest, PipeSpecRequest, BuildRunnerResponse, ConceptResponse, PipeSpecResponse, } from "./models.js";
15
+ export type { UploadableAsset, UploadFileOptions, UploadRecord } from "./upload.js";
16
+ export type { PrepareInputsRequest, PreparedInputs } from "./prepare-inputs.js";
17
+ export type { DiagnosticKind, DiagnosticRange, Diagnostic, LintResponse, FormatResponse, DictStuff, DictWorkingMemory, DictPipeOutput, DictRunResultExecute, DryRunStatus, ValidatedPipeEntry, PipelexValidationReport, PipelexInvalidReport, PipelexValidationResult, ValidationErrorCategory, ValidationErrorItem, ConceptRepresentationFormat, InputsTemplateFormat, MthdsFileItem, BuildRequestBase, BuildInputsRequest, BuildOutputRequest, BuildRunnerRequest, ConceptRequest, PipeSpecRequest, CrateInvalidReport, BuildInputsValidReport, BuildOutputValidReport, BuildRunnerValidReport, GeneratedArtifact, RunnerStructures, BuildInputsResponse, BuildOutputResponse, BuildRunnerResponse, ConceptResponse, PipeSpecResponse, } from "./models.js";
16
18
  export type { UserProfile, MethodData, MethodWriteInput, Membership, MembershipsResponse, SubscriptionResponse, PlanView, InvoiceView, CheckoutResponse, ChangePlanResponse, BillingPortalResponse, PipelexApiKey, PipelexApiKeyCreated, PipelexApiKeyList, GatewayApiKey, GatewayApiKeyStatus, OnboardingRole, OnboardingCurrentTool, OnboardingInputType, OnboardingHeardFrom, OnboardingSubmission, ResolvedStorageUrl, UploadInput, UploadedFile, PipeStatus, PipelineRun, UpdateRunInput, } from "./product-models.js";
17
19
  export { isTerminalRunStatus, isSuccessRunStatus } from "./runs.js";
18
- export type { RunStatus, RunPublic, RunRead, RunResults, RunResultState, WaitForResultOptions, } from "./runs.js";
19
- export { ApiResponseError, ApiUnreachableError, ClientAuthenticationError, MissingMainStuffError, PipelineExecuteTimeoutError, RunFailedError, RunTimeoutError, RunStillRunningError, RunLifecycleUnavailableError, } from "./errors.js";
20
+ export type { RunStatus, RunPublic, RunRead, RunResults, RunResultState, TokensUsageRecord, WaitForResultOptions, } from "./runs.js";
21
+ export { ApiResponseError, ApiUnreachableError, ClientAuthenticationError, MissingMainStuffError, PipelineExecuteTimeoutError, RunFailedError, RunTimeoutError, RunStillRunningError, RunLifecycleUnavailableError, InputPreparationError, InvalidLocalSourceError, RejectedAssetError, UnsupportedUploadCapabilityError, UploadAuthenticationError, UploadTransportError, } from "./errors.js";
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * errors. Consumers should import everything they need from `@pipelex/sdk`.
8
8
  */
9
9
  /** Package version. Kept in sync with `package.json` — enforced by `tests/index.test.ts`. */
10
- export const SDK_VERSION = "0.3.1";
10
+ export const SDK_VERSION = "0.5.0";
11
11
  // ── Pure MTHDS Protocol surface (re-exported from the `mthds/protocol` subpath) ──
12
12
  // The standard's interface, wire models, request/options surface, abstract domain
13
13
  // shapes, and the protocol-base `PipelineRequestError`. Re-exported so apps have a
@@ -20,5 +20,5 @@ export { PipelexExecuteResult } from "./execute-result.js";
20
20
  // ── Run lifecycle (hosted extension — NOT part of the protocol) ──────
21
21
  export { isTerminalRunStatus, isSuccessRunStatus } from "./runs.js";
22
22
  // ── Typed errors (PipelineRequestError rides the protocol re-export above) ──
23
- export { ApiResponseError, ApiUnreachableError, ClientAuthenticationError, MissingMainStuffError, PipelineExecuteTimeoutError, RunFailedError, RunTimeoutError, RunStillRunningError, RunLifecycleUnavailableError, } from "./errors.js";
23
+ export { ApiResponseError, ApiUnreachableError, ClientAuthenticationError, MissingMainStuffError, PipelineExecuteTimeoutError, RunFailedError, RunTimeoutError, RunStillRunningError, RunLifecycleUnavailableError, InputPreparationError, InvalidLocalSourceError, RejectedAssetError, UnsupportedUploadCapabilityError, UploadAuthenticationError, UploadTransportError, } from "./errors.js";
24
24
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,6FAA6F;AAC7F,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAEnC,oFAAoF;AACpF,kFAAkF;AAClF,mFAAmF;AACnF,wBAAwB;AACxB,cAAc,gBAAgB,CAAC;AAE/B,wEAAwE;AACxE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGrE,4FAA4F;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAyD3D,wEAAwE;AACxE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAUpE,+EAA+E;AAC/E,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,6FAA6F;AAC7F,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC;AAEnC,oFAAoF;AACpF,kFAAkF;AAClF,mFAAmF;AACnF,wBAAwB;AACxB,cAAc,gBAAgB,CAAC;AAE/B,wEAAwE;AACxE,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGrE,4FAA4F;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AA8E3D,wEAAwE;AACxE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAWpE,+EAA+E;AAC/E,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,4BAA4B,EAC5B,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,gCAAgC,EAChC,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,aAAa,CAAC"}
package/dist/models.d.ts CHANGED
@@ -22,10 +22,18 @@ export interface DictWorkingMemory {
22
22
  * runtime-internal field produced by the pipelex runtime inside the
23
23
  * `pipe_output` payload — it deliberately keeps its name (runtime internals are
24
24
  * out of the wire-rename scope).
25
+ *
26
+ * **Extension-open**, mirroring `DictPipeOutputAbstract`'s `extra="allow"`: the
27
+ * runner rides Pipelex extension fields here beside `working_memory` — the usage
28
+ * pair (`tokens_usages` / `usage_assembly_error`) is the current example. Without
29
+ * the index signature, reading one means casting the whole value away, and the
30
+ * two SDK mirrors of the same wire shape disagree on whether it is closed.
25
31
  */
26
32
  export interface DictPipeOutput {
27
33
  working_memory: DictWorkingMemory;
28
34
  pipeline_run_id: string;
35
+ /** Pipelex extension fields the runner rides on the pipe output. */
36
+ [extension: string]: unknown;
29
37
  }
30
38
  /**
31
39
  * The default `RunResultExecute` binding — the concrete execute result with a
@@ -136,19 +144,95 @@ export interface ValidationErrorItem {
136
144
  missing_concept_code?: string;
137
145
  declared_concepts?: string[];
138
146
  }
147
+ /** Which analysis produced a `Diagnostic` — mirror of `pipelex-tools`' closed kind set. */
148
+ export type DiagnosticKind = "syntax" | "semantic" | "schema";
149
+ /** Source span of a `Diagnostic` — byte offsets plus 1-based line/column coordinates. */
150
+ export interface DiagnosticRange {
151
+ start_offset: number;
152
+ end_offset: number;
153
+ start_line: number;
154
+ start_col: number;
155
+ end_line: number;
156
+ end_col: number;
157
+ }
158
+ /**
159
+ * One structured lint/format diagnostic — mirror of pipelex's `Diagnostic`.
160
+ * `severity` stays an open string (the server does not close the vocabulary);
161
+ * `location` and `range` are `null` when the analysis cannot attribute a span.
162
+ */
163
+ export interface Diagnostic {
164
+ kind: DiagnosticKind;
165
+ severity: string;
166
+ message: string;
167
+ location: string | null;
168
+ range: DiagnosticRange | null;
169
+ }
170
+ /** `POST /v1/lint` 200 body — the diagnostics of one linted `.mthds` file. */
171
+ export interface LintResponse {
172
+ diagnostics: Diagnostic[];
173
+ }
174
+ /**
175
+ * `POST /v1/format` 200 body — the canonically formatted content, whether it
176
+ * differs from the submitted one, and any diagnostics found on the way. A syntax
177
+ * error yields `changed: false` with the content echoed back unchanged.
178
+ */
179
+ export interface FormatResponse {
180
+ formatted: string;
181
+ changed: boolean;
182
+ diagnostics: Diagnostic[];
183
+ }
139
184
  export type ConceptRepresentationFormat = "json" | "python" | "schema";
140
- export interface BuildInputsRequest {
141
- mthds_contents: string[];
142
- pipe_code: string;
185
+ /** Encoding of a `/v1/build/inputs` template. Decides which field carries it back. */
186
+ export type InputsTemplateFormat = "json" | "toml";
187
+ /**
188
+ * One MTHDS file in a build closure. `source` is an optional provenance label (a
189
+ * filename, a URI) that the server threads onto every diagnostic it raises from
190
+ * this file, so an invalid verdict can point at the file that caused it.
191
+ *
192
+ * NOT the same type as `MthdsFile` (the one `validateFiles()` takes), which the
193
+ * client adapts into `/v1/validate`'s parallel `mthds_contents` + `mthds_sources`
194
+ * arrays: that route spells the label `uri`, this envelope spells it `source`. The
195
+ * two collapse into one only if `/v1/validate` ever migrates onto `files[]` — a
196
+ * protocol-level change owned by the MTHDS standard, not ours to make here.
197
+ */
198
+ export interface MthdsFileItem {
199
+ content: string;
200
+ source?: string;
143
201
  }
144
- export interface BuildOutputRequest {
145
- mthds_contents: string[];
146
- pipe_code: string;
202
+ /**
203
+ * The closure + pipe selector every `/v1/build/*` route shares.
204
+ *
205
+ * Supply the closure EITHER as inline `files` OR as a `method_ref` into the method
206
+ * registry — never both. `method_ref` is reserved: the registry does not exist yet,
207
+ * so the server answers `501` for it today.
208
+ */
209
+ export interface BuildRequestBase {
210
+ files?: MthdsFileItem[];
211
+ method_ref?: string;
212
+ /**
213
+ * The pipe to project, as a QUALIFIED `domain.pipe_code` ref. Omit it to default
214
+ * to the closure's declared `main_pipe` — which fails (422) when the closure
215
+ * declares none, or declares several across its domains.
216
+ */
217
+ pipe_ref?: string;
218
+ }
219
+ export interface BuildInputsRequest extends BuildRequestBase {
220
+ /** `json` (default) puts the parsed template in `inputs`; `toml` puts raw text in `inputs_toml`. */
221
+ format?: InputsTemplateFormat;
222
+ /** Emit the ceremonial `{concept, content}` envelope per input. Defaults to the light shape. */
223
+ explicit?: boolean;
224
+ }
225
+ export interface BuildOutputRequest extends BuildRequestBase {
226
+ /** `schema` (default) and `json` put a parsed object in `output`; `python` puts source in `output_python`. */
147
227
  format?: ConceptRepresentationFormat;
148
228
  }
149
- export interface BuildRunnerRequest {
150
- mthds_contents: string[];
151
- pipe_code: string;
229
+ export interface BuildRunnerRequest extends BuildRequestBase {
230
+ /**
231
+ * Accept unresolved pipe signatures as pending rather than invalid. Alone among
232
+ * the build routes this one still runs the dry-run sweep, and the flag only ever
233
+ * parameterized that sweep.
234
+ */
235
+ allow_signatures?: boolean;
152
236
  }
153
237
  export interface ConceptRequest {
154
238
  spec: Record<string, unknown>;
@@ -157,12 +241,92 @@ export interface PipeSpecRequest {
157
241
  pipe_type: string;
158
242
  spec: Record<string, unknown>;
159
243
  }
160
- export interface BuildRunnerResponse {
161
- python_code: string;
162
- pipe_code: string;
163
- success: boolean;
244
+ /**
245
+ * The `is_valid: false` arm shared by every `/v1/build/*` route.
246
+ *
247
+ * The build routes follow `/validate`'s discipline: an unresolvable closure is the
248
+ * *successful product* of the call (the request was well-formed, the library was
249
+ * not), so it rides a **200** discriminated on `is_valid` — never a 4xx. Only a
250
+ * no-verdict condition (an unknown `pipe_ref`, `method_ref`, auth, a server fault)
251
+ * throws `ApiResponseError`. Branch on `is_valid`, never on the transport.
252
+ */
253
+ export interface CrateInvalidReport {
254
+ is_valid: false;
255
+ validation_errors: ValidationErrorItem[];
164
256
  message: string;
165
257
  }
258
+ /** Fields the valid arm of every `/v1/build/*` route carries. */
259
+ interface BuildValidReportBase {
260
+ is_valid: true;
261
+ /** The qualified pipe that was projected — the RESOLVED selector, always `domain.pipe_code`. */
262
+ pipe_ref: string;
263
+ /** The `pipe_ref` as submitted. Absent when it was omitted and defaulted to `main_pipe`. */
264
+ requested_pipe_ref?: string;
265
+ message: string;
266
+ }
267
+ /**
268
+ * The `/v1/build/inputs` valid arm. The template rides ONE of two fields, chosen by
269
+ * `format`: `inputs` (a parsed object) for `json`, `inputs_toml` (raw text) for
270
+ * `toml`. TOML cannot be carried as a parsed object without losing what makes it
271
+ * worth asking for — its concept comments and key order — so the two are separate
272
+ * fields and the unused one is absent from the body entirely.
273
+ *
274
+ * That "absent entirely" is why this is a union rather than one interface with two
275
+ * optional fields: `format` is a real discriminant, so narrowing on it hands you the
276
+ * field it selected as REQUIRED, with the other one statically unreachable.
277
+ */
278
+ interface BuildInputsJsonReport extends BuildValidReportBase {
279
+ format: "json";
280
+ explicit: boolean;
281
+ inputs: Record<string, unknown>;
282
+ inputs_toml?: never;
283
+ }
284
+ interface BuildInputsTomlReport extends BuildValidReportBase {
285
+ format: "toml";
286
+ explicit: boolean;
287
+ inputs?: never;
288
+ inputs_toml: string;
289
+ }
290
+ export type BuildInputsValidReport = BuildInputsJsonReport | BuildInputsTomlReport;
291
+ export type BuildInputsResponse = BuildInputsValidReport | CrateInvalidReport;
292
+ /**
293
+ * The `/v1/build/output` valid arm. Same two-field split as the inputs template, for
294
+ * the same reason: `schema` and `json` are objects, `python` is source text — and so
295
+ * it is a discriminated union for the same reason too.
296
+ */
297
+ interface BuildOutputObjectReport extends BuildValidReportBase {
298
+ format: "schema" | "json";
299
+ output: Record<string, unknown>;
300
+ output_python?: never;
301
+ }
302
+ interface BuildOutputPythonReport extends BuildValidReportBase {
303
+ format: "python";
304
+ output?: never;
305
+ output_python: string;
306
+ }
307
+ export type BuildOutputValidReport = BuildOutputObjectReport | BuildOutputPythonReport;
308
+ export type BuildOutputResponse = BuildOutputValidReport | CrateInvalidReport;
309
+ /** One stamped generated file in the structures projection. */
310
+ export interface GeneratedArtifact {
311
+ path: string;
312
+ content: string;
313
+ }
314
+ /**
315
+ * The typed-structures projection the runner script imports from. Write `artifacts`
316
+ * and `lock` (as `lock_filename`) under `directory`, relative to the runner script,
317
+ * and the returned `python_code` runs against them.
318
+ */
319
+ export interface RunnerStructures {
320
+ directory: string;
321
+ artifacts: GeneratedArtifact[];
322
+ lock: string;
323
+ lock_filename: string;
324
+ }
325
+ export interface BuildRunnerValidReport extends BuildValidReportBase {
326
+ python_code: string;
327
+ structures: RunnerStructures;
328
+ }
329
+ export type BuildRunnerResponse = BuildRunnerValidReport | CrateInvalidReport;
166
330
  export interface ConceptResponse {
167
331
  success: boolean;
168
332
  concept_code: string;
@@ -174,3 +338,4 @@ export interface PipeSpecResponse {
174
338
  pipe_type: string;
175
339
  toml: string;
176
340
  }
341
+ export {};
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `prepareInputs` — signature-driven input preparation. Resolves the target
3
+ * pipe's declared inputs via the explicit inputs template, interprets the
4
+ * caller's compact inputs top-down against it, uploads the file-bearing values,
5
+ * and returns rewritten inputs (canonical content carrying `pipelex-storage://`
6
+ * in `url`) plus one upload record per prepared asset.
7
+ *
8
+ * The classification mirrors the runtime: `pipelex`'s `input_normalizer` walks
9
+ * Image/Document contents (recognized by their `url`-bearing shape, incl. nested
10
+ * in structured content) and `resolve_uri` decides upload vs pass-through. The
11
+ * declared signature comes from the explicit template (`buildInputs`,
12
+ * `explicit: true`), whose canonical content shape is the classifier — the file
13
+ * signal is a value that is a dict containing a `url` key. See the shared
14
+ * behavior matrix (`wip/upload/behavior-matrix.md`) and `docs/input-preparation.md`.
15
+ */
16
+ import type { BuildInputsResponse, MthdsFileItem } from "./models.js";
17
+ import type { UploadCapableClient, UploadRecord } from "./upload.js";
18
+ /** What `prepareInputs` takes: the method closure, the target pipe, and the caller's compact inputs. */
19
+ export interface PrepareInputsRequest {
20
+ /** The method closure — inline MTHDS files. This is the signature source. */
21
+ files: MthdsFileItem[];
22
+ /** The pipe to prepare inputs for, as a qualified `domain.pipe_code`; omit to default to the closure's `main_pipe`. */
23
+ pipe_ref?: string;
24
+ /** The caller's compact inputs (variable name → value). */
25
+ inputs: Record<string, unknown>;
26
+ }
27
+ /** The result of `prepareInputs`: rewritten inputs (copy-on-write) plus upload records. */
28
+ export interface PreparedInputs {
29
+ /** A copy of `inputs` with each file-bearing value rewritten to canonical content carrying `pipelex-storage://` in `url`. */
30
+ inputs: Record<string, unknown>;
31
+ /** One record per uploaded asset, exposing `uri`. Pass-through references (http(s), existing storage URIs) produce no record. */
32
+ uploads: UploadRecord[];
33
+ }
34
+ /** The client surface `prepareInputs` needs: raw `upload` plus the `buildInputs` signature source. */
35
+ export interface PrepareCapableClient extends UploadCapableClient {
36
+ buildInputs(request: {
37
+ files: MthdsFileItem[];
38
+ pipe_ref?: string;
39
+ format?: "json";
40
+ explicit?: boolean;
41
+ }): Promise<BuildInputsResponse>;
42
+ }
43
+ /**
44
+ * Prepare a pipe's inputs: upload local/byte/data-URL assets at the signature's
45
+ * file-bearing positions and return copy-on-write rewritten inputs plus upload
46
+ * records. HTTP(S) URLs and existing `pipelex-storage://` URIs pass through
47
+ * unchanged. All failures are raised before any run is created.
48
+ *
49
+ * The declared signature is resolved from the closure; a closure that does not
50
+ * resolve throws {@link InputPreparationError}. No-verdict conditions from the
51
+ * signature route (unknown `pipe_ref`, auth, server fault) surface as the build
52
+ * route's `ApiResponseError`.
53
+ */
54
+ export declare function prepareInputs(client: PrepareCapableClient, request: PrepareInputsRequest): Promise<PreparedInputs>;