taskflow-core 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/build-info.json +2 -2
  2. package/dist/compile.d.ts +8 -1
  3. package/dist/compile.d.ts.map +1 -1
  4. package/dist/compile.js +75 -9
  5. package/dist/compile.js.map +1 -1
  6. package/dist/exec/driver.d.ts +5 -0
  7. package/dist/exec/driver.d.ts.map +1 -1
  8. package/dist/exec/driver.js +96 -52
  9. package/dist/exec/driver.js.map +1 -1
  10. package/dist/exec/kernel-policy.d.ts.map +1 -1
  11. package/dist/exec/kernel-policy.js +20 -20
  12. package/dist/exec/kernel-policy.js.map +1 -1
  13. package/dist/exec/step-kinds.d.ts.map +1 -1
  14. package/dist/exec/step-kinds.js +59 -22
  15. package/dist/exec/step-kinds.js.map +1 -1
  16. package/dist/exec/step.d.ts.map +1 -1
  17. package/dist/exec/step.js +44 -10
  18. package/dist/exec/step.js.map +1 -1
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +1 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/runtime.d.ts +13 -0
  24. package/dist/runtime.d.ts.map +1 -1
  25. package/dist/runtime.js +60 -4
  26. package/dist/runtime.js.map +1 -1
  27. package/dist/verifiers/discover.d.ts +44 -0
  28. package/dist/verifiers/discover.d.ts.map +1 -0
  29. package/dist/verifiers/discover.js +152 -0
  30. package/dist/verifiers/discover.js.map +1 -0
  31. package/dist/verifiers/index.d.ts +12 -0
  32. package/dist/verifiers/index.d.ts.map +1 -0
  33. package/dist/verifiers/index.js +12 -0
  34. package/dist/verifiers/index.js.map +1 -0
  35. package/dist/verifiers/script-lint.d.ts +24 -0
  36. package/dist/verifiers/script-lint.d.ts.map +1 -0
  37. package/dist/verifiers/script-lint.js +311 -0
  38. package/dist/verifiers/script-lint.js.map +1 -0
  39. package/dist/verify.d.ts +55 -3
  40. package/dist/verify.d.ts.map +1 -1
  41. package/dist/verify.js +201 -2
  42. package/dist/verify.js.map +1 -1
  43. package/package.json +1 -1
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Verifier discovery — convention-based loading of project-local verifiers.
3
+ *
4
+ * Discovers verifier modules from `.pi/taskflows/verifiers/` (project scope)
5
+ * and `~/.pi/taskflows/verifiers/` (user scope). Each `.ts` or `.js` file in
6
+ * the directory is dynamically imported; its default export (or named
7
+ * `verifier` / `verifiers` export) is collected. Project-scope verifiers
8
+ * shadow user-scope verifiers with the same `name`.
9
+ *
10
+ * This is the minimum-viable discovery deferred by #82: convention dir, no
11
+ * config file, no registry. Programmatic registration via
12
+ * `verifyTaskflow(flow, { verifiers })` always takes precedence.
13
+ *
14
+ * Discovery is async (dynamic import) and fail-open: a broken verifier module
15
+ * is skipped with a warning, never crashes the host.
16
+ */
17
+ import type { TaskflowVerifier } from "../verify.ts";
18
+ export interface DiscoveredVerifiers {
19
+ /** All discovered verifiers, project-scope shadowing user-scope by name. */
20
+ verifiers: TaskflowVerifier[];
21
+ /** Warnings for modules that failed to load or had no valid exports. */
22
+ warnings: string[];
23
+ /** Directories that were scanned. */
24
+ dirs: string[];
25
+ }
26
+ /**
27
+ * Discover project-local and user-scope verifiers from the convention
28
+ * directories. Fail-open: broken modules are skipped with a warning.
29
+ *
30
+ * Project-scope verifiers shadow user-scope verifiers with the same `name`.
31
+ * Within a scope, files are loaded in sorted order; later files do NOT shadow
32
+ * earlier ones with the same name (first wins within a scope).
33
+ */
34
+ export declare function discoverVerifiers(cwd: string): Promise<DiscoveredVerifiers>;
35
+ /**
36
+ * Synchronous variant: discovers verifier files but does NOT import them
37
+ * (import is async). Returns the file paths that would be loaded, for
38
+ * diagnostics / `--list-verifiers` style commands.
39
+ */
40
+ export declare function listVerifierPaths(cwd: string): {
41
+ project: string[];
42
+ user: string[];
43
+ };
44
+ //# sourceMappingURL=discover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../../src/verifiers/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AA2ErD,MAAM,WAAW,mBAAmB;IACnC,4EAA4E;IAC5E,SAAS,EAAE,gBAAgB,EAAE,CAAC;IAC9B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,qCAAqC;IACrC,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAoCjF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAMpF"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Verifier discovery — convention-based loading of project-local verifiers.
3
+ *
4
+ * Discovers verifier modules from `.pi/taskflows/verifiers/` (project scope)
5
+ * and `~/.pi/taskflows/verifiers/` (user scope). Each `.ts` or `.js` file in
6
+ * the directory is dynamically imported; its default export (or named
7
+ * `verifier` / `verifiers` export) is collected. Project-scope verifiers
8
+ * shadow user-scope verifiers with the same `name`.
9
+ *
10
+ * This is the minimum-viable discovery deferred by #82: convention dir, no
11
+ * config file, no registry. Programmatic registration via
12
+ * `verifyTaskflow(flow, { verifiers })` always takes precedence.
13
+ *
14
+ * Discovery is async (dynamic import) and fail-open: a broken verifier module
15
+ * is skipped with a warning, never crashes the host.
16
+ */
17
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
18
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
19
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
20
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
21
+ });
22
+ }
23
+ return path;
24
+ };
25
+ import * as fs from "node:fs";
26
+ import * as os from "node:os";
27
+ import * as path from "node:path";
28
+ /** The convention directory name under `.pi/taskflows/`. */
29
+ const VERIFIERS_DIR = "verifiers";
30
+ /** Find the project-scope verifiers directory (walk-up, same as flows). */
31
+ function findProjectVerifiersDir(cwd) {
32
+ const home = os.homedir();
33
+ let dir = cwd;
34
+ while (true) {
35
+ if (dir !== home) {
36
+ const candidate = path.join(dir, ".pi", "taskflows", VERIFIERS_DIR);
37
+ if (fs.existsSync(candidate))
38
+ return candidate;
39
+ }
40
+ const parent = path.dirname(dir);
41
+ if (parent === dir)
42
+ break;
43
+ dir = parent;
44
+ }
45
+ return null;
46
+ }
47
+ /** The user-scope verifiers directory. */
48
+ function userVerifiersDir() {
49
+ return path.join(os.homedir(), ".pi", "taskflows", VERIFIERS_DIR);
50
+ }
51
+ /** List verifier files in a directory (`.ts` and `.js`, sorted). */
52
+ function listVerifierFiles(dir) {
53
+ if (!fs.existsSync(dir))
54
+ return [];
55
+ return fs
56
+ .readdirSync(dir)
57
+ .filter((f) => /\.(ts|js|mjs)$/.test(f) && !f.startsWith("."))
58
+ .sort()
59
+ .map((f) => path.join(dir, f));
60
+ }
61
+ /** Extract verifiers from a dynamically imported module. */
62
+ function extractVerifiers(mod) {
63
+ if (!mod || typeof mod !== "object")
64
+ return [];
65
+ const m = mod;
66
+ const result = [];
67
+ // default export: single verifier or array
68
+ if (m.default) {
69
+ if (Array.isArray(m.default)) {
70
+ for (const v of m.default) {
71
+ if (isVerifier(v))
72
+ result.push(v);
73
+ }
74
+ }
75
+ else if (isVerifier(m.default)) {
76
+ result.push(m.default);
77
+ }
78
+ }
79
+ // named `verifier` export: single verifier
80
+ if (m.verifier && isVerifier(m.verifier)) {
81
+ result.push(m.verifier);
82
+ }
83
+ // named `verifiers` export: array
84
+ if (Array.isArray(m.verifiers)) {
85
+ for (const v of m.verifiers) {
86
+ if (isVerifier(v))
87
+ result.push(v);
88
+ }
89
+ }
90
+ return result;
91
+ }
92
+ /** Shape-check a value as a TaskflowVerifier. */
93
+ function isVerifier(v) {
94
+ if (!v || typeof v !== "object")
95
+ return false;
96
+ const obj = v;
97
+ return typeof obj.name === "string" && typeof obj.verify === "function";
98
+ }
99
+ /**
100
+ * Discover project-local and user-scope verifiers from the convention
101
+ * directories. Fail-open: broken modules are skipped with a warning.
102
+ *
103
+ * Project-scope verifiers shadow user-scope verifiers with the same `name`.
104
+ * Within a scope, files are loaded in sorted order; later files do NOT shadow
105
+ * earlier ones with the same name (first wins within a scope).
106
+ */
107
+ export async function discoverVerifiers(cwd) {
108
+ const warnings = [];
109
+ const dirs = [];
110
+ const byName = new Map();
111
+ // Load user-scope first (lower priority), then project-scope (shadows).
112
+ const userDir = userVerifiersDir();
113
+ const projectDir = findProjectVerifiersDir(cwd);
114
+ for (const [scope, dir] of [["user", userDir], ["project", projectDir]]) {
115
+ if (!dir || !fs.existsSync(dir))
116
+ continue;
117
+ dirs.push(dir);
118
+ for (const file of listVerifierFiles(dir)) {
119
+ try {
120
+ // Dynamic import with file:// URL for ESM compatibility.
121
+ const mod = await import(__rewriteRelativeImportExtension(`file://${file}`));
122
+ const extracted = extractVerifiers(mod);
123
+ if (extracted.length === 0) {
124
+ warnings.push(`${scope} verifier ${path.basename(file)}: no valid TaskflowVerifier export found`);
125
+ continue;
126
+ }
127
+ for (const v of extracted) {
128
+ if (scope === "project" || !byName.has(v.name)) {
129
+ byName.set(v.name, v);
130
+ }
131
+ }
132
+ }
133
+ catch (e) {
134
+ warnings.push(`${scope} verifier ${path.basename(file)}: failed to load (${e instanceof Error ? e.message : String(e)})`);
135
+ }
136
+ }
137
+ }
138
+ return { verifiers: [...byName.values()], warnings, dirs };
139
+ }
140
+ /**
141
+ * Synchronous variant: discovers verifier files but does NOT import them
142
+ * (import is async). Returns the file paths that would be loaded, for
143
+ * diagnostics / `--list-verifiers` style commands.
144
+ */
145
+ export function listVerifierPaths(cwd) {
146
+ const projectDir = findProjectVerifiersDir(cwd);
147
+ return {
148
+ project: projectDir ? listVerifierFiles(projectDir) : [],
149
+ user: listVerifierFiles(userVerifiersDir()),
150
+ };
151
+ }
152
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/verifiers/discover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Built-in verifiers barrel.
3
+ *
4
+ * Re-exports the shipped verifiers so hosts can import them from one place:
5
+ * import { scriptLintVerifier, builtinVerifiers } from "taskflow-core/verifiers";
6
+ */
7
+ export { scriptLintVerifier } from "./script-lint.ts";
8
+ export { discoverVerifiers, listVerifierPaths, type DiscoveredVerifiers } from "./discover.ts";
9
+ import type { TaskflowVerifier } from "../verify.ts";
10
+ /** All built-in verifiers, in recommended registration order. */
11
+ export declare const builtinVerifiers: readonly TaskflowVerifier[];
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/verifiers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAE/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,EAAE,SAAS,gBAAgB,EAAyB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Built-in verifiers barrel.
3
+ *
4
+ * Re-exports the shipped verifiers so hosts can import them from one place:
5
+ * import { scriptLintVerifier, builtinVerifiers } from "taskflow-core/verifiers";
6
+ */
7
+ export { scriptLintVerifier } from "./script-lint.js";
8
+ export { discoverVerifiers, listVerifierPaths } from "./discover.js";
9
+ import { scriptLintVerifier } from "./script-lint.js";
10
+ /** All built-in verifiers, in recommended registration order. */
11
+ export const builtinVerifiers = [scriptLintVerifier];
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/verifiers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAA4B,MAAM,eAAe,CAAC;AAG/F,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,iEAAiE;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAgC,CAAC,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Built-in script-lint verifier — static analysis of `script` phase `run`
3
+ * commands. Catches common shell mistakes that are 100% statically detectable,
4
+ * zero-token, and runner-agnostic:
5
+ *
6
+ * 1. `grep`/`egrep`/`fgrep` whose pattern starts with `-` and has no `--`
7
+ * separator (grep parses it as flags → exit 2, a false RED).
8
+ * 2. `grep`/`sed` with obviously invalid regex under common dialect flags
9
+ * (unbalanced brackets/parens → exit 2).
10
+ * 3. `runner | grep …` without `pipefail` / `PIPESTATUS` (the filter's exit
11
+ * masks the runner's — a failing runner reads as GREEN).
12
+ * 4. A script that references a file path matching a phase id's likely output
13
+ * artifact created by an earlier phase (RED until that phase runs).
14
+ *
15
+ * This is the dogfood verifier motivated by issue #82. It ships as an optional
16
+ * built-in: hosts can register it via `verifyTaskflow(flow, { verifiers:
17
+ * [scriptLintVerifier] })` or it is auto-included by `compileTaskflow` when
18
+ * `opts.lint !== false`.
19
+ */
20
+ import type { TaskflowVerifier } from "../verify.ts";
21
+ /** The built-in script-lint verifier. Register it via
22
+ * `verifyTaskflow(flow, { verifiers: [scriptLintVerifier] })`. */
23
+ export declare const scriptLintVerifier: TaskflowVerifier;
24
+ //# sourceMappingURL=script-lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-lint.d.ts","sourceRoot":"","sources":["../../src/verifiers/script-lint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAiC,MAAM,cAAc,CAAC;AAsPpF;mEACmE;AACnE,eAAO,MAAM,kBAAkB,EAAE,gBA2ChC,CAAC"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Built-in script-lint verifier — static analysis of `script` phase `run`
3
+ * commands. Catches common shell mistakes that are 100% statically detectable,
4
+ * zero-token, and runner-agnostic:
5
+ *
6
+ * 1. `grep`/`egrep`/`fgrep` whose pattern starts with `-` and has no `--`
7
+ * separator (grep parses it as flags → exit 2, a false RED).
8
+ * 2. `grep`/`sed` with obviously invalid regex under common dialect flags
9
+ * (unbalanced brackets/parens → exit 2).
10
+ * 3. `runner | grep …` without `pipefail` / `PIPESTATUS` (the filter's exit
11
+ * masks the runner's — a failing runner reads as GREEN).
12
+ * 4. A script that references a file path matching a phase id's likely output
13
+ * artifact created by an earlier phase (RED until that phase runs).
14
+ *
15
+ * This is the dogfood verifier motivated by issue #82. It ships as an optional
16
+ * built-in: hosts can register it via `verifyTaskflow(flow, { verifiers:
17
+ * [scriptLintVerifier] })` or it is auto-included by `compileTaskflow` when
18
+ * `opts.lint !== false`.
19
+ */
20
+ // ---------------------------------------------------------------------------
21
+ // Helpers
22
+ // ---------------------------------------------------------------------------
23
+ /** Tokenize a shell command string naively (split on whitespace, respecting
24
+ * single/double quotes). Not a full shell parser — just enough to identify
25
+ * command names and their arguments for lint heuristics. */
26
+ function tokenize(cmd) {
27
+ const tokens = [];
28
+ let current = "";
29
+ let inSingle = false;
30
+ let inDouble = false;
31
+ let escaped = false;
32
+ for (const ch of cmd) {
33
+ if (escaped) {
34
+ current += ch;
35
+ escaped = false;
36
+ continue;
37
+ }
38
+ if (ch === "\\" && !inSingle) {
39
+ escaped = true;
40
+ current += ch;
41
+ continue;
42
+ }
43
+ if (ch === "'" && !inDouble) {
44
+ inSingle = !inSingle;
45
+ current += ch;
46
+ continue;
47
+ }
48
+ if (ch === '"' && !inSingle) {
49
+ inDouble = !inDouble;
50
+ current += ch;
51
+ continue;
52
+ }
53
+ if ((ch === " " || ch === "\t") && !inSingle && !inDouble) {
54
+ if (current)
55
+ tokens.push(current);
56
+ current = "";
57
+ continue;
58
+ }
59
+ current += ch;
60
+ }
61
+ if (current)
62
+ tokens.push(current);
63
+ return tokens;
64
+ }
65
+ /** Split a command string on unquoted pipe characters into pipeline segments. */
66
+ function splitPipeline(cmd) {
67
+ const segments = [];
68
+ let current = "";
69
+ let inSingle = false;
70
+ let inDouble = false;
71
+ let escaped = false;
72
+ for (const ch of cmd) {
73
+ if (escaped) {
74
+ current += ch;
75
+ escaped = false;
76
+ continue;
77
+ }
78
+ if (ch === "\\" && !inSingle) {
79
+ escaped = true;
80
+ current += ch;
81
+ continue;
82
+ }
83
+ if (ch === "'" && !inDouble) {
84
+ inSingle = !inSingle;
85
+ current += ch;
86
+ continue;
87
+ }
88
+ if (ch === '"' && !inSingle) {
89
+ inDouble = !inDouble;
90
+ current += ch;
91
+ continue;
92
+ }
93
+ if (ch === "|" && !inSingle && !inDouble) {
94
+ segments.push(current.trim());
95
+ current = "";
96
+ continue;
97
+ }
98
+ current += ch;
99
+ }
100
+ if (current.trim())
101
+ segments.push(current.trim());
102
+ return segments;
103
+ }
104
+ const GREP_COMMANDS = new Set(["grep", "egrep", "fgrep", "rg", "ag"]);
105
+ /** Strip a directory path prefix from a command name using linear-time
106
+ * lastIndexOf instead of a regex (avoids CodeQL ReDoS alert). */
107
+ function stripPathPrefix(token) {
108
+ if (!token)
109
+ return undefined;
110
+ const idx = token.lastIndexOf("/");
111
+ return idx >= 0 ? token.slice(idx + 1) : token;
112
+ }
113
+ /** Check if a grep-like command has a pattern starting with `-` without a `--`
114
+ * separator before it. */
115
+ function checkGrepDashPattern(tokens) {
116
+ const cmdName = stripPathPrefix(tokens[0]);
117
+ if (!cmdName || !GREP_COMMANDS.has(cmdName))
118
+ return undefined;
119
+ let sawDoubleDash = false;
120
+ for (let i = 1; i < tokens.length; i++) {
121
+ const t = tokens[i];
122
+ if (t === "--") {
123
+ sawDoubleDash = true;
124
+ continue;
125
+ }
126
+ if (sawDoubleDash) {
127
+ // First arg after -- is the pattern; it's safe.
128
+ return undefined;
129
+ }
130
+ // Skip known flags (single-dash options).
131
+ if (t.startsWith("-") && t.length <= 3 && !t.startsWith("--"))
132
+ continue;
133
+ // Skip --flag=value style.
134
+ if (t.startsWith("--"))
135
+ continue;
136
+ // First non-flag argument is the pattern.
137
+ if (t.startsWith("-")) {
138
+ return `grep pattern '${t}' starts with '-' but has no '--' separator — grep will parse it as flags (exit 2)`;
139
+ }
140
+ // Pattern doesn't start with dash — fine.
141
+ return undefined;
142
+ }
143
+ return undefined;
144
+ }
145
+ /** Check for obviously unbalanced regex in grep/sed patterns. */
146
+ function checkUnbalancedRegex(tokens) {
147
+ const cmdName = stripPathPrefix(tokens[0]);
148
+ if (!cmdName)
149
+ return undefined;
150
+ let pattern;
151
+ if (GREP_COMMANDS.has(cmdName)) {
152
+ // Find the pattern (first non-flag arg, or arg after -e).
153
+ let sawE = false;
154
+ for (let i = 1; i < tokens.length; i++) {
155
+ const t = tokens[i];
156
+ if (t === "--") {
157
+ pattern = tokens[i + 1];
158
+ break;
159
+ }
160
+ if (t === "-e") {
161
+ sawE = true;
162
+ continue;
163
+ }
164
+ if (sawE) {
165
+ pattern = t;
166
+ break;
167
+ }
168
+ if (t.startsWith("-"))
169
+ continue;
170
+ pattern = t;
171
+ break;
172
+ }
173
+ }
174
+ else if (cmdName === "sed") {
175
+ // sed 's/pattern/replacement/' — extract the pattern between first two
176
+ // delimiters.
177
+ for (let i = 1; i < tokens.length; i++) {
178
+ const t = tokens[i];
179
+ if (t.startsWith("-"))
180
+ continue;
181
+ // First non-flag arg is the script.
182
+ const cleaned = t.replace(/^['"]|['"]$/g, "");
183
+ const match = cleaned.match(/^s(.)(.*)$/);
184
+ if (match) {
185
+ const delim = match[1];
186
+ const rest = match[2];
187
+ const endIdx = rest.indexOf(delim);
188
+ if (endIdx > 0)
189
+ pattern = rest.slice(0, endIdx);
190
+ }
191
+ break;
192
+ }
193
+ }
194
+ if (!pattern)
195
+ return undefined;
196
+ // Strip quotes.
197
+ const p = pattern.replace(/^['"]|['"]$/g, "");
198
+ // Check unbalanced brackets/parens (basic heuristic — not a full regex
199
+ // parser, but catches the common `[abc` and `(foo` mistakes).
200
+ let bracketDepth = 0;
201
+ let parenDepth = 0;
202
+ let inBracket = false;
203
+ for (let i = 0; i < p.length; i++) {
204
+ const ch = p[i];
205
+ if (ch === "\\" && i + 1 < p.length) {
206
+ i++; // skip escaped char
207
+ continue;
208
+ }
209
+ if (ch === "[") {
210
+ inBracket = true;
211
+ bracketDepth++;
212
+ }
213
+ else if (ch === "]") {
214
+ if (inBracket) {
215
+ bracketDepth--;
216
+ if (bracketDepth === 0)
217
+ inBracket = false;
218
+ }
219
+ }
220
+ else if (ch === "(" && !inBracket) {
221
+ parenDepth++;
222
+ }
223
+ else if (ch === ")" && !inBracket) {
224
+ parenDepth--;
225
+ }
226
+ }
227
+ if (bracketDepth > 0)
228
+ return `unbalanced '[' in regex pattern '${p}' — grep/sed will exit 2`;
229
+ if (parenDepth > 0)
230
+ return `unbalanced '(' in regex pattern '${p}' — grep/sed will exit 2`;
231
+ if (parenDepth < 0)
232
+ return `unbalanced ')' in regex pattern '${p}' — grep/sed will exit 2`;
233
+ return undefined;
234
+ }
235
+ /** Check if a pipeline has a grep/filter at the end without pipefail. */
236
+ function checkPipefail(cmd, segments) {
237
+ if (segments.length < 2)
238
+ return undefined;
239
+ const lastSegment = segments[segments.length - 1];
240
+ const lastTokens = tokenize(lastSegment);
241
+ const lastCmd = stripPathPrefix(lastTokens[0]);
242
+ // Only flag when the last command is a filter (grep/awk/head/tail/wc/sort).
243
+ const FILTER_COMMANDS = new Set(["grep", "egrep", "fgrep", "rg", "ag", "awk", "head", "tail", "wc", "sort", "uniq"]);
244
+ if (!lastCmd || !FILTER_COMMANDS.has(lastCmd))
245
+ return undefined;
246
+ // Check if pipefail is set anywhere in the command.
247
+ if (/set\s+-[a-zA-Z]*o\s+pipefail/.test(cmd) || /set\s+-[a-zA-Z]*p/.test(cmd))
248
+ return undefined;
249
+ if (/PIPESTATUS/.test(cmd))
250
+ return undefined;
251
+ if (/pipefail/.test(cmd))
252
+ return undefined;
253
+ // Check if the script uses `bash -o pipefail` or similar.
254
+ if (cmd.includes("-o") && cmd.includes("pipefail") && cmd.includes("bash"))
255
+ return undefined;
256
+ return `pipeline ends with '${lastCmd}' but has no 'set -o pipefail' or PIPESTATUS check — a failing upstream command will be masked by the filter's exit code`;
257
+ }
258
+ // ---------------------------------------------------------------------------
259
+ // The verifier
260
+ // ---------------------------------------------------------------------------
261
+ /** Extract the command string(s) from a script phase's `run` field. */
262
+ function extractCommands(phase) {
263
+ const run = phase.run;
264
+ if (typeof run === "string")
265
+ return [run];
266
+ if (Array.isArray(run))
267
+ return run.filter((r) => typeof r === "string");
268
+ return [];
269
+ }
270
+ /** The built-in script-lint verifier. Register it via
271
+ * `verifyTaskflow(flow, { verifiers: [scriptLintVerifier] })`. */
272
+ export const scriptLintVerifier = {
273
+ name: "script-lint",
274
+ verify(flow) {
275
+ const issues = [];
276
+ for (const phase of flow.phases) {
277
+ if ((phase.type ?? "agent") !== "script")
278
+ continue;
279
+ const commands = extractCommands(phase);
280
+ for (const cmd of commands) {
281
+ // Skip commands with interpolation placeholders — we can't lint
282
+ // what we can't see yet.
283
+ if (/\{[a-zA-Z]/.test(cmd))
284
+ continue;
285
+ const segments = splitPipeline(cmd);
286
+ for (const segment of segments) {
287
+ const tokens = tokenize(segment);
288
+ if (tokens.length === 0)
289
+ continue;
290
+ // Check 1: grep dash pattern.
291
+ const dashIssue = checkGrepDashPattern(tokens);
292
+ if (dashIssue) {
293
+ issues.push({ phaseId: phase.id, message: dashIssue, severity: "error" });
294
+ }
295
+ // Check 2: unbalanced regex.
296
+ const regexIssue = checkUnbalancedRegex(tokens);
297
+ if (regexIssue) {
298
+ issues.push({ phaseId: phase.id, message: regexIssue, severity: "error" });
299
+ }
300
+ }
301
+ // Check 3: pipefail.
302
+ const pipefailIssue = checkPipefail(cmd, segments);
303
+ if (pipefailIssue) {
304
+ issues.push({ phaseId: phase.id, message: pipefailIssue, severity: "warning" });
305
+ }
306
+ }
307
+ }
308
+ return issues;
309
+ },
310
+ };
311
+ //# sourceMappingURL=script-lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"script-lint.js","sourceRoot":"","sources":["../../src/verifiers/script-lint.ts"],"names":[],"mappings":"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"}