@pipelex/sdk 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +99 -9
- package/dist/client.js +136 -16
- package/dist/client.js.map +1 -1
- package/dist/hooks/bundle-gather.d.ts +31 -0
- package/dist/hooks/bundle-gather.js +92 -0
- package/dist/hooks/bundle-gather.js.map +1 -0
- package/dist/hooks/check-core.d.ts +111 -0
- package/dist/hooks/check-core.js +224 -0
- package/dist/hooks/check-core.js.map +1 -0
- package/dist/hooks/claude-mthds-check.d.ts +29 -0
- package/dist/hooks/claude-mthds-check.js +220 -0
- package/dist/hooks/claude-mthds-check.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +170 -13
- package/package.json +6 -2
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-agnostic core of the `.mthds` PostToolUse hook: the per-stage verdict
|
|
3
|
+
* shapes and the mapping from verdicts to the hook's decision output.
|
|
4
|
+
*
|
|
5
|
+
* The three stages (lint, format, validate) are swappable engines — local WASM
|
|
6
|
+
* today, `client.lint`/`client.format` as the documented fallback, MCP calls
|
|
7
|
+
* later. Nothing in this module knows which engine produced a verdict; it only
|
|
8
|
+
* maps verdict → decision, mirroring the Stage-3 model of the plxt-era hook:
|
|
9
|
+
*
|
|
10
|
+
* - lint diagnostics → BLOCK (agent fixes the file)
|
|
11
|
+
* - validate `is_valid: false` → BLOCK (input-domain by construction: over the
|
|
12
|
+
* API a produced verdict is always a 200; server/config faults are non-2xx =
|
|
13
|
+
* no verdict = unavailable)
|
|
14
|
+
* - validate valid + pending `PipeSignature`s → non-blocking additionalContext
|
|
15
|
+
* - any stage unavailable → fail-open (the other stages' verdicts stand)
|
|
16
|
+
*/
|
|
17
|
+
import type { Diagnostic, ValidationErrorItem } from "../models.js";
|
|
18
|
+
/** Verdict of the local lint stage. `unavailable` = engine failed to load. */
|
|
19
|
+
export type LintStage = {
|
|
20
|
+
status: "clean";
|
|
21
|
+
} | {
|
|
22
|
+
status: "diagnostics";
|
|
23
|
+
diagnostics: Diagnostic[];
|
|
24
|
+
} | {
|
|
25
|
+
status: "unavailable";
|
|
26
|
+
};
|
|
27
|
+
/** Verdict of the networked validate stage. `unavailable` = no verdict could be produced. */
|
|
28
|
+
export type ValidateStage = {
|
|
29
|
+
status: "valid";
|
|
30
|
+
pendingSignatures: string[];
|
|
31
|
+
} | {
|
|
32
|
+
status: "invalid";
|
|
33
|
+
message?: string;
|
|
34
|
+
validationErrors: ValidationErrorItem[];
|
|
35
|
+
renderedMarkdown?: string;
|
|
36
|
+
} | {
|
|
37
|
+
status: "unavailable";
|
|
38
|
+
};
|
|
39
|
+
/** The hook's decision, prior to JSON encoding. */
|
|
40
|
+
export type HookOutcome = {
|
|
41
|
+
kind: "pass";
|
|
42
|
+
} | {
|
|
43
|
+
kind: "block";
|
|
44
|
+
reason: string;
|
|
45
|
+
} | {
|
|
46
|
+
kind: "context";
|
|
47
|
+
context: string;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Which harness invoked the hook. Claude and Codex share the block /
|
|
51
|
+
* `hookSpecificOutput` stdout protocol; Mistral Vibe speaks
|
|
52
|
+
* deny / `hook_specific_output.additional_context`.
|
|
53
|
+
*/
|
|
54
|
+
export type HookPlatform = "claude" | "codex" | "vibe";
|
|
55
|
+
/**
|
|
56
|
+
* Extract the edited `.mthds` path from the Claude PostToolUse stdin payload;
|
|
57
|
+
* null = not this hook's business (fail open, mirroring the plxt-era hook,
|
|
58
|
+
* which also passed silently on unparseable input).
|
|
59
|
+
*/
|
|
60
|
+
export declare function extractMthdsFilePath(stdinJson: string): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Extract every distinct `.mthds` path from a Codex PostToolUse(apply_patch)
|
|
63
|
+
* payload. `apply_patch` is Codex's freeform multi-file write tool: the patch
|
|
64
|
+
* envelope rides verbatim in `tool_input.command`, and the touched files are
|
|
65
|
+
* its `*** Update File: / *** Add File: / *** Move to:` headers (`Delete
|
|
66
|
+
* File:` and `Move from:` are skipped — the file no longer exists post-patch).
|
|
67
|
+
* Mirrors `mthds-agent codex hook`'s parser. Paths come back as written in
|
|
68
|
+
* the envelope (usually cwd-relative); the caller resolves and existence-checks.
|
|
69
|
+
*/
|
|
70
|
+
export declare function extractCodexMthdsFiles(stdinJson: string): string[];
|
|
71
|
+
/**
|
|
72
|
+
* Extract the edited `.mthds` path from a Mistral Vibe AfterToolInvocation
|
|
73
|
+
* payload, plus the cwd to resolve it against. Only successful tool calls
|
|
74
|
+
* count (`tool_status: "success"`); the path rides in `tool_output.file` /
|
|
75
|
+
* `tool_output.path` / `tool_input.file_path` / `tool_input.path` — the same
|
|
76
|
+
* fallback chain as the plxt-era Vibe hook.
|
|
77
|
+
*/
|
|
78
|
+
export declare function extractVibeMthdsFilePath(stdinJson: string): {
|
|
79
|
+
filePath: string;
|
|
80
|
+
cwd?: string;
|
|
81
|
+
} | null;
|
|
82
|
+
/**
|
|
83
|
+
* Merge per-file outcomes (Codex's `apply_patch` can touch several `.mthds`
|
|
84
|
+
* files in one call) into the single decision the hook emits: any block wins
|
|
85
|
+
* (reasons joined), else contexts are joined, else pass.
|
|
86
|
+
*/
|
|
87
|
+
export declare function mergeOutcomes(outcomes: HookOutcome[]): HookOutcome;
|
|
88
|
+
export declare function truncate(text: string): string;
|
|
89
|
+
/**
|
|
90
|
+
* Map the lint verdict to a decision. Every engine diagnostic is an error by
|
|
91
|
+
* construction (the shared Rust engine emits `severity: "error"` only), so any
|
|
92
|
+
* diagnostic blocks — the same bar as `plxt lint`'s non-zero exit.
|
|
93
|
+
*/
|
|
94
|
+
export declare function decideAfterLint(filePath: string, lint: LintStage): HookOutcome;
|
|
95
|
+
/**
|
|
96
|
+
* Map the validate verdict to a decision.
|
|
97
|
+
*
|
|
98
|
+
* Invalid blocks with the server-rendered Markdown verbatim when present (the
|
|
99
|
+
* workspace's "surface output conventions": the wire is JSON, the agent reads
|
|
100
|
+
* Markdown), falling back to a client-side rendering of `validation_errors[]`.
|
|
101
|
+
* Valid passes, with a non-blocking nudge listing still-unimplemented
|
|
102
|
+
* `PipeSignature`s. Unavailable passes silently — the local lint/format
|
|
103
|
+
* verdicts already applied.
|
|
104
|
+
*/
|
|
105
|
+
export declare function decideAfterValidate(filePath: string, validate: ValidateStage): HookOutcome;
|
|
106
|
+
/**
|
|
107
|
+
* Encode an outcome as the harness's stdout payload. `pass` is empty output;
|
|
108
|
+
* the hook always exits 0. Claude and Codex share the block /
|
|
109
|
+
* `hookSpecificOutput` protocol; Vibe speaks deny / `hook_specific_output`.
|
|
110
|
+
*/
|
|
111
|
+
export declare function encodeOutcome(outcome: HookOutcome, platform?: HookPlatform): string;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-agnostic core of the `.mthds` PostToolUse hook: the per-stage verdict
|
|
3
|
+
* shapes and the mapping from verdicts to the hook's decision output.
|
|
4
|
+
*
|
|
5
|
+
* The three stages (lint, format, validate) are swappable engines — local WASM
|
|
6
|
+
* today, `client.lint`/`client.format` as the documented fallback, MCP calls
|
|
7
|
+
* later. Nothing in this module knows which engine produced a verdict; it only
|
|
8
|
+
* maps verdict → decision, mirroring the Stage-3 model of the plxt-era hook:
|
|
9
|
+
*
|
|
10
|
+
* - lint diagnostics → BLOCK (agent fixes the file)
|
|
11
|
+
* - validate `is_valid: false` → BLOCK (input-domain by construction: over the
|
|
12
|
+
* API a produced verdict is always a 200; server/config faults are non-2xx =
|
|
13
|
+
* no verdict = unavailable)
|
|
14
|
+
* - validate valid + pending `PipeSignature`s → non-blocking additionalContext
|
|
15
|
+
* - any stage unavailable → fail-open (the other stages' verdicts stand)
|
|
16
|
+
*/
|
|
17
|
+
function parseJsonOrNull(stdinJson) {
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(stdinJson);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null; // fail open on unparseable input, mirroring the plxt-era hooks
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract the edited `.mthds` path from the Claude PostToolUse stdin payload;
|
|
27
|
+
* null = not this hook's business (fail open, mirroring the plxt-era hook,
|
|
28
|
+
* which also passed silently on unparseable input).
|
|
29
|
+
*/
|
|
30
|
+
export function extractMthdsFilePath(stdinJson) {
|
|
31
|
+
const parsed = parseJsonOrNull(stdinJson);
|
|
32
|
+
const filePath = parsed?.tool_input
|
|
33
|
+
?.file_path;
|
|
34
|
+
if (typeof filePath !== "string" || !filePath.endsWith(".mthds")) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return filePath;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Extract every distinct `.mthds` path from a Codex PostToolUse(apply_patch)
|
|
41
|
+
* payload. `apply_patch` is Codex's freeform multi-file write tool: the patch
|
|
42
|
+
* envelope rides verbatim in `tool_input.command`, and the touched files are
|
|
43
|
+
* its `*** Update File: / *** Add File: / *** Move to:` headers (`Delete
|
|
44
|
+
* File:` and `Move from:` are skipped — the file no longer exists post-patch).
|
|
45
|
+
* Mirrors `mthds-agent codex hook`'s parser. Paths come back as written in
|
|
46
|
+
* the envelope (usually cwd-relative); the caller resolves and existence-checks.
|
|
47
|
+
*/
|
|
48
|
+
export function extractCodexMthdsFiles(stdinJson) {
|
|
49
|
+
const parsed = parseJsonOrNull(stdinJson);
|
|
50
|
+
const command = parsed?.tool_input?.command;
|
|
51
|
+
if (typeof command !== "string") {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const headerRe = /^\*\*\* (?:Update File|Add File|Move to):\s*(.+\.mthds)\s*$/gm;
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
let match;
|
|
57
|
+
while ((match = headerRe.exec(command)) !== null) {
|
|
58
|
+
seen.add(match[1].trim());
|
|
59
|
+
}
|
|
60
|
+
return Array.from(seen);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Extract the edited `.mthds` path from a Mistral Vibe AfterToolInvocation
|
|
64
|
+
* payload, plus the cwd to resolve it against. Only successful tool calls
|
|
65
|
+
* count (`tool_status: "success"`); the path rides in `tool_output.file` /
|
|
66
|
+
* `tool_output.path` / `tool_input.file_path` / `tool_input.path` — the same
|
|
67
|
+
* fallback chain as the plxt-era Vibe hook.
|
|
68
|
+
*/
|
|
69
|
+
export function extractVibeMthdsFilePath(stdinJson) {
|
|
70
|
+
const parsed = parseJsonOrNull(stdinJson);
|
|
71
|
+
if (!parsed || parsed.tool_status !== "success") {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
const candidates = [
|
|
75
|
+
parsed.tool_output?.file,
|
|
76
|
+
parsed.tool_output?.path,
|
|
77
|
+
parsed.tool_input?.file_path,
|
|
78
|
+
parsed.tool_input?.path,
|
|
79
|
+
];
|
|
80
|
+
const filePath = candidates.find((value) => typeof value === "string" && value.endsWith(".mthds"));
|
|
81
|
+
if (!filePath) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return { filePath, cwd: typeof parsed.cwd === "string" ? parsed.cwd : undefined };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Merge per-file outcomes (Codex's `apply_patch` can touch several `.mthds`
|
|
88
|
+
* files in one call) into the single decision the hook emits: any block wins
|
|
89
|
+
* (reasons joined), else contexts are joined, else pass.
|
|
90
|
+
*/
|
|
91
|
+
export function mergeOutcomes(outcomes) {
|
|
92
|
+
const blocks = outcomes.filter((outcome) => outcome.kind === "block");
|
|
93
|
+
if (blocks.length > 0) {
|
|
94
|
+
return { kind: "block", reason: truncate(blocks.map((block) => block.reason).join("\n\n")) };
|
|
95
|
+
}
|
|
96
|
+
const contexts = outcomes.filter((outcome) => outcome.kind === "context");
|
|
97
|
+
if (contexts.length > 0) {
|
|
98
|
+
return {
|
|
99
|
+
kind: "context",
|
|
100
|
+
context: truncate(contexts.map((context) => context.context).join("\n\n")),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return { kind: "pass" };
|
|
104
|
+
}
|
|
105
|
+
/** Cap on emitted reason/context bodies — same guard as the plxt-era hook. */
|
|
106
|
+
const MAX_OUTPUT_CHARS = 9500;
|
|
107
|
+
export function truncate(text) {
|
|
108
|
+
if (text.length <= MAX_OUTPUT_CHARS) {
|
|
109
|
+
return text;
|
|
110
|
+
}
|
|
111
|
+
const omitted = text.length - MAX_OUTPUT_CHARS;
|
|
112
|
+
return `${text.slice(0, MAX_OUTPUT_CHARS)}\n\n[truncated, ${omitted} chars omitted]`;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* One diagnostic as an agent-actionable line: severity, locators, message.
|
|
116
|
+
* `location` and `range` are independent — a schema/semantic diagnostic can name
|
|
117
|
+
* its target (a pipe, a concept) without a byte span, so both render when present.
|
|
118
|
+
*/
|
|
119
|
+
function renderDiagnosticLine(diagnostic) {
|
|
120
|
+
const locators = [
|
|
121
|
+
diagnostic.location,
|
|
122
|
+
diagnostic.range && `line ${diagnostic.range.start_line}, col ${diagnostic.range.start_col}`,
|
|
123
|
+
].filter(Boolean);
|
|
124
|
+
const span = locators.length > 0 ? ` (${locators.join(", ")})` : "";
|
|
125
|
+
return `- [${diagnostic.kind}/${diagnostic.severity}] ${diagnostic.message}${span}`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Map the lint verdict to a decision. Every engine diagnostic is an error by
|
|
129
|
+
* construction (the shared Rust engine emits `severity: "error"` only), so any
|
|
130
|
+
* diagnostic blocks — the same bar as `plxt lint`'s non-zero exit.
|
|
131
|
+
*/
|
|
132
|
+
export function decideAfterLint(filePath, lint) {
|
|
133
|
+
if (lint.status !== "diagnostics" || lint.diagnostics.length === 0) {
|
|
134
|
+
return { kind: "pass" };
|
|
135
|
+
}
|
|
136
|
+
const lines = [
|
|
137
|
+
`MTHDS lint errors in ${filePath}:`,
|
|
138
|
+
"",
|
|
139
|
+
...lint.diagnostics.map(renderDiagnosticLine),
|
|
140
|
+
];
|
|
141
|
+
return { kind: "block", reason: truncate(lines.join("\n")) };
|
|
142
|
+
}
|
|
143
|
+
/** One validation error with its locators — mirror of the plxt-era rendering. */
|
|
144
|
+
function renderValidationErrorLine(item) {
|
|
145
|
+
const locators = [
|
|
146
|
+
item.pipe_code && `pipe ${item.pipe_code}`,
|
|
147
|
+
item.concept_code && `concept ${item.concept_code}`,
|
|
148
|
+
item.field_name && `field ${item.field_name}`,
|
|
149
|
+
item.source && `source ${item.source}`,
|
|
150
|
+
]
|
|
151
|
+
.filter(Boolean)
|
|
152
|
+
.join(", ");
|
|
153
|
+
return `- [${item.category ?? "error"}] ${item.message ?? ""}${locators ? ` (${locators})` : ""}`;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Map the validate verdict to a decision.
|
|
157
|
+
*
|
|
158
|
+
* Invalid blocks with the server-rendered Markdown verbatim when present (the
|
|
159
|
+
* workspace's "surface output conventions": the wire is JSON, the agent reads
|
|
160
|
+
* Markdown), falling back to a client-side rendering of `validation_errors[]`.
|
|
161
|
+
* Valid passes, with a non-blocking nudge listing still-unimplemented
|
|
162
|
+
* `PipeSignature`s. Unavailable passes silently — the local lint/format
|
|
163
|
+
* verdicts already applied.
|
|
164
|
+
*/
|
|
165
|
+
export function decideAfterValidate(filePath, validate) {
|
|
166
|
+
switch (validate.status) {
|
|
167
|
+
case "unavailable":
|
|
168
|
+
return { kind: "pass" };
|
|
169
|
+
case "valid": {
|
|
170
|
+
if (validate.pendingSignatures.length === 0) {
|
|
171
|
+
return { kind: "pass" };
|
|
172
|
+
}
|
|
173
|
+
const context = "Bundle is valid but not yet runnable. Signatures still unimplemented (PipeSignature placeholders): " +
|
|
174
|
+
validate.pendingSignatures.join(", ") +
|
|
175
|
+
". They mock their output on dry-run; implement them before running the method for real.";
|
|
176
|
+
return { kind: "context", context: truncate(context) };
|
|
177
|
+
}
|
|
178
|
+
case "invalid": {
|
|
179
|
+
if (validate.renderedMarkdown) {
|
|
180
|
+
return { kind: "block", reason: truncate(validate.renderedMarkdown) };
|
|
181
|
+
}
|
|
182
|
+
const lines = [
|
|
183
|
+
`Validation failed for ${filePath}:`,
|
|
184
|
+
"",
|
|
185
|
+
validate.message || "Bundle is invalid.",
|
|
186
|
+
];
|
|
187
|
+
if (validate.validationErrors.length > 0) {
|
|
188
|
+
lines.push("");
|
|
189
|
+
lines.push(...validate.validationErrors.map(renderValidationErrorLine));
|
|
190
|
+
}
|
|
191
|
+
return { kind: "block", reason: truncate(lines.join("\n")) };
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Encode an outcome as the harness's stdout payload. `pass` is empty output;
|
|
197
|
+
* the hook always exits 0. Claude and Codex share the block /
|
|
198
|
+
* `hookSpecificOutput` protocol; Vibe speaks deny / `hook_specific_output`.
|
|
199
|
+
*/
|
|
200
|
+
export function encodeOutcome(outcome, platform = "claude") {
|
|
201
|
+
switch (outcome.kind) {
|
|
202
|
+
case "pass":
|
|
203
|
+
return "";
|
|
204
|
+
case "block":
|
|
205
|
+
if (platform === "vibe") {
|
|
206
|
+
return JSON.stringify({ decision: "deny", reason: outcome.reason }) + "\n";
|
|
207
|
+
}
|
|
208
|
+
return JSON.stringify({ decision: "block", reason: outcome.reason }) + "\n";
|
|
209
|
+
case "context":
|
|
210
|
+
if (platform === "vibe") {
|
|
211
|
+
return (JSON.stringify({
|
|
212
|
+
decision: "allow",
|
|
213
|
+
hook_specific_output: { additional_context: outcome.context },
|
|
214
|
+
}) + "\n");
|
|
215
|
+
}
|
|
216
|
+
return (JSON.stringify({
|
|
217
|
+
hookSpecificOutput: {
|
|
218
|
+
hookEventName: "PostToolUse",
|
|
219
|
+
additionalContext: outcome.context,
|
|
220
|
+
},
|
|
221
|
+
}) + "\n");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=check-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-core.js","sourceRoot":"","sources":["../../src/hooks/check-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
|
17
|
+
* AfterToolInvocation 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
|
|
17
|
+
* AfterToolInvocation 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,12 +7,12 @@
|
|
|
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.
|
|
10
|
+
export declare const SDK_VERSION = "0.4.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 { 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
16
|
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
17
|
export { isTerminalRunStatus, isSuccessRunStatus } from "./runs.js";
|
|
18
18
|
export type { RunStatus, RunPublic, RunRead, RunResults, RunResultState, WaitForResultOptions, } from "./runs.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.
|
|
10
|
+
export const SDK_VERSION = "0.4.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
|
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;
|
|
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;AAyE3D,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"}
|