agentic-workflow-manager 3.4.0 → 3.6.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.
Files changed (61) hide show
  1. package/dist/src/commands/job/exec-wrapper.js +136 -0
  2. package/dist/src/commands/job/export.js +94 -0
  3. package/dist/src/commands/job/gate.js +118 -0
  4. package/dist/src/commands/job/heartbeat.js +15 -0
  5. package/dist/src/commands/job/index.js +246 -0
  6. package/dist/src/commands/job/query.js +37 -0
  7. package/dist/src/commands/job/reap.js +24 -0
  8. package/dist/src/commands/job/reconcile.js +112 -0
  9. package/dist/src/commands/job/request.js +27 -0
  10. package/dist/src/commands/sensors/exec.js +121 -0
  11. package/dist/src/commands/sensors/index.js +4 -4
  12. package/dist/src/commands/sensors/run.js +124 -71
  13. package/dist/src/commands/watch/apply.js +352 -0
  14. package/dist/src/commands/watch/generations.js +249 -0
  15. package/dist/src/commands/watch/index.js +49 -0
  16. package/dist/src/commands/watch/init.js +72 -0
  17. package/dist/src/commands/watch/lock.js +89 -0
  18. package/dist/src/commands/watch/runner.js +191 -0
  19. package/dist/src/commands/watch/supervisor.js +266 -0
  20. package/dist/src/core/atomic-file.js +31 -0
  21. package/dist/src/core/export/pack.js +7 -1
  22. package/dist/src/core/journal/adapter.js +27 -0
  23. package/dist/src/core/journal/fingerprint.js +80 -0
  24. package/dist/src/core/journal/paths.js +56 -0
  25. package/dist/src/core/journal/process.js +284 -0
  26. package/dist/src/core/journal/redact.js +142 -0
  27. package/dist/src/core/journal/requests.js +132 -0
  28. package/dist/src/core/journal/store.js +107 -0
  29. package/dist/src/core/journal/types.js +165 -0
  30. package/dist/src/index.js +4 -0
  31. package/dist/tests/commands/job/exec-wrapper.test.js +85 -0
  32. package/dist/tests/commands/job/export.test.js +76 -0
  33. package/dist/tests/commands/job/gate-reconcile.test.js +297 -0
  34. package/dist/tests/commands/job/reap-cli.test.js +101 -0
  35. package/dist/tests/commands/job/verbs.test.js +56 -0
  36. package/dist/tests/commands/job/verdict-determinism.test.js +138 -0
  37. package/dist/tests/commands/sensors/exec-fixtures.js +24 -0
  38. package/dist/tests/commands/sensors/exec.test.js +91 -0
  39. package/dist/tests/commands/sensors/run-inconclusive.test.js +55 -66
  40. package/dist/tests/commands/sensors/run-partial.test.js +225 -0
  41. package/dist/tests/commands/sensors/run-tool-missing.test.js +6 -6
  42. package/dist/tests/commands/sensors/run.test.js +64 -81
  43. package/dist/tests/commands/watch/apply.test.js +397 -0
  44. package/dist/tests/commands/watch/e2e-crash.test.js +157 -0
  45. package/dist/tests/commands/watch/generations.test.js +115 -0
  46. package/dist/tests/commands/watch/integration.test.js +124 -0
  47. package/dist/tests/commands/watch/lock.test.js +60 -0
  48. package/dist/tests/commands/watch/runner.test.js +239 -0
  49. package/dist/tests/commands/watch/supervisor-loop.test.js +203 -0
  50. package/dist/tests/commands/watch/watch-init.test.js +43 -0
  51. package/dist/tests/core/atomic-file-durable.test.js +42 -0
  52. package/dist/tests/core/journal/adapter.test.js +27 -0
  53. package/dist/tests/core/journal/fingerprint.test.js +164 -0
  54. package/dist/tests/core/journal/paths.test.js +35 -0
  55. package/dist/tests/core/journal/process.test.js +213 -0
  56. package/dist/tests/core/journal/redact.test.js +59 -0
  57. package/dist/tests/core/journal/requests.test.js +134 -0
  58. package/dist/tests/core/journal/store.test.js +88 -0
  59. package/dist/tests/core/journal/types.test.js +78 -0
  60. package/dist/tests/structural/exec-invocation-explicit-stdio.test.js +94 -0
  61. package/package.json +1 -1
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ // Structural regression guard for the recurring class of bug found across
3
+ // R1's durable-controller work (harness-retro, 2026-08-01 — r1-durable-controller
4
+ // plan, Task 20 + post-implementation-qa): execFileSync/spawn/spawnSync calls
5
+ // with no explicit `stdio` option inherit Node's default `inheritStderr`
6
+ // relay, which pipes the SUBPROCESS's stderr onto the CALLING process's own
7
+ // stderr fd. When that fd is a destroyed/broken pipe (a detached wrapper
8
+ // whose parent already tore down its own pipes, a supervisor whose stdout
9
+ // went away), the relay itself raises an async EPIPE with no listener,
10
+ // which Node re-throws — silently crashing the caller before it can finish
11
+ // its work.
12
+ //
13
+ // The bug recurred FIVE separate times in the same session even after the
14
+ // first fix landed: spawnStructured's own detached-child spawn, then 4 more
15
+ // bare execFileSync('git'/'ps'/'pgrep', ...) call sites in DIFFERENT files
16
+ // (process.ts, lock.ts, job/index.ts, watch/index.ts, fingerprint.ts) plus a
17
+ // bonus spawnSync('zip', ...) in pack.ts — because each fix was scoped to
18
+ // the one call site a reviewer happened to be looking at, not the whole
19
+ // class. This test exercises the whole class in one pass: every
20
+ // execFileSync/spawn/spawnSync call site anywhere under cli/src must pass an
21
+ // explicit `stdio` option (or the shared `EXEC_STDIO` constant) — so a
22
+ // future call site added without one fails immediately instead of waiting
23
+ // for the next EPIPE crash to be noticed.
24
+ var __importDefault = (this && this.__importDefault) || function (mod) {
25
+ return (mod && mod.__esModule) ? mod : { "default": mod };
26
+ };
27
+ Object.defineProperty(exports, "__esModule", { value: true });
28
+ const fs_1 = __importDefault(require("fs"));
29
+ const path_1 = __importDefault(require("path"));
30
+ const SRC_ROOT = path_1.default.join(__dirname, '../../src');
31
+ const CALLEE_NAMES = ['execFileSync', 'spawnSync', 'spawn'];
32
+ function listTsFiles(dir) {
33
+ const out = [];
34
+ for (const entry of fs_1.default.readdirSync(dir, { withFileTypes: true })) {
35
+ const full = path_1.default.join(dir, entry.name);
36
+ if (entry.isDirectory())
37
+ out.push(...listTsFiles(full));
38
+ else if (entry.isFile() && entry.name.endsWith('.ts'))
39
+ out.push(full);
40
+ }
41
+ return out;
42
+ }
43
+ // Strips comments before scanning: JSDoc/inline comments in this codebase
44
+ // routinely reference "spawn (...)" or "execFileSync(...)" in prose (e.g.
45
+ // process.ts's own EPIPE-hardening comment), which would otherwise register
46
+ // as phantom call sites. Naive block/line-comment stripping, not a full TS
47
+ // parser — sufficient for a structural guard, and a false positive here
48
+ // fails loud rather than silently missing a real site. The `[^:]` guard on
49
+ // `//` avoids treating a `https://` URL in a string as a line comment.
50
+ function stripComments(source) {
51
+ return source
52
+ .replace(/\/\*[\s\S]*?\*\//g, '')
53
+ .replace(/(^|[^:])\/\/.*$/gm, '$1');
54
+ }
55
+ // Extracts the paren-balanced argument text of every call to one of
56
+ // CALLEE_NAMES in `source` — e.g. "execFileSync('git', [...], {...})" -> the
57
+ // text between the outer parens. Balanced-paren scanning (not a single-line
58
+ // regex) is required because real call sites in this repo span multiple
59
+ // lines (e.g. process.ts's pgrep call).
60
+ function extractCalls(rawSource) {
61
+ const source = stripComments(rawSource);
62
+ const calls = [];
63
+ const calleeRe = new RegExp(`\\b(${CALLEE_NAMES.join('|')})\\s*\\(`, 'g');
64
+ let m;
65
+ while ((m = calleeRe.exec(source)) !== null) {
66
+ const start = m.index + m[0].length; // just after the opening '('
67
+ let depth = 1;
68
+ let i = start;
69
+ while (i < source.length && depth > 0) {
70
+ if (source[i] === '(')
71
+ depth++;
72
+ else if (source[i] === ')')
73
+ depth--;
74
+ i++;
75
+ }
76
+ calls.push({ callee: m[1], args: source.slice(start, i - 1) });
77
+ }
78
+ return calls;
79
+ }
80
+ describe('execFileSync/spawn/spawnSync invocations — explicit stdio required (structural)', () => {
81
+ it('every call site under cli/src passes an explicit stdio option, never relying on Node defaults', () => {
82
+ const violations = [];
83
+ for (const file of listTsFiles(SRC_ROOT)) {
84
+ const source = fs_1.default.readFileSync(file, 'utf8');
85
+ for (const call of extractCalls(source)) {
86
+ const hasExplicitStdio = /\bstdio\s*:/.test(call.args) || /\bEXEC_STDIO\b/.test(call.args);
87
+ if (!hasExplicitStdio) {
88
+ violations.push(`${path_1.default.relative(SRC_ROOT, file)}: ${call.callee}(...) has no explicit stdio option`);
89
+ }
90
+ }
91
+ }
92
+ expect(violations).toEqual([]);
93
+ });
94
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-workflow-manager",
3
- "version": "3.4.0",
3
+ "version": "3.6.0",
4
4
  "main": "dist/src/index.js",
5
5
  "bin": {
6
6
  "awm": "./dist/src/index.js"