@pipelex/sdk 0.24.0 → 0.25.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.
@@ -16,9 +16,17 @@
16
16
  * files — outcomes are merged, any block wins); Vibe reads the stable
17
17
  * `post_tool` payload (`tool_status` gate, path resolved against `cwd`).
18
18
  *
19
+ * A Codex patch run through the shell (`tool_name: "Bash"`) is placed by
20
+ * following the script's working directory. A file it names by a relative
21
+ * path, or by an absolute one no patch command reads, is checked only when it
22
+ * carries the patch's added lines, and one named by another absolute path
23
+ * only when it does not lack them. The relative paths it could not check are
24
+ * named in one non-blocking note, which a block from another file outranks
25
+ * (see docs/hook-bundle.md).
26
+ *
19
27
  * Failure posture (fail-open, per the networked-hook plan):
20
28
  * - no `.mthds` in the payload / unparseable stdin → pass silently
21
- * - WASM engine fails to load → whole hook unavailable → pass silently
29
+ * - WASM engine fails to load → no file is checked; the note above is still sent
22
30
  * - validate unavailable (no `PIPELEX_API_KEY`, network error, timeout, any
23
31
  * non-2xx, bundle-gather overflow) → the local lint/format verdicts already
24
32
  * applied; the validate stage passes silently
@@ -26,9 +34,9 @@
26
34
  * The hook always exits 0; a block/deny is expressed on stdout, never via the
27
35
  * exit code.
28
36
  */
29
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
37
+ import { readFileSync, writeFileSync } from "node:fs";
30
38
  import { resolve as resolvePath } from "node:path";
31
- import { decideAfterLint, decideAfterValidate, encodeOutcome, extractCodexMthdsFiles, extractMthdsFilePath, extractVibeMthdsFilePath, mergeOutcomes, } from "./check-core.js";
39
+ import { decideAfterLint, decideAfterValidate, encodeOutcome, extractCodexMthdsTargets, extractMthdsFilePath, extractVibeMthdsFilePath, mergeOutcomes, selectCodexTargets, uncheckedShellPatchNote, } from "./check-core.js";
32
40
  import { gatherBundle } from "./bundle-gather.js";
33
41
  import { createHookClient } from "./validate-client.js";
34
42
  /** Per-request ceiling on the one network call — well under the hook's overall timeout. */
@@ -51,7 +59,19 @@ function parsePlatform(argv) {
51
59
  }
52
60
  return "claude";
53
61
  }
54
- /** The absolute paths of edited `.mthds` files that exist on disk, per platform. */
62
+ /** A file's content, or null when there is no file to read. */
63
+ function readFileOrNull(filePath) {
64
+ try {
65
+ return readFileSync(filePath, "utf-8");
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ /**
72
+ * The edited `.mthds` files to check, per platform, and the relative paths of
73
+ * a Codex shell patch the hook could not check.
74
+ */
55
75
  function resolveTargets(platform, stdinJson) {
56
76
  let candidates;
57
77
  switch (platform) {
@@ -60,10 +80,8 @@ function resolveTargets(platform, stdinJson) {
60
80
  candidates = filePath ? [filePath] : [];
61
81
  break;
62
82
  }
63
- case "codex": {
64
- candidates = extractCodexMthdsFiles(stdinJson).map((raw) => resolvePath(process.cwd(), raw));
65
- break;
66
- }
83
+ case "codex":
84
+ return selectCodexTargets(extractCodexMthdsTargets(stdinJson, process.cwd()), readFileOrNull);
67
85
  case "vibe": {
68
86
  const extracted = extractVibeMthdsFilePath(stdinJson);
69
87
  candidates = extracted
@@ -72,9 +90,7 @@ function resolveTargets(platform, stdinJson) {
72
90
  break;
73
91
  }
74
92
  }
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));
93
+ return { targets: candidates, unchecked: [] };
78
94
  }
79
95
  /**
80
96
  * Load the WASM engine. The one-line "deprecated parameters" warning the
@@ -154,14 +170,16 @@ function emit(outcome, platform) {
154
170
  function warn(message) {
155
171
  writeFileSync(2, `[mthds-hook] ${message}\n`);
156
172
  }
157
- /** The full pipeline on one edited file: lint → format write-back → validate. */
173
+ /**
174
+ * The full pipeline on one edited file: lint → format write-back → validate.
175
+ * The file is read here, when its turn comes, and no await separates the read
176
+ * from the write-back, so an edit made while an earlier file was validated is
177
+ * never overwritten with older content.
178
+ */
158
179
  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
180
+ const content = readFileOrNull(filePath);
181
+ if (content === null) {
182
+ return { kind: "pass" }; // a deleted file has nothing to check (an edit can race a delete)
165
183
  }
166
184
  // Stage 1 — local lint
167
185
  const lintStage = {
@@ -188,20 +206,19 @@ async function checkOneFile(engine, filePath) {
188
206
  }
189
207
  async function main() {
190
208
  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
- }
209
+ const { targets, unchecked } = resolveTargets(platform, await readStdin());
202
210
  const outcomes = [];
203
- for (const filePath of filePaths) {
204
- outcomes.push(await checkOneFile(engine, filePath));
211
+ if (targets.length > 0) {
212
+ // An engine that cannot load fails the checks open, and only them: the note needs none.
213
+ const engine = await loadEngine().catch(() => null);
214
+ if (engine) {
215
+ for (const target of targets) {
216
+ outcomes.push(await checkOneFile(engine, target));
217
+ }
218
+ }
219
+ }
220
+ if (unchecked.length > 0) {
221
+ outcomes.push(uncheckedShellPatchNote(unchecked));
205
222
  }
206
223
  emit(mergeOutcomes(outcomes), platform);
207
224
  }
@@ -1 +1 @@
1
- {"version":3,"file":"claude-mthds-check.js","sourceRoot":"","sources":["../../src/hooks/claude-mthds-check.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-mthds-check.js","sourceRoot":"","sources":["../../src/hooks/claude-mthds-check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Reader of Codex's `apply_patch` envelope, as sections rather than bare
3
+ * header lines.
4
+ *
5
+ * A patch is `*** Begin Patch`, then one section per file, then `*** End
6
+ * Patch`. A section opens with `*** Add File: <path>`, `*** Update File:
7
+ * <path>` (optionally followed by `*** Move to: <path>`) or `*** Delete File:
8
+ * <path>`, and holds the lines under it until the next header. Its `+` lines
9
+ * are the lines the patch adds, which Codex writes to the file verbatim.
10
+ *
11
+ * The text read may be the patch alone (the `apply_patch` tool) or a whole
12
+ * shell script with the patch inside it (Codex's `Bash` tool), so the reader
13
+ * keeps each section's offset for the caller to place it in the script.
14
+ */
15
+ /** One file's section of a patch. */
16
+ export interface PatchSection {
17
+ kind: "add" | "update" | "delete";
18
+ /** The path as the header wrote it, trimmed. */
19
+ path: string;
20
+ /** The destination of an `Update File` section's `Move to`, or null. */
21
+ moveTo: string | null;
22
+ /** Offset of the section's header line in the text read. */
23
+ offset: number;
24
+ /**
25
+ * How many `*** Begin Patch` and `*** End Patch` lines precede the section:
26
+ * the sections of one envelope share it, and no others do, since an envelope
27
+ * ends on its `End Patch` line even when its `Begin Patch` does not start a
28
+ * line, as in `apply_patch '*** Begin Patch`.
29
+ */
30
+ envelope: number;
31
+ /** The section's `+` lines, marker stripped, otherwise as written. */
32
+ addedLines: string[];
33
+ }
34
+ /** A file the patch leaves on disk. */
35
+ export interface SurvivingFile {
36
+ /** The caller's key for the file. */
37
+ key: string;
38
+ /** The path as the first section leaving the file named it: its own, or its `Move to`. */
39
+ path: string;
40
+ /** Each envelope's last section that leaves the file on disk. */
41
+ sections: PatchSection[];
42
+ /** Some section deletes the file or moves it away, so its absence may be the patch's doing. */
43
+ removedByPatch: boolean;
44
+ }
45
+ /**
46
+ * Every section of every patch envelope in `text`, in order. The recognised
47
+ * headers are anchored at the start of a line, as the `pipelex-plugins`
48
+ * wrapper's pre-filter reads them; a `Move to` counts only inside an `Update
49
+ * File` section, and a `Begin Patch` or `End Patch` line closes the section
50
+ * before it and starts a new envelope, so script lines after a patch are not
51
+ * read as its content, and the patches of a script stay apart.
52
+ */
53
+ export declare function readPatchSections(text: string): PatchSection[];
54
+ /**
55
+ * The `.mthds` files that survive the sections. Within one envelope the
56
+ * sections apply in order and in one directory: an added or updated file
57
+ * becomes a target, a moved file stops being one and its destination becomes
58
+ * one, and a deleted file stops being one. The envelopes of a shell script
59
+ * may run in other directories, in branches, or not at all, so across them a
60
+ * file survives when any envelope leaves it, and a delete in one never hides
61
+ * another's edit. Two paths name the same file when `keyOf` gives them the
62
+ * same key, which lets the caller compare paths resolved against the
63
+ * directory each section was applied in; by default the paths are compared
64
+ * as written.
65
+ */
66
+ export declare function patchTargets(sections: readonly PatchSection[], keyOf?: (path: string, section: PatchSection) => string): SurvivingFile[];
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Reader of Codex's `apply_patch` envelope, as sections rather than bare
3
+ * header lines.
4
+ *
5
+ * A patch is `*** Begin Patch`, then one section per file, then `*** End
6
+ * Patch`. A section opens with `*** Add File: <path>`, `*** Update File:
7
+ * <path>` (optionally followed by `*** Move to: <path>`) or `*** Delete File:
8
+ * <path>`, and holds the lines under it until the next header. Its `+` lines
9
+ * are the lines the patch adds, which Codex writes to the file verbatim.
10
+ *
11
+ * The text read may be the patch alone (the `apply_patch` tool) or a whole
12
+ * shell script with the patch inside it (Codex's `Bash` tool), so the reader
13
+ * keeps each section's offset for the caller to place it in the script.
14
+ */
15
+ const SECTION_HEADER = /^\*\*\* (Add File|Update File|Delete File):\s*(.*?)\s*$/;
16
+ const MOVE_HEADER = /^\*\*\* Move to:\s*(.*?)\s*$/;
17
+ const ENVELOPE_BOUNDARY = /^\*\*\* (Begin|End) Patch\b/;
18
+ const MTHDS_PATH = /.\.mthds$/;
19
+ const SECTION_KINDS = {
20
+ "Add File": "add",
21
+ "Update File": "update",
22
+ "Delete File": "delete",
23
+ };
24
+ /**
25
+ * Every section of every patch envelope in `text`, in order. The recognised
26
+ * headers are anchored at the start of a line, as the `pipelex-plugins`
27
+ * wrapper's pre-filter reads them; a `Move to` counts only inside an `Update
28
+ * File` section, and a `Begin Patch` or `End Patch` line closes the section
29
+ * before it and starts a new envelope, so script lines after a patch are not
30
+ * read as its content, and the patches of a script stay apart.
31
+ */
32
+ export function readPatchSections(text) {
33
+ const sections = [];
34
+ let current = null;
35
+ let envelope = 0;
36
+ let lineStart = 0;
37
+ while (lineStart <= text.length) {
38
+ const newline = text.indexOf("\n", lineStart);
39
+ const lineEnd = newline === -1 ? text.length : newline;
40
+ const line = text.slice(lineStart, lineEnd).replace(/\r$/, "");
41
+ const header = SECTION_HEADER.exec(line);
42
+ const boundary = ENVELOPE_BOUNDARY.exec(line);
43
+ if (header) {
44
+ current = null;
45
+ if (header[2]) {
46
+ current = {
47
+ kind: SECTION_KINDS[header[1]],
48
+ path: header[2],
49
+ moveTo: null,
50
+ offset: lineStart,
51
+ envelope,
52
+ addedLines: [],
53
+ };
54
+ sections.push(current);
55
+ }
56
+ }
57
+ else if (boundary) {
58
+ current = null;
59
+ envelope++;
60
+ }
61
+ else if (current) {
62
+ const move = MOVE_HEADER.exec(line);
63
+ if (move) {
64
+ if (current.kind === "update" && current.moveTo === null && move[1]) {
65
+ current.moveTo = move[1];
66
+ }
67
+ }
68
+ else if (line.startsWith("+")) {
69
+ current.addedLines.push(line.slice(1));
70
+ }
71
+ }
72
+ if (newline === -1) {
73
+ break;
74
+ }
75
+ lineStart = newline + 1;
76
+ }
77
+ return sections;
78
+ }
79
+ /**
80
+ * The `.mthds` files that survive the sections. Within one envelope the
81
+ * sections apply in order and in one directory: an added or updated file
82
+ * becomes a target, a moved file stops being one and its destination becomes
83
+ * one, and a deleted file stops being one. The envelopes of a shell script
84
+ * may run in other directories, in branches, or not at all, so across them a
85
+ * file survives when any envelope leaves it, and a delete in one never hides
86
+ * another's edit. Two paths name the same file when `keyOf` gives them the
87
+ * same key, which lets the caller compare paths resolved against the
88
+ * directory each section was applied in; by default the paths are compared
89
+ * as written.
90
+ */
91
+ export function patchTargets(sections, keyOf = (path) => path) {
92
+ const envelopes = new Map();
93
+ for (const section of sections) {
94
+ envelopes.set(section.envelope, [...(envelopes.get(section.envelope) ?? []), section]);
95
+ }
96
+ const files = new Map();
97
+ const removed = new Set();
98
+ for (const envelope of envelopes.values()) {
99
+ const surviving = new Map();
100
+ for (const section of envelope) {
101
+ const key = keyOf(section.path, section);
102
+ if (section.kind === "delete" || section.moveTo !== null) {
103
+ surviving.delete(key);
104
+ removed.add(key);
105
+ }
106
+ if (section.moveTo !== null) {
107
+ surviving.set(keyOf(section.moveTo, section), { path: section.moveTo, section });
108
+ }
109
+ else if (section.kind !== "delete") {
110
+ surviving.set(key, { path: section.path, section });
111
+ }
112
+ }
113
+ for (const [key, { path, section }] of surviving) {
114
+ const file = files.get(key);
115
+ if (file) {
116
+ file.sections.push(section);
117
+ }
118
+ else {
119
+ files.set(key, { key, path, sections: [section], removedByPatch: false });
120
+ }
121
+ }
122
+ }
123
+ return Array.from(files.values())
124
+ .filter((file) => MTHDS_PATH.test(file.path))
125
+ .map((file) => ({ ...file, removedByPatch: removed.has(file.key) }));
126
+ }
127
+ //# sourceMappingURL=patch-envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-envelope.js","sourceRoot":"","sources":["../../src/hooks/patch-envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * A reading of a POSIX shell script that tells, for an offset in it, which
3
+ * directory the patch command reading that offset runs in.
4
+ *
5
+ * Codex reports a patch run through the shell as a `Bash` call carrying the
6
+ * whole script, and a relative path in that patch is relative to wherever the
7
+ * script had moved when `apply_patch` ran. This module lexes the script far
8
+ * enough to follow `cd`: commands, quotes, heredocs, substitutions, scopes,
9
+ * branches and loops. It is not a shell parser. Past what it reads, it
10
+ * answers "unknown" rather than guessing, and a script it cannot lex at all
11
+ * is "unparsed".
12
+ *
13
+ * - Text is placed only where a patch command reads it: the words and
14
+ * heredoc bodies of an `apply_patch` command, and the text of a command
15
+ * feeding one through a pipeline or a substitution in its words. Text that
16
+ * any other command holds, such as a variable, a file, `bash -c` or `eval`,
17
+ * is unknown, since this reading does not follow whatever reads it later.
18
+ * - `cd DIR` with one literal operand (optionally after `-L`, `-P` or `--`)
19
+ * moves the directory, and is assumed to succeed; any other `cd`, and
20
+ * `pushd`, `popd`, `eval`, `source`, `.` or a function definition, makes
21
+ * it unknown. An absolute `cd` makes an unknown directory known again.
22
+ * - The reading follows the path on which each command succeeds, so a
23
+ * negated `cd` fails on it. What runs only on the other path (after `||`,
24
+ * in `elif` and `else`, after a negated `cd` and `&&`, and on the path a
25
+ * loop's condition takes to end or skip it) starts where the shell stood
26
+ * when nothing had moved it, and from an unknown directory otherwise.
27
+ * - `( … )`, `$( … )`, `<( … )` and `>( … )` are scopes: a `cd` inside one
28
+ * ends at its closing parenthesis. A list sent to the background, and every
29
+ * member of a pipeline but the last, run in subshells in bash and zsh
30
+ * alike. zsh runs a pipeline's last member in the current shell and bash
31
+ * does not, so a directory change there makes the directory after it
32
+ * unknown.
33
+ * - `{ … }` and the separators `;`, newline and `&&` are followed in order.
34
+ * Where only one of several paths runs, after `||`, between the branches of
35
+ * `if` and `case`, and across the passes of a loop, the directory is kept
36
+ * when every path leaves it the same, and is unknown otherwise.
37
+ * - Heredoc bodies, quoted strings, comments and the expression of a `[[ … ]]`
38
+ * are never read as commands. A heredoc body belongs to the command that
39
+ * opened it.
40
+ * - The text a command reads is the script's after the shell's quoting, which
41
+ * the reading also tells: a patch in double quotes or in an unquoted heredoc
42
+ * has its backslash escapes removed and its `$` and backtick expansions run.
43
+ */
44
+ /** Where the patch command reading an offset runs. */
45
+ export type Placement = {
46
+ kind: "directory";
47
+ path: string;
48
+ }
49
+ /** A patch command reads the offset from somewhere this reading cannot follow. */
50
+ | {
51
+ kind: "unknown";
52
+ }
53
+ /** A command holds the offset, and no patch command reads it: a variable, a file, `bash -c`. */
54
+ | {
55
+ kind: "unread";
56
+ }
57
+ /** No command holds the offset: it is in a comment or between commands. */
58
+ | {
59
+ kind: "outside";
60
+ };
61
+ /** How the shell turns a stretch of the script into the text a command reads. */
62
+ export type Quoting =
63
+ /** As written: in a quoted heredoc, or plain. */
64
+ "verbatim"
65
+ /** In single quotes: as written, up to the `'` that closes them. */
66
+ | "single-quoted"
67
+ /** In double quotes: a backslash escapes `$`, a backtick, `"` or itself, and `$` and backticks expand. */
68
+ | "double-quoted"
69
+ /** In an unquoted heredoc: a backslash escapes `$`, a backtick or itself, and `$` and backticks expand. */
70
+ | "heredoc";
71
+ /** A script that could be lexed, able to place any offset in it. */
72
+ export interface ShellReading {
73
+ directoryAt(offset: number): Placement;
74
+ quotingAt(offset: number): Quoting;
75
+ }
76
+ /**
77
+ * Read `script` as a POSIX shell script run from `sessionDir`, or return
78
+ * `"unparsed"` when it holds an unterminated quote, substitution or backtick,
79
+ * a heredoc inside backticks, a parenthesis that closes nothing, or any other
80
+ * syntax error this reading can see.
81
+ */
82
+ export declare function readShellScript(script: string, sessionDir: string): ShellReading | "unparsed";
83
+ /**
84
+ * The lines of a patch section as the patch command reads them, given the
85
+ * quoting its header is in, less any line an expansion makes unknown. A line
86
+ * in quotes may close them and open others, as `'\''` writes an apostrophe in
87
+ * single quotes, and is read through each. When a line ends in other quoting
88
+ * than it began in, or in a backslash that joins it to the next, the lines
89
+ * after it are read in quoting this reading does not follow, so no line of
90
+ * the section is known and none is given.
91
+ */
92
+ export declare function linesAsRead(lines: readonly string[], quoting: Quoting): string[];