@magnusekdahl/parallix 1.3.4 → 1.5.126

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 (227) hide show
  1. package/NOTICES +1423 -0
  2. package/README.md +76 -103
  3. package/build/asset-manifest.json +129 -0
  4. package/{config → build/config}/agents.json +4 -8
  5. package/build/manifest.sha256 +40 -0
  6. package/build/migrations/0001-initial-schema.sql +91 -0
  7. package/build/migrations/0002-import-history.sql +16 -0
  8. package/build/migrations/0003-board-lane-events.sql +72 -0
  9. package/build/migrations/0004-mission-aggregate.sql +151 -0
  10. package/build/migrations/0005-mission-external-task-ref.sql +18 -0
  11. package/build/migrations/0005-repository-scoped-session-markers.sql +47 -0
  12. package/build/migrations/0006-session-markers.sql +35 -0
  13. package/build/migrations/0007-usage-statistics-identity.sql +60 -0
  14. package/build/migrations/0008-review-workflow-state.sql +61 -0
  15. package/build/migrations/0009-review-gate-retries.sql +16 -0
  16. package/build/migrations/0010-review-events-and-implementer-response.sql +64 -0
  17. package/build/migrations/0011-board-lane-events-repository-id.sql +89 -0
  18. package/build/migrations/0012-review-hook-retries.sql +11 -0
  19. package/build/migrations/0013-usage-statistics-thoughts-tokens.sql +11 -0
  20. package/build/migrations/0014-remove-usage-closed.sql +33 -0
  21. package/build/migrations/0015-current-work-latest-per-mission.sql +5 -0
  22. package/build/migrations/0016-review-drop-retry-counters.sql +21 -0
  23. package/build/migrations/0017-retire-mission-import-provenance.sql +5 -0
  24. package/build/migrations/0018-adhoc-mission-counter.sql +19 -0
  25. package/build/migrations/0019-custom-agent-leases.sql +12 -0
  26. package/build/package.json +5 -0
  27. package/{prompts/act-on-review.md → build/prompts/act-on-review-core.md} +6 -4
  28. package/build/prompts/act-on-review.md +1 -0
  29. package/{prompts/draft.md → build/prompts/draft-core.md} +8 -1
  30. package/build/prompts/execute-core.md +37 -0
  31. package/build/prompts/execute.md +0 -0
  32. package/build/prompts/review-core.md +71 -0
  33. package/build/prompts/review.md +0 -0
  34. package/build/px.mjs +1226 -0
  35. package/build/px.mjs.map +7 -0
  36. package/build/sbom.json +2155 -0
  37. package/build/templates/mission-scaffold.md +61 -0
  38. package/build/web/assets/index-B8Hv3ORh.js +9 -0
  39. package/build/web/assets/index-DYY4ROtr.css +1 -0
  40. package/build/web/index.html +13 -0
  41. package/build/web/manifest.json +20 -0
  42. package/package.json +56 -30
  43. package/CHANGELOG.md +0 -140
  44. package/config/agents.local.json.template +0 -8
  45. package/config/integration-pipelines.json +0 -14
  46. package/config/state-map.json.template +0 -31
  47. package/config/workflow.config.schema.json +0 -110
  48. package/docs/adr/0031-ai-agent-instruction-boundary-and-command-floor.md +0 -114
  49. package/docs/adr/0032-mission-refinement-state-and-usage-budget-signals.md +0 -137
  50. package/docs/adr/0034-module-and-skill-invocation-model.md +0 -202
  51. package/docs/adr/0036-mission-sizing-and-dependency-wave-heuristics.md +0 -81
  52. package/docs/adr/0037-ai-workflow-coordination-architecture.md +0 -162
  53. package/docs/adr/0041-integration-pipeline-gates.md +0 -165
  54. package/docs/adr/0042-workflow-cli-color-rendering-approach.md +0 -106
  55. package/docs/adr/0043-git-target-resolution-strategy.md +0 -185
  56. package/docs/adr/0044-workflow-distribution-model.md +0 -277
  57. package/docs/adr/0045-parallax-branch-model.md +0 -182
  58. package/docs/adr/0046-npm-publish-process-and-security.md +0 -138
  59. package/docs/adr/0047-per-mission-change-size-budget.md +0 -161
  60. package/docs/adr/0048-fail-closed-harness-defense-against-agent-hallucinations.md +0 -161
  61. package/docs/adr/index.md +0 -23
  62. package/docs/agents.md +0 -212
  63. package/docs/authority-reference.md +0 -328
  64. package/docs/doc-standards.md +0 -89
  65. package/docs/forgejo-setup.md +0 -55
  66. package/docs/migration/extraction.md +0 -61
  67. package/docs/migration/task-classification.md +0 -36
  68. package/docs/operator-setup.md +0 -76
  69. package/docs/readme-rewrite-benchmark.md +0 -188
  70. package/docs/use-cases.md +0 -149
  71. package/examples/README.md +0 -62
  72. package/examples/run-enterprise-tarball-workflow-smoke.sh +0 -257
  73. package/examples/run-verify-env-smoke.sh +0 -40
  74. package/index.js +0 -262
  75. package/lib/README.md +0 -13
  76. package/lib/agents/agents.js +0 -880
  77. package/lib/agents/agents.ts +0 -978
  78. package/lib/agents/claude-telemetry.js +0 -232
  79. package/lib/agents/claude-telemetry.ts +0 -233
  80. package/lib/agents/claude.js +0 -152
  81. package/lib/agents/claude.ts +0 -158
  82. package/lib/agents/codex-telemetry.js +0 -227
  83. package/lib/agents/codex-telemetry.ts +0 -205
  84. package/lib/agents/codex.js +0 -213
  85. package/lib/agents/codex.ts +0 -238
  86. package/lib/agents/limit-hit.js +0 -259
  87. package/lib/agents/limit-hit.ts +0 -262
  88. package/lib/agents/mistral-telemetry.js +0 -140
  89. package/lib/agents/mistral-telemetry.ts +0 -159
  90. package/lib/agents/mistral.js +0 -174
  91. package/lib/agents/mistral.ts +0 -224
  92. package/lib/agents/opencode-export.js +0 -158
  93. package/lib/agents/opencode-export.ts +0 -160
  94. package/lib/agents/opencode-telemetry.js +0 -372
  95. package/lib/agents/opencode-telemetry.ts +0 -350
  96. package/lib/agents/opencode.js +0 -355
  97. package/lib/agents/opencode.ts +0 -372
  98. package/lib/agents/stage-telemetry.js +0 -41
  99. package/lib/agents/stage-telemetry.ts +0 -47
  100. package/lib/commands/active.js +0 -642
  101. package/lib/commands/active.ts +0 -707
  102. package/lib/commands/checkpoint.js +0 -102
  103. package/lib/commands/checkpoint.ts +0 -79
  104. package/lib/commands/config.js +0 -76
  105. package/lib/commands/config.ts +0 -52
  106. package/lib/commands/coverage-gate.js +0 -408
  107. package/lib/commands/coverage-gate.ts +0 -367
  108. package/lib/commands/diff.js +0 -151
  109. package/lib/commands/diff.ts +0 -130
  110. package/lib/commands/draft.js +0 -920
  111. package/lib/commands/draft.ts +0 -1026
  112. package/lib/commands/handoff.js +0 -685
  113. package/lib/commands/handoff.ts +0 -705
  114. package/lib/commands/integrate.js +0 -1612
  115. package/lib/commands/integrate.ts +0 -1724
  116. package/lib/commands/mission-start.js +0 -313
  117. package/lib/commands/mission-start.ts +0 -268
  118. package/lib/commands/rebase.js +0 -667
  119. package/lib/commands/rebase.ts +0 -639
  120. package/lib/commands/repair-handoff.js +0 -363
  121. package/lib/commands/repair-handoff.ts +0 -373
  122. package/lib/commands/resolve-conflict.js +0 -137
  123. package/lib/commands/resolve-conflict.ts +0 -117
  124. package/lib/commands/review.js +0 -18
  125. package/lib/commands/review.ts +0 -19
  126. package/lib/commands/setup-review.js +0 -18
  127. package/lib/commands/setup-review.ts +0 -19
  128. package/lib/commands/setup.js +0 -9
  129. package/lib/commands/setup.ts +0 -7
  130. package/lib/commands/stats-backfill.js +0 -448
  131. package/lib/commands/stats-backfill.ts +0 -423
  132. package/lib/commands/stats.js +0 -2016
  133. package/lib/commands/stats.ts +0 -2135
  134. package/lib/commands/status.js +0 -246
  135. package/lib/commands/status.ts +0 -224
  136. package/lib/commands/verify.js +0 -12
  137. package/lib/commands/verify.ts +0 -7
  138. package/lib/core/fmt.js +0 -178
  139. package/lib/core/fmt.ts +0 -189
  140. package/lib/core/git.js +0 -140
  141. package/lib/core/git.ts +0 -146
  142. package/lib/core/gitignore.js +0 -73
  143. package/lib/core/gitignore.ts +0 -108
  144. package/lib/core/mission-utils.js +0 -1058
  145. package/lib/core/mission-utils.ts +0 -998
  146. package/lib/core/nels.js +0 -184
  147. package/lib/core/nels.ts +0 -189
  148. package/lib/core/persistent-data-migration.js +0 -285
  149. package/lib/core/persistent-data-migration.ts +0 -257
  150. package/lib/core/product-config.js +0 -460
  151. package/lib/core/product-config.ts +0 -518
  152. package/lib/core/runtime-matrix.js +0 -49
  153. package/lib/core/runtime-matrix.ts +0 -84
  154. package/lib/core/spawn-tee.js +0 -160
  155. package/lib/core/spawn-tee.ts +0 -202
  156. package/lib/core/state-map.js +0 -108
  157. package/lib/core/state-map.ts +0 -115
  158. package/lib/core/storage.js +0 -151
  159. package/lib/core/storage.ts +0 -182
  160. package/lib/core/subagent-limit.js +0 -27
  161. package/lib/core/subagent-limit.ts +0 -25
  162. package/lib/core/verification.js +0 -176
  163. package/lib/core/verification.ts +0 -200
  164. package/lib/index.js +0 -160
  165. package/lib/index.ts +0 -134
  166. package/lib/review/rebase.js +0 -168
  167. package/lib/review/rebase.ts +0 -188
  168. package/lib/review/review-adapter.js +0 -234
  169. package/lib/review/review-adapter.ts +0 -198
  170. package/lib/review/review-artifacts.js +0 -542
  171. package/lib/review/review-artifacts.ts +0 -622
  172. package/lib/review/review-commands.js +0 -1318
  173. package/lib/review/review-commands.ts +0 -1579
  174. package/lib/review/review-events.js +0 -716
  175. package/lib/review/review-events.ts +0 -954
  176. package/lib/review/review-loop.js +0 -1271
  177. package/lib/review/review-loop.ts +0 -1493
  178. package/lib/review/review-polling.js +0 -132
  179. package/lib/review/review-polling.ts +0 -194
  180. package/lib/review/review-prompts.js +0 -212
  181. package/lib/review/review-prompts.ts +0 -186
  182. package/lib/review/review-state.js +0 -325
  183. package/lib/review/review-state.ts +0 -353
  184. package/lib/review/review.js +0 -126
  185. package/lib/review/review.ts +0 -143
  186. package/lib/tools/backlog.js +0 -848
  187. package/lib/tools/backlog.ts +0 -835
  188. package/lib/tools/forgejo.js +0 -1659
  189. package/lib/tools/forgejo.ts +0 -1793
  190. package/lib/tools/gatekeeper.js +0 -134
  191. package/lib/tools/gatekeeper.ts +0 -124
  192. package/lib/tools/redgreen.js +0 -239
  193. package/lib/tools/redgreen.ts +0 -221
  194. package/lib/tools/sessions.js +0 -87
  195. package/lib/tools/sessions.ts +0 -81
  196. package/lib/tools/setup-review.js +0 -1083
  197. package/lib/tools/setup-review.ts +0 -1152
  198. package/prompts/act-on-review-verbose.md +0 -20
  199. package/prompts/execute.md +0 -24
  200. package/prompts/portfolio.md +0 -30
  201. package/prompts/review-verbose.md +0 -36
  202. package/prompts/review.md +0 -50
  203. package/px.js +0 -268
  204. package/templates/AGENTS-snippet.md +0 -14
  205. package/templates/AGENTS.md.template +0 -34
  206. package/templates/CLAUDE.md.template +0 -27
  207. package/templates/CODEX.md.template +0 -38
  208. package/templates/MISTRAL.md.template +0 -24
  209. package/templates/claude-commands/act-on-review.md +0 -3
  210. package/templates/claude-commands/area-review.md +0 -3
  211. package/templates/claude-commands/draft.md +0 -6
  212. package/templates/claude-commands/execute.md +0 -6
  213. package/templates/claude-commands/integrate.md +0 -4
  214. package/templates/claude-commands/portfolio.md +0 -5
  215. package/templates/claude-commands/review.md +0 -4
  216. package/templates/codex/config.toml +0 -6
  217. package/templates/mission-scaffold.md +0 -39
  218. package/templates/vibe/skills/act-on-review/SKILL.md +0 -16
  219. package/templates/vibe/skills/area-review/SKILL.md +0 -16
  220. package/templates/vibe/skills/draft/SKILL.md +0 -16
  221. package/templates/vibe/skills/execute/SKILL.md +0 -16
  222. package/templates/vibe/skills/integrate/SKILL.md +0 -16
  223. package/templates/vibe/skills/portfolio/SKILL.md +0 -21
  224. package/templates/vibe/skills/review/SKILL.md +0 -16
  225. package/tools/setup-forgejo-docker.sh +0 -87
  226. /package/{config → build/config}/state-map.json +0 -0
  227. /package/{data/.gitkeep → build/prompts/draft.md} +0 -0
@@ -1,408 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- /**
4
- * coverage-gate.js - run parallix tests with Node's built-in coverage support
5
- * and enforce a configurable line-coverage threshold (default 90%).
6
- *
7
- * Usage:
8
- * node parallix/lib/commands/coverage-gate.js [--threshold <pct>] [--dry-run]
9
- *
10
- * Exit 0 when tests pass and coverage >= threshold.
11
- * Exit 1 otherwise.
12
- *
13
- * Denominator: parallix/index.js plus all nested .js files under parallix/lib
14
- * Excludes: parallix/test/*, parallix/prompts/*, parallix/config/*.json,
15
- * coverage output dirs, node_modules, generated/temp files.
16
- *
17
- * /tmp write inventory (SC-1): every /tmp or os.tmpdir() write location used by
18
- * coverage-gate.js and the workflow test infrastructure it runs:
19
- *
20
- * 1. PER_RUN_SCRATCH array (line 58) — tracks per-process scratch dirs created
21
- * by this process. Each entry is a path returned by fs.mkdtempSync().
22
- * 2. Node --experimental-test-coverage scratch (line 146) — Node creates
23
- * coverage-*.json files under NODE_V8_COVERAGE. coverage-gate.js sets
24
- * NODE_V8_COVERAGE to a per-process unique dir via createPerRunScratchDirs()
25
- * (line 176), so Node writes to a unique path, never /tmp/node-coverage-*.
26
- * 3. parallix/coverage/ directory (line 153) — created via fs.mkdirSync for
27
- * lcov output; lives under REPO_ROOT, not /tmp.
28
- * 4. TEMP_DIR_PREFIXES (lines 26-44) — prefix-based cleanup allowlist used by
29
- * cleanupNewTempDirs() (lines 94-110). Covers dirs created by test files
30
- * under parallix/test/*. These prefixes are intentionally NOT modified per SC-8.
31
- * 5. os.tmpdir() default parameter (lines 85, 94) — listTempEntries() and
32
- * cleanupNewTempDirs() accept os.tmpdir() as default root. runTests() passes
33
- * a per-run TMPDIR to the child test process and cleans only that root.
34
- * 6. Per-process mkdtempSync dirs (line 113) — createPerRunScratchDirs() creates
35
- * a unique dir via fs.mkdtempSync(path.join(os.tmpdir(), 'node-coverage-'))
36
- * and records it in PER_RUN_SCRATCH for targeted cleanup.
37
- * 7. Test files (37 files, ~168 mkdtempSync calls) — all use
38
- * fs.mkdtempSync(path.join(os.tmpdir(), 'prefix-')) pattern; already
39
- * per-process unique. No fixed-path /tmp writes in test files. Generic
40
- * runtime-* dirs are intentionally excluded because runtime-matrix launcher
41
- * tests keep executable probes there while parallel coverage processes run.
42
- * 8. /tmp/test-main — not produced by any in-scope code; orphaned 1.1 GB dir
43
- * on disk from manual integration test (pre-existing, outside parallix/ scope).
44
- * 9. Prompt templates (review.md, review-verbose.md, act-on-review.md, etc.) —
45
- * /tmp/{{slug}}-*.md patterns are templates, not actual writes.
46
- *
47
- * Cleanup strategy: per-process inventory (PER_RUN_SCRATCH) + exit/SIGINT/SIGTERM
48
- * handlers (lines 131-141) that remove only tracked dirs. No blanket rm -rf.
49
- */
50
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
51
- if (k2 === undefined) k2 = k;
52
- var desc = Object.getOwnPropertyDescriptor(m, k);
53
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
54
- desc = { enumerable: true, get: function() { return m[k]; } };
55
- }
56
- Object.defineProperty(o, k2, desc);
57
- }) : (function(o, m, k, k2) {
58
- if (k2 === undefined) k2 = k;
59
- o[k2] = m[k];
60
- }));
61
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
62
- Object.defineProperty(o, "default", { enumerable: true, value: v });
63
- }) : function(o, v) {
64
- o["default"] = v;
65
- });
66
- var __importStar = (this && this.__importStar) || (function () {
67
- var ownKeys = function(o) {
68
- ownKeys = Object.getOwnPropertyNames || function (o) {
69
- var ar = [];
70
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
71
- return ar;
72
- };
73
- return ownKeys(o);
74
- };
75
- return function (mod) {
76
- if (mod && mod.__esModule) return mod;
77
- var result = {};
78
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
79
- __setModuleDefault(result, mod);
80
- return result;
81
- };
82
- })();
83
- Object.defineProperty(exports, "__esModule", { value: true });
84
- exports.DEFAULT_TEST_TIMEOUT_MS = exports.COVERAGE_INCLUDES = exports.COVERAGE_EXCLUDES = void 0;
85
- exports.run = run;
86
- exports.cleanupPerRunScratch = cleanupPerRunScratch;
87
- exports.createPerRunScratchDirs = createPerRunScratchDirs;
88
- exports.discoverTestFiles = discoverTestFiles;
89
- exports.listTempEntries = listTempEntries;
90
- exports.registerExitHandlers = registerExitHandlers;
91
- exports.resetPerRunScratchState = resetPerRunScratchState;
92
- exports.resolveTestTimeoutMs = resolveTestTimeoutMs;
93
- exports.runTests = runTests;
94
- exports.shouldCleanTempDir = shouldCleanTempDir;
95
- const node_child_process_1 = require("node:child_process");
96
- const fs = __importStar(require("node:fs"));
97
- const os = __importStar(require("node:os"));
98
- const path = __importStar(require("node:path"));
99
- const fmt = __importStar(require("../core/fmt.js"));
100
- const REPO_ROOT = path.resolve(__dirname, '..', '..');
101
- const SELF_TEST_FILE = 'coverage-gate.test.js';
102
- const TEMP_DIR_PREFIXES = [
103
- 'agents-',
104
- 'sessions-',
105
- 'review-',
106
- 'forgejo-',
107
- 'workflow-',
108
- 'gatekeeper-',
109
- 'graphify-',
110
- 'claude-',
111
- 'codex-',
112
- 'gemini-',
113
- 'opencode-',
114
- 'startagent-',
115
- 'test-',
116
- 'mission-task-',
117
- 'visualBoard-task-',
118
- 'backlog-'
119
- ];
120
- const COVERAGE_INCLUDES = [
121
- 'index.js',
122
- 'lib/**/*.js'
123
- ];
124
- exports.COVERAGE_INCLUDES = COVERAGE_INCLUDES;
125
- const COVERAGE_EXCLUDES = [
126
- 'test/**',
127
- 'prompts/**',
128
- 'config/*.json',
129
- '.workflow/**',
130
- 'node_modules/**'
131
- ];
132
- exports.COVERAGE_EXCLUDES = COVERAGE_EXCLUDES;
133
- // The full suite regularly exceeds 10 minutes in this repository, especially
134
- // under cold caches. Keep the gate generous so it can finish without a manual
135
- // override while still failing on real hangs.
136
- const DEFAULT_TEST_TIMEOUT_MS = 3_600_000;
137
- exports.DEFAULT_TEST_TIMEOUT_MS = DEFAULT_TEST_TIMEOUT_MS;
138
- const PER_RUN_SCRATCH = [];
139
- let threshold = 90;
140
- let dryRun = false;
141
- let lcov = false;
142
- let cleanupDone = false;
143
- for (let i = 2; i < process.argv.length; i++) {
144
- if (process.argv[i] === '--threshold' && process.argv[i + 1]) {
145
- threshold = parseFloat(process.argv[i + 1]);
146
- i++;
147
- }
148
- else if (process.argv[i] === '--dry-run') {
149
- dryRun = true;
150
- }
151
- else if (process.argv[i] === '--lcov') {
152
- lcov = true;
153
- }
154
- }
155
- function discoverTestFiles() {
156
- const testDir = path.join(REPO_ROOT, 'test');
157
- if (!fs.existsSync(testDir)) {
158
- return [];
159
- }
160
- return fs.readdirSync(testDir)
161
- .filter(file => file.endsWith('.test.js'))
162
- .filter(file => file !== SELF_TEST_FILE)
163
- .map(file => path.join(testDir, file))
164
- .sort();
165
- }
166
- function listTempEntries(tmpRoot = os.tmpdir()) {
167
- if (!fs.existsSync(tmpRoot)) {
168
- return new Set();
169
- }
170
- return new Set(fs.readdirSync(tmpRoot));
171
- }
172
- function shouldCleanTempDir(name) {
173
- return TEMP_DIR_PREFIXES.some(prefix => name.startsWith(prefix));
174
- }
175
- function cleanupNewTempDirs(beforeEntries, tmpRoot = os.tmpdir()) {
176
- if (!fs.existsSync(tmpRoot)) {
177
- return;
178
- }
179
- for (const name of fs.readdirSync(tmpRoot)) {
180
- if (beforeEntries.has(name) || !shouldCleanTempDir(name)) {
181
- continue;
182
- }
183
- const fullPath = path.join(tmpRoot, name);
184
- let stat = null;
185
- try {
186
- stat = fs.statSync(fullPath);
187
- }
188
- catch (_) {
189
- continue;
190
- }
191
- if (!stat.isDirectory()) {
192
- continue;
193
- }
194
- try {
195
- fs.rmSync(fullPath, { recursive: true, force: true });
196
- }
197
- catch (_) { }
198
- }
199
- }
200
- function createPerRunScratchDirs() {
201
- const coverageDir = fs.mkdtempSync(path.join(os.tmpdir(), 'node-coverage-'));
202
- PER_RUN_SCRATCH.push(coverageDir);
203
- return coverageDir;
204
- }
205
- function createPerRunTmpRoot() {
206
- const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'coverage-gate-tmp-'));
207
- PER_RUN_SCRATCH.push(tmpRoot);
208
- return tmpRoot;
209
- }
210
- function createMockGraphifyBin() {
211
- const graphifyDir = fs.mkdtempSync(path.join(os.tmpdir(), 'graphify-'));
212
- PER_RUN_SCRATCH.push(graphifyDir);
213
- const graphifyBin = path.join(graphifyDir, 'graphify');
214
- fs.writeFileSync(graphifyBin, `#!/usr/bin/env bash
215
- set -euo pipefail
216
- if [[ "\${1:-}" == "--help" ]]; then
217
- echo "mock graphify"
218
- exit 0
219
- fi
220
- if [[ "\${1:-}" == "update" ]]; then
221
- mkdir -p graphify-out
222
- echo '{"nodes":[],"edges":[]}' > graphify-out/graph.json
223
- echo '# Mock Graph Report' > graphify-out/GRAPH_REPORT.md
224
- echo "[mock graphify] update $*"
225
- exit 0
226
- fi
227
- echo "Unhandled graphify command: $*" >&2
228
- exit 1
229
- `, { mode: 0o755 });
230
- return graphifyBin;
231
- }
232
- function cleanupPerRunScratch() {
233
- if (cleanupDone) {
234
- return;
235
- }
236
- cleanupDone = true;
237
- for (const dir of PER_RUN_SCRATCH) {
238
- try {
239
- if (fs.existsSync(dir)) {
240
- fs.rmSync(dir, { recursive: true, force: true });
241
- }
242
- }
243
- catch (_) { }
244
- }
245
- PER_RUN_SCRATCH.length = 0;
246
- }
247
- function registerExitHandlers() {
248
- process.on('exit', cleanupPerRunScratch);
249
- process.on('SIGINT', () => {
250
- cleanupPerRunScratch();
251
- process.exit(130);
252
- });
253
- process.on('SIGTERM', () => {
254
- cleanupPerRunScratch();
255
- process.exit(143);
256
- });
257
- }
258
- function resetPerRunScratchState() {
259
- PER_RUN_SCRATCH.length = 0;
260
- cleanupDone = false;
261
- }
262
- function buildCoverageArgs(testFiles, coverageThreshold = threshold, useLcov = lcov) {
263
- const args = [
264
- '--test',
265
- '--experimental-test-coverage',
266
- `--test-coverage-lines=${coverageThreshold}`,
267
- ...COVERAGE_INCLUDES.flatMap(pattern => ['--test-coverage-include', pattern]),
268
- ...COVERAGE_EXCLUDES.flatMap(pattern => ['--test-coverage-exclude', pattern]),
269
- ];
270
- if (useLcov) {
271
- const coverageDir = path.join(REPO_ROOT, 'coverage');
272
- if (!fs.existsSync(coverageDir)) {
273
- fs.mkdirSync(coverageDir, { recursive: true });
274
- }
275
- args.push('--test-reporter=lcov');
276
- args.push(`--test-reporter-destination=${path.join(coverageDir, 'lcov.info')}`);
277
- args.push('--test-reporter=spec');
278
- args.push('--test-reporter-destination=stdout');
279
- }
280
- args.push(...testFiles);
281
- return args;
282
- }
283
- function resolveTestTimeoutMs(env = process.env) {
284
- const raw = env.WORKFLOW_COVERAGE_GATE_TIMEOUT_MS;
285
- if (raw === undefined || raw === '') {
286
- return DEFAULT_TEST_TIMEOUT_MS;
287
- }
288
- const parsed = Number(raw);
289
- return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_TEST_TIMEOUT_MS;
290
- }
291
- function runTests(testFiles, coverageThreshold = threshold, _spawnSync = node_child_process_1.spawnSync) {
292
- const tmpRoot = createPerRunTmpRoot();
293
- const tmpEntriesBefore = listTempEntries(tmpRoot);
294
- const nodeCoverageDir = createPerRunScratchDirs();
295
- const childEnv = { ...process.env };
296
- delete childEnv.NODE_TEST_CONTEXT;
297
- delete childEnv.NODE_OPTIONS;
298
- childEnv.TMPDIR = tmpRoot;
299
- childEnv.NODE_V8_COVERAGE = nodeCoverageDir;
300
- childEnv.GRAPHIFY_BIN = createMockGraphifyBin();
301
- const result = _spawnSync(process.execPath, buildCoverageArgs(testFiles, coverageThreshold), {
302
- encoding: 'utf8',
303
- cwd: REPO_ROOT,
304
- env: childEnv,
305
- stdio: ['pipe', 'inherit', 'inherit'],
306
- timeout: resolveTestTimeoutMs(),
307
- });
308
- cleanupNewTempDirs(tmpEntriesBefore, tmpRoot);
309
- cleanupPerRunScratch();
310
- if (result.error) {
311
- fmt.log.error(`[coverage-gate] failed to spawn test runner: ${result.error.message}`);
312
- return 1;
313
- }
314
- if (result.signal) {
315
- fmt.log.error(`[coverage-gate] test runner killed by signal ${result.signal}`);
316
- return 1;
317
- }
318
- return result.status === null ? 1 : result.status;
319
- }
320
- function main() {
321
- const testFiles = discoverTestFiles();
322
- if (testFiles.length === 0) {
323
- fmt.log.fail('no parallix test files found under test/');
324
- process.exit(1);
325
- }
326
- fmt.log.info(`Found ${testFiles.length} test file(s)`);
327
- if (dryRun) {
328
- fmt.log.info(`DRY-RUN mode — threshold=${threshold}%`);
329
- fmt.log.info('Denominator: index.js + lib/**/*.js');
330
- fmt.log.info(`Include globs: ${COVERAGE_INCLUDES.join(', ')}`);
331
- fmt.log.info(`Exclude globs: ${COVERAGE_EXCLUDES.join(', ')}`);
332
- fmt.log.info(`Would run: ${fmt.command(`${process.execPath} ${buildCoverageArgs(testFiles, threshold).join(' ')}`)}`);
333
- process.exit(0);
334
- }
335
- registerExitHandlers();
336
- process.exit(runTests(testFiles, threshold));
337
- }
338
- if (typeof require !== 'undefined' && require.main === module) {
339
- main();
340
- }
341
- function run(args, options = {}) {
342
- const exitFn = options.exitFn || process.exit;
343
- let threshold_ = 90;
344
- let dryRun_ = false;
345
- for (let i = 0; i < args.length; i++) {
346
- if (args[i] === '--threshold' && args[i + 1]) {
347
- threshold_ = parseFloat(args[i + 1]);
348
- i++;
349
- }
350
- else if (args[i] === '--dry-run') {
351
- dryRun_ = true;
352
- }
353
- }
354
- const savedThreshold = threshold;
355
- const savedDryRun = dryRun;
356
- threshold = threshold_;
357
- dryRun = dryRun_;
358
- try {
359
- if (dryRun_) {
360
- const testFiles = discoverTestFiles();
361
- if (testFiles.length === 0) {
362
- if (typeof exitFn === 'function') {
363
- exitFn(1);
364
- }
365
- }
366
- else {
367
- fmt.log.info(`Found ${testFiles.length} test file(s)`);
368
- fmt.log.info(`DRY-RUN mode — threshold=${threshold}%`);
369
- fmt.log.info('Denominator: index.js + lib/**/*.js');
370
- fmt.log.info(`Include globs: ${COVERAGE_INCLUDES.join(', ')}`);
371
- fmt.log.info(`Exclude globs: ${COVERAGE_EXCLUDES.join(', ')}`);
372
- fmt.log.info(`Would run: ${fmt.command(`${process.execPath} ${buildCoverageArgs(testFiles, threshold).join(' ')}`)}`);
373
- if (typeof exitFn === 'function') {
374
- exitFn(0);
375
- }
376
- else {
377
- process.exit(0);
378
- }
379
- }
380
- }
381
- else {
382
- registerExitHandlers();
383
- exitFn(runTests(discoverTestFiles(), threshold));
384
- }
385
- }
386
- finally {
387
- threshold = savedThreshold;
388
- dryRun = savedDryRun;
389
- }
390
- }
391
- run.buildCoverageArgs = buildCoverageArgs;
392
- run.cleanupNewTempDirs = cleanupNewTempDirs;
393
- run.cleanupPerRunScratch = cleanupPerRunScratch;
394
- run.createPerRunScratchDirs = createPerRunScratchDirs;
395
- run.COVERAGE_EXCLUDES = COVERAGE_EXCLUDES;
396
- run.COVERAGE_INCLUDES = COVERAGE_INCLUDES;
397
- run.DEFAULT_TEST_TIMEOUT_MS = DEFAULT_TEST_TIMEOUT_MS;
398
- run.discoverTestFiles = discoverTestFiles;
399
- run.listTempEntries = listTempEntries;
400
- run.registerExitHandlers = registerExitHandlers;
401
- run.resetPerRunScratchState = resetPerRunScratchState;
402
- run.resolveTestTimeoutMs = resolveTestTimeoutMs;
403
- run.runTests = runTests;
404
- run.shouldCleanTempDir = shouldCleanTempDir;
405
- exports.default = run;
406
- if (typeof module !== 'undefined') {
407
- module.exports = run;
408
- }