@vibe-agent-toolkit/cli 0.2.0-rc.3 → 0.2.0-rc.5

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 (154) hide show
  1. package/dist/bin/vat +2 -1
  2. package/dist/bin/vat.js +2 -1
  3. package/dist/bin/vat.js.map +1 -1
  4. package/dist/bin.js +37 -3
  5. package/dist/bin.js.map +1 -1
  6. package/dist/commands/audit/distributed-tree.d.ts +1 -1
  7. package/dist/commands/audit/distributed-tree.d.ts.map +1 -1
  8. package/dist/commands/audit/distributed-tree.js +2 -1
  9. package/dist/commands/audit/distributed-tree.js.map +1 -1
  10. package/dist/commands/audit/git-url-clone.d.ts +1 -1
  11. package/dist/commands/audit/git-url-clone.d.ts.map +1 -1
  12. package/dist/commands/audit/git-url-clone.js.map +1 -1
  13. package/dist/commands/audit.d.ts.map +1 -1
  14. package/dist/commands/audit.js +25 -6
  15. package/dist/commands/audit.js.map +1 -1
  16. package/dist/commands/build.d.ts.map +1 -1
  17. package/dist/commands/build.js +14 -11
  18. package/dist/commands/build.js.map +1 -1
  19. package/dist/commands/cache/cache-control.d.ts +16 -7
  20. package/dist/commands/cache/cache-control.d.ts.map +1 -1
  21. package/dist/commands/cache/cache-control.js +17 -8
  22. package/dist/commands/cache/cache-control.js.map +1 -1
  23. package/dist/commands/claude/budget.js +1 -1
  24. package/dist/commands/claude/budget.js.map +1 -1
  25. package/dist/commands/claude/context.d.ts +138 -9
  26. package/dist/commands/claude/context.d.ts.map +1 -1
  27. package/dist/commands/claude/context.js +450 -80
  28. package/dist/commands/claude/context.js.map +1 -1
  29. package/dist/commands/claude/marketplace/git-publish.d.ts.map +1 -1
  30. package/dist/commands/claude/marketplace/git-publish.js +2 -1
  31. package/dist/commands/claude/marketplace/git-publish.js.map +1 -1
  32. package/dist/commands/claude/marketplace/validate.d.ts +18 -0
  33. package/dist/commands/claude/marketplace/validate.d.ts.map +1 -1
  34. package/dist/commands/claude/marketplace/validate.js +40 -20
  35. package/dist/commands/claude/marketplace/validate.js.map +1 -1
  36. package/dist/commands/claude/plugin/build.d.ts +17 -1
  37. package/dist/commands/claude/plugin/build.d.ts.map +1 -1
  38. package/dist/commands/claude/plugin/build.js +45 -16
  39. package/dist/commands/claude/plugin/build.js.map +1 -1
  40. package/dist/commands/claude/plugin/helpers.d.ts.map +1 -1
  41. package/dist/commands/claude/plugin/helpers.js +2 -1
  42. package/dist/commands/claude/plugin/helpers.js.map +1 -1
  43. package/dist/commands/claude/plugin/install.d.ts.map +1 -1
  44. package/dist/commands/claude/plugin/install.js +2 -2
  45. package/dist/commands/claude/plugin/install.js.map +1 -1
  46. package/dist/commands/claude/plugin/tree-copy.d.ts.map +1 -1
  47. package/dist/commands/claude/plugin/tree-copy.js +2 -1
  48. package/dist/commands/claude/plugin/tree-copy.js.map +1 -1
  49. package/dist/commands/consistency-check.d.ts.map +1 -1
  50. package/dist/commands/consistency-check.js +2 -1
  51. package/dist/commands/consistency-check.js.map +1 -1
  52. package/dist/commands/corpus/runner.d.ts.map +1 -1
  53. package/dist/commands/corpus/runner.js +3 -20
  54. package/dist/commands/corpus/runner.js.map +1 -1
  55. package/dist/commands/corpus/scan.d.ts.map +1 -1
  56. package/dist/commands/corpus/scan.js +2 -1
  57. package/dist/commands/corpus/scan.js.map +1 -1
  58. package/dist/commands/doctor.d.ts.map +1 -1
  59. package/dist/commands/doctor.js +3 -2
  60. package/dist/commands/doctor.js.map +1 -1
  61. package/dist/commands/inventory.js +2 -2
  62. package/dist/commands/inventory.js.map +1 -1
  63. package/dist/commands/phase-utils.d.ts +154 -103
  64. package/dist/commands/phase-utils.d.ts.map +1 -1
  65. package/dist/commands/phase-utils.js +109 -155
  66. package/dist/commands/phase-utils.js.map +1 -1
  67. package/dist/commands/resources/check-progress.d.ts +145 -0
  68. package/dist/commands/resources/check-progress.d.ts.map +1 -0
  69. package/dist/commands/resources/check-progress.js +205 -0
  70. package/dist/commands/resources/check-progress.js.map +1 -0
  71. package/dist/commands/resources/check-supervisor.d.ts +465 -0
  72. package/dist/commands/resources/check-supervisor.d.ts.map +1 -0
  73. package/dist/commands/resources/check-supervisor.js +566 -0
  74. package/dist/commands/resources/check-supervisor.js.map +1 -0
  75. package/dist/commands/resources/check.d.ts +454 -0
  76. package/dist/commands/resources/check.d.ts.map +1 -0
  77. package/dist/commands/resources/check.js +1237 -0
  78. package/dist/commands/resources/check.js.map +1 -0
  79. package/dist/commands/resources/index.d.ts.map +1 -1
  80. package/dist/commands/resources/index.js +277 -6
  81. package/dist/commands/resources/index.js.map +1 -1
  82. package/dist/commands/resources/query.d.ts +89 -0
  83. package/dist/commands/resources/query.d.ts.map +1 -0
  84. package/dist/commands/resources/query.js +146 -0
  85. package/dist/commands/resources/query.js.map +1 -0
  86. package/dist/commands/resources/scan.d.ts.map +1 -1
  87. package/dist/commands/resources/scan.js +2 -2
  88. package/dist/commands/resources/scan.js.map +1 -1
  89. package/dist/commands/resources/validate.d.ts +11 -0
  90. package/dist/commands/resources/validate.d.ts.map +1 -1
  91. package/dist/commands/resources/validate.js +96 -48
  92. package/dist/commands/resources/validate.js.map +1 -1
  93. package/dist/commands/skill/test/run.d.ts.map +1 -1
  94. package/dist/commands/skill/test/run.js +11 -2
  95. package/dist/commands/skill/test/run.js.map +1 -1
  96. package/dist/commands/skills/build.d.ts +10 -0
  97. package/dist/commands/skills/build.d.ts.map +1 -1
  98. package/dist/commands/skills/build.js +83 -25
  99. package/dist/commands/skills/build.js.map +1 -1
  100. package/dist/commands/skills/install.js +0 -1
  101. package/dist/commands/skills/install.js.map +1 -1
  102. package/dist/commands/skills/skill-discovery.d.ts.map +1 -1
  103. package/dist/commands/skills/skill-discovery.js +6 -3
  104. package/dist/commands/skills/skill-discovery.js.map +1 -1
  105. package/dist/commands/skills/validate.d.ts +78 -1
  106. package/dist/commands/skills/validate.d.ts.map +1 -1
  107. package/dist/commands/skills/validate.js +67 -32
  108. package/dist/commands/skills/validate.js.map +1 -1
  109. package/dist/commands/validate.d.ts.map +1 -1
  110. package/dist/commands/validate.js +26 -16
  111. package/dist/commands/validate.js.map +1 -1
  112. package/dist/commands/verify.d.ts +9 -8
  113. package/dist/commands/verify.d.ts.map +1 -1
  114. package/dist/commands/verify.js +46 -35
  115. package/dist/commands/verify.js.map +1 -1
  116. package/dist/utils/agent-runner.d.ts.map +1 -1
  117. package/dist/utils/agent-runner.js +7 -3
  118. package/dist/utils/agent-runner.js.map +1 -1
  119. package/dist/utils/command-error.d.ts +88 -2
  120. package/dist/utils/command-error.d.ts.map +1 -1
  121. package/dist/utils/command-error.js +98 -11
  122. package/dist/utils/command-error.js.map +1 -1
  123. package/dist/utils/config-loader.d.ts.map +1 -1
  124. package/dist/utils/config-loader.js +10 -3
  125. package/dist/utils/config-loader.js.map +1 -1
  126. package/dist/utils/issue-severity.d.ts +12 -5
  127. package/dist/utils/issue-severity.d.ts.map +1 -1
  128. package/dist/utils/issue-severity.js +1 -1
  129. package/dist/utils/issue-severity.js.map +1 -1
  130. package/dist/utils/population-wiring.d.ts +47 -6
  131. package/dist/utils/population-wiring.d.ts.map +1 -1
  132. package/dist/utils/population-wiring.js +45 -2
  133. package/dist/utils/population-wiring.js.map +1 -1
  134. package/dist/utils/projection-query.d.ts +263 -0
  135. package/dist/utils/projection-query.d.ts.map +1 -0
  136. package/dist/utils/projection-query.js +262 -0
  137. package/dist/utils/projection-query.js.map +1 -0
  138. package/dist/utils/projection-store.d.ts +110 -6
  139. package/dist/utils/projection-store.d.ts.map +1 -1
  140. package/dist/utils/projection-store.js +133 -9
  141. package/dist/utils/projection-store.js.map +1 -1
  142. package/dist/utils/resource-loader.d.ts +1 -1
  143. package/dist/utils/resource-loader.d.ts.map +1 -1
  144. package/dist/utils/resource-loader.js +11 -1
  145. package/dist/utils/resource-loader.js.map +1 -1
  146. package/dist/utils/vat-bin-path.d.ts +36 -0
  147. package/dist/utils/vat-bin-path.d.ts.map +1 -0
  148. package/dist/utils/vat-bin-path.js +49 -0
  149. package/dist/utils/vat-bin-path.js.map +1 -0
  150. package/package.json +25 -14
  151. package/dist/commands/resources/command-helpers.d.ts +0 -5
  152. package/dist/commands/resources/command-helpers.d.ts.map +0 -1
  153. package/dist/commands/resources/command-helpers.js +0 -6
  154. package/dist/commands/resources/command-helpers.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-supervisor.d.ts","sourceRoot":"","sources":["../../../src/commands/resources/check-supervisor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,566 @@
1
+ /**
2
+ * The time bound on `vat resources check`, enforced from OUTSIDE the process
3
+ * doing the work.
4
+ *
5
+ * ## ðŸšĻ Why an external process, and not any of the cheaper things
6
+ *
7
+ * This verb runs adopter-authored SQL as an unattended CI gate. An accidental
8
+ * cross join, or a `WITH RECURSIVE` with no termination, runs forever — and
9
+ * every in-process lever was tried and MEASURED on Node 24.13.1 before this
10
+ * shape was chosen. Do not re-derive them:
11
+ *
12
+ * - **A worker thread does not work.** `worker.terminate()` never resolves
13
+ * against a thread blocked in native SQLite, and the parent's own
14
+ * `process.exit()` does not exit either. V8 can unwind a worker spinning in
15
+ * JS — which is why the parse pool's `terminate()` genuinely works — but a
16
+ * thread inside a synchronous native call is not spinning in JS. Do NOT
17
+ * "align" this design with the parse pool's.
18
+ * - **A signal handler is a REGRESSION.** A process blocked in synchronous
19
+ * `node:sqlite` dies INSTANTLY on SIGINT while no handler is installed, and
20
+ * SURVIVES both SIGINT and SIGTERM once one is — the handler is a JS callback,
21
+ * and the event loop that would schedule it is the resource that is blocked.
22
+ * Installing one removes the operator's Ctrl-C. There is no
23
+ * `process.on('SIGINT')` here and there must never be.
24
+ * - **The kill is `SIGKILL` because SIGKILL cannot be REGRESSED.** No code the
25
+ * child runs, now or after any future edit, can handle, ignore or block it.
26
+ *
27
+ * ⚠ïļ This header used to claim, as measured fact, that "SIGTERM does not kill
28
+ * the child either, for the same reason". **That is false and was measured to
29
+ * be false**: `kill -TERM` on a child blocked inside synchronous `node:sqlite`
30
+ * `.all()` killed it instantly. The measurement above is about a process that
31
+ * HAS a JS handler installed — a handler is a JS callback and the blocked
32
+ * event loop is what would schedule it — and with no handler installed
33
+ * SIGTERM's default disposition is kernel-delivered termination that needs no
34
+ * cooperation at all. So SIGTERM works today only because nothing here
35
+ * installs a handler, which is a property one future edit could silently
36
+ * remove; SIGKILL is not a property anything can remove. The design did not
37
+ * change, only the reason for it — recorded because a false claim is at its
38
+ * worst in a section that tells the next reader not to re-derive it.
39
+ * - **The database cannot be handed over.** `DatabaseSync` has no `serialize()`
40
+ * and `:memory:` is per-CONNECTION, so whoever runs the SQL populates its own
41
+ * projection. That is why the child is a whole `vat resources check` run and
42
+ * not a query executor.
43
+ *
44
+ * ## 🔑 The budget is ABSENCE OF PROGRESS, not total runtime
45
+ *
46
+ * A total-runtime bound has to be set above the slowest legitimate run on the
47
+ * largest adopter tree, which makes it useless as a hang detector, and it kills
48
+ * healthy runs that are merely large. So the parent watches the child's progress
49
+ * log and resets its clock on every new line — INCLUDING the population line,
50
+ * which is what bounds the population itself without charging it the first
51
+ * check's budget. A gate that can hang forever is the thing being fixed, and
52
+ * that includes hanging before the first statement.
53
+ *
54
+ * ⚠ïļ **That property holds for the CHECKS. It does NOT hold for the population,
55
+ * and the difference is not a detail.** The population emits exactly ONE line,
56
+ * at its end, so for the single longest unit in a cold run the budget degrades
57
+ * to precisely the total-runtime bound this section argues against: a population
58
+ * that takes longer than the budget is killed however healthily it is working.
59
+ *
60
+ * That is not cheap to fix and a half-fix would be worse than saying so.
61
+ * `onContributorTiming` does fire per contributor, but ~88% of a cold population
62
+ * is the BLOB stage — one call, remark-parsing every document, 33-35 s of the
63
+ * 35 s — and it emits nothing. Per-contributor lines would therefore bound the
64
+ * cheap part, leave the expensive part exactly as unbounded as it is now, and
65
+ * make the whole thing LOOK instrumented. So the population stays one
66
+ * un-instrumented unit, the default budget is set well above a cold one, and the
67
+ * per-unit property is claimed only where it is true.
68
+ *
69
+ * ## Why the child is the CLI itself
70
+ *
71
+ * The child is `vat resources check` with a hidden `--cost-log` flag, running
72
+ * the ordinary in-process path. Forking the logic would give the supervised lane
73
+ * and the unsupervised one two implementations of the same gate — and the one
74
+ * nobody runs interactively is the one that would rot.
75
+ */
76
+ import { spawn } from 'node:child_process';
77
+ import { mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs';
78
+ import { safePath } from '@vibe-agent-toolkit/utils';
79
+ import { normalizedTmpdir } from '@vibe-agent-toolkit/utils/fs';
80
+ import { resolveVatBinPath } from '../../utils/vat-bin-path.js';
81
+ /**
82
+ * The bound applied when `--budget` is not passed, in seconds.
83
+ *
84
+ * Not a round number chosen for looks, and no longer sized against this
85
+ * repository alone. Population is ~1.2 s warm here and 33-35 s with a cold parse
86
+ * cache; on a real adopter tree of 9,992 tracked files it is ~5 s warm and
87
+ * **16.5 s cold**, which is the first time the default was checked outside VAT.
88
+ * So 300 s is ~18× the worst thing anyone has actually measured — deliberately
89
+ * loose, because a FALSE kill is far worse than a slow honest failure: it
90
+ * teaches the operator to pass `--budget 0` and lose the bound entirely. Five
91
+ * minutes still turns an infinite hang into a clean bounded failure, which is
92
+ * the whole objective. A tree ten times that adopter's lands near 165 s, still
93
+ * inside the default but no longer comfortably.
94
+ */
95
+ const DEFAULT_BUDGET_SECONDS = 300;
96
+ /** How many times per budget the parent looks at the log. */
97
+ const POLLS_PER_BUDGET = 10;
98
+ /** Poll bounds, so a huge budget still notices promptly and a tiny one is cheap. */
99
+ const MIN_POLL_MS = 50;
100
+ const MAX_POLL_MS = 250;
101
+ /**
102
+ * How many refused SIGKILLs the watchdog sends before it stops trying and
103
+ * REPORTS instead.
104
+ *
105
+ * A retry count, not a bound on anything stored. It exists because the two ways
106
+ * a kill can fail want opposite responses: `ESRCH` is a race that resolves
107
+ * itself the instant `close` arrives, while `EPERM` is a permission fact that
108
+ * will be just as true on the thousandth attempt. Retrying a handful of times
109
+ * covers the first at negligible cost; continuing past that would turn the
110
+ * supervisor into a second unbounded hang, which is the thing this module
111
+ * exists to abolish. So it escalates to an honest report naming the pid.
112
+ */
113
+ const KILL_ATTEMPTS_BEFORE_REPORTING = 5;
114
+ /**
115
+ * Decide whether the child has gone quiet for longer than the budget.
116
+ *
117
+ * Pure, and separated from the timer for exactly that reason: the interesting
118
+ * behaviour is "a run that keeps making progress is never killed, however long
119
+ * it takes", and a test of that against a real timer would be a twenty-second
120
+ * test that flakes. Here it is twenty function calls.
121
+ *
122
+ * ðŸŠĪ Growth is measured in BYTES rather than parsed lines. A partially written
123
+ * line also grows the file, and treating that as progress is the safe direction:
124
+ * the child is demonstrably alive and writing. Counting lines instead would mean
125
+ * a very slow write could look like silence.
126
+ *
127
+ * @param state - What the previous poll saw
128
+ * @param observation - The run
129
+ * @param observation.bytes - The progress log's current size
130
+ * @param observation.now - The clock, in milliseconds
131
+ * @param observation.budgetMs - How long silence is allowed to last
132
+ * @returns The state to carry forward, and whether the budget was blown
133
+ */
134
+ export function pollWatchdog(state, observation) {
135
+ if (observation.bytes !== state.bytesSeen) {
136
+ return { state: { bytesSeen: observation.bytes, quietSince: observation.now }, breach: false };
137
+ }
138
+ return { state, breach: observation.now - state.quietSince >= observation.budgetMs };
139
+ }
140
+ /**
141
+ * Read `--budget`, or supply the default.
142
+ *
143
+ * ðŸŠĪ A typo is REFUSED rather than defaulted. `--budget 2O` (letter O) would
144
+ * otherwise run with a five-minute bound while the operator believed they had
145
+ * set two seconds — and they would only find out from a CI job that hung for
146
+ * five minutes instead of two. Thrown, so it exits 2 as an operator error, in
147
+ * line with this command's existing contract for an unknown `--check` name.
148
+ *
149
+ * ðŸšĻ **A BLANK value is refused before `Number` ever sees it, and that is the
150
+ * more important half.** `Number('')`, `Number(' ')` and `Number('\n')` are all
151
+ * `0` — finite, non-negative, and therefore accepted by the range guard below —
152
+ * and `0` is this flag's documented escape hatch meaning *no bound at all*. So
153
+ * `--budget "$CHECK_BUDGET"` with the variable unset did not shorten the bound
154
+ * and did not complain: it silently REMOVED it, on the one flag whose entire
155
+ * purpose is to stop an unattended job hanging forever. An unset shell variable
156
+ * is a far more common CI accident than the typo the guard was written for.
157
+ *
158
+ * ðŸšĻ **The blank string was only the visible half of the hazard, and the guard
159
+ * below it is the rest.** What actually removes the bound is `Number(raw) === 0`
160
+ * for a raw string nobody would recognise as a zero — `--budget 1e-400`
161
+ * underflows to `0`, and `--budget -0` is negative zero, which sails past the
162
+ * `seconds < 0` test because `-0 < 0` is false. Both were MEASURED to run
163
+ * completely unbounded, in process, exiting 0 with no supervision and no word
164
+ * said. So a value that PARSES to zero is refused unless the operator literally
165
+ * wrote a zero: `raw.trim() !== '0'` and it is an operator error. The escape
166
+ * hatch is still there, it just has to be spelled the one unambiguous way.
167
+ *
168
+ * ⚠ïļ That deliberately refuses `0.0` and `0x0` as well. They are not accidents
169
+ * an operator can fall into, they cost one character to rewrite, and a guard
170
+ * with an exception list is a guard whose next exception nobody argues about.
171
+ *
172
+ * 🔑 **Non-zero hex is deliberately KEPT.** `Number('0x10')` is 16 and
173
+ * `--budget 0x10` runs with a sixteen-second bound. That is unambiguous, it
174
+ * cannot arise by accident the way an empty variable can, and refusing it would
175
+ * buy nothing — recorded here so the next reader does not "fix" it into a
176
+ * refusal.
177
+ *
178
+ * @param raw - Whatever Commander parsed, or undefined
179
+ * @returns The budget in seconds; 0 means no bound
180
+ * @throws When the value is blank, means zero without saying so, or is not a
181
+ * non-negative number
182
+ */
183
+ export function parseBudgetSeconds(raw) {
184
+ if (raw === undefined)
185
+ return DEFAULT_BUDGET_SECONDS;
186
+ if (raw.trim() === '') {
187
+ throw new Error('--budget was given an empty value. That is almost always an unset shell'
188
+ + ' variable (`--budget "$CHECK_BUDGET"`), and it is refused rather than read'
189
+ + ' as `--budget 0` — which would remove the bound entirely and let the run'
190
+ + ' hang forever. Pass a number of seconds, or `--budget 0` explicitly if that'
191
+ + ' is really what you mean.');
192
+ }
193
+ const seconds = Number(raw);
194
+ if (!Number.isFinite(seconds) || seconds < 0) {
195
+ throw new Error(`--budget must be a non-negative number of seconds, not "${raw}".`
196
+ + ` It bounds how long the run may go without completing a unit of work;`
197
+ + ` --budget 0 removes the bound entirely (and can then hang forever).`);
198
+ }
199
+ if (seconds === 0 && raw.trim() !== '0') {
200
+ throw new Error(`--budget "${raw}" is a number that means ZERO — and 0 is this flag's escape`
201
+ + ' hatch for "no bound at all", so the run would have gone entirely'
202
+ + ' unsupervised and could hang forever. `1e-400` underflows to zero and `-0`'
203
+ + ' is negative zero, neither of which reads as a request to remove the bound.'
204
+ + ' Pass a positive number of seconds, or exactly `--budget 0` if removing it'
205
+ + ' is really what you mean.');
206
+ }
207
+ return seconds;
208
+ }
209
+ /**
210
+ * Does this process do the work, or supervise a child that does?
211
+ *
212
+ * ðŸšĻ **The recursion guard, and the reason it is a named function.** `--cost-log`
213
+ * is what a supervising parent hands its child, and it must WIN against the
214
+ * budget — a child that consulted the budget first would spawn a child of its
215
+ * own, which would spawn a child of its own. A condition inline in the command
216
+ * would be a fork bomb one refactor away with nothing asserting on it.
217
+ *
218
+ * `--budget 0` also runs here: there is nothing to supervise, and a spawn would
219
+ * cost a second process startup to buy no bound at all.
220
+ *
221
+ * @param options - The run
222
+ * @param options.costLog - The hidden `--cost-log` value, or undefined
223
+ * @param options.budgetSecs - The bound in seconds; 0 means none
224
+ * @returns True when the checks run in this process
225
+ */
226
+ export function runsInThisProcess(options) {
227
+ return options.costLog !== undefined || options.budgetSecs === 0;
228
+ }
229
+ /**
230
+ * Refuse a combination where one flag the operator passed would do nothing.
231
+ *
232
+ * ðŸšĻ **The defect: `--cost-log` wins the fork above unconditionally**, so
233
+ * `vat resources check --budget 60 --cost-log /tmp/x` ran entirely UNBOUNDED and
234
+ * said nothing about it. That is harmless to the recursion guard — a child must
235
+ * keep winning — but an explicitly-passed, documented flag that is silently
236
+ * inert is exactly the shape an operator never discovers until the hang it was
237
+ * meant to prevent.
238
+ *
239
+ * ⚠ïļ **The real spawn path must survive this.** {@link runsInThisProcess}'s
240
+ * caller builds the child's argv with `--cost-log` and does NOT forward
241
+ * `--budget` — which is why the RAW flag is the discriminator here rather than
242
+ * the parsed seconds: the child's `budgetSecs` is the 300 s default, not
243
+ * anything the operator typed.
244
+ *
245
+ * `--budget 0` alongside `--cost-log` is allowed: both say "nobody is
246
+ * supervising this", so there is no contradiction to report.
247
+ *
248
+ * @param options - The run
249
+ * @param options.costLog - The hidden `--cost-log` value, or undefined
250
+ * @param options.budgetRaw - What the operator actually typed for `--budget`
251
+ * @param options.budgetSecs - The parsed bound; 0 means none
252
+ * @throws When both flags were passed and the budget could not be honoured
253
+ */
254
+ export function requireSupervisableFlags(options) {
255
+ if (options.costLog === undefined)
256
+ return;
257
+ if (options.budgetRaw === undefined || options.budgetSecs === 0)
258
+ return;
259
+ throw new Error('--budget cannot be combined with --cost-log. --cost-log means "you are the'
260
+ + ' child a supervisor already spawned", so this process does the work rather'
261
+ + ' than bounding it, and the budget would be silently ignored. Drop one:'
262
+ + ' --budget alone gets you the bound, --cost-log alone gets you the progress'
263
+ + ' log with no bound at all.');
264
+ }
265
+ /**
266
+ * Read `close`'s two arguments, and the watchdog's belief, into one answer.
267
+ *
268
+ * ## ðŸšĻ The defect this closes: a signal death READ AS SUCCESS
269
+ *
270
+ * `close` fires with `(code, signal)`, and a process that dies from a signal has
271
+ * `code === null` with `signal` set. This handler used to read only the code and
272
+ * coerce it — `resolve(exitCode ?? 0)` — so every signal death became a
273
+ * COMPLETED run with exit code 0. The parent then forwarded an empty stdout and
274
+ * exited 0, and a CI gate reads that as a clean pass.
275
+ *
276
+ * It needed no external actor. A check whose statement materialises an unbounded
277
+ * result set — `SELECT i FROM <infinite recursive CTE>`, the row-returning twin
278
+ * of the aggregate this whole module exists for — makes `.all()` fill the heap
279
+ * until V8 gives up and Node ABORTS. Measured: `PARENT_EXIT=0`, zero bytes of
280
+ * stdout, on precisely the input the bound exists to catch. Through the
281
+ * unsupervised lane the identical input exits 134.
282
+ *
283
+ * Every memory death arrives here: Node's own heap abort, a kernel OOM killer on
284
+ * a memory-capped runner (which picks the large CHILD, never the idle parent),
285
+ * and a container limit. `?? 0` turned all of them into a pass.
286
+ *
287
+ * ## ðŸŠĪ A kill only counts if it LANDED
288
+ *
289
+ * `killed` says the watchdog fired, not that the child died of it. libuv runs
290
+ * timers BEFORE the poll phase that reaps the child, so the timer can fire in
291
+ * the same loop turn as a child that has already exited cleanly. A NORMAL ending
292
+ * — a non-null code with no signal — is therefore honoured whatever `killed`
293
+ * says: that run finished on its own terms and its answer is real. Reporting it
294
+ * as killed fails closed, but it discards a correct result, which is its own
295
+ * kind of wrong.
296
+ *
297
+ * ## ðŸšĻ The ORDER of the tests below is load-bearing
298
+ *
299
+ * `spawnError` used to be tested FIRST, so `killed` was never consulted on that
300
+ * branch — and `child.on('error')` is not only a spawn-failure listener. Node
301
+ * emits `error` on the ChildProcess when `subprocess.kill()` itself fails, so a
302
+ * refused SIGKILL landed on the spawn-failure branch and the report said the
303
+ * child "could not be started at all", that "nothing ran at all, so this is an
304
+ * installation or PATH problem", and that "the watchdog never fired". Three
305
+ * statements, all false, about a runaway that was still executing.
306
+ *
307
+ * So: a real ending first, then what the SUPERVISOR did (a refused kill, then a
308
+ * kill), and only then a failure to start. A run whose kill was refused must
309
+ * never claim the watchdog was uninvolved.
310
+ *
311
+ * @param ending - What `close` reported, plus what the supervisor did and saw
312
+ * @param ending.code - `close`'s first argument
313
+ * @param ending.signal - `close`'s second argument
314
+ * @param ending.killed - Whether the watchdog sent SIGKILL
315
+ * @param ending.spawnError - Set when the child never started at all
316
+ * @param ending.killFailure - Set when the watchdog's SIGKILL was REFUSED
317
+ * @returns What actually happened
318
+ */
319
+ export function resolveChildEnding(ending) {
320
+ if (ending.code !== null && ending.signal === null) {
321
+ return { kind: 'completed', code: ending.code };
322
+ }
323
+ if (ending.killFailure !== undefined) {
324
+ return { kind: 'abnormal', death: { kind: 'kill-failed', ...ending.killFailure } };
325
+ }
326
+ if (ending.killed)
327
+ return { kind: 'killed' };
328
+ if (ending.spawnError !== undefined) {
329
+ return { kind: 'abnormal', death: { kind: 'spawn-failed', ...ending.spawnError } };
330
+ }
331
+ return ending.signal === null
332
+ ? { kind: 'abnormal', death: { kind: 'no-status' } }
333
+ : { kind: 'abnormal', death: { kind: 'signal', signal: ending.signal } };
334
+ }
335
+ /**
336
+ * Reconcile "how the process ended" with "what it left behind".
337
+ *
338
+ * ## ðŸšĻ A completion that PUBLISHED NOTHING did not complete
339
+ *
340
+ * {@link resolveChildEnding} answers a question about the process — what `close`
341
+ * reported, reconciled with what the supervisor did. This answers a DIFFERENT
342
+ * one, about the artifact, and the two disagree in exactly one place: a child
343
+ * that exited with a code and wrote no document.
344
+ *
345
+ * Every in-process path through `checkCommand` ends at `emitCheckDocument` or at
346
+ * `handleCommandError`, and both write to stdout — a clean pass, a violation, a
347
+ * bricked config, a mistyped `--check`. There is no exit this command can take
348
+ * that legitimately publishes nothing. So an empty stdout is not a quiet run, it
349
+ * is a run that was cut off before it could say anything, and forwarding its
350
+ * exit code verbatim tells the operator a number and nothing else.
351
+ *
352
+ * ## ðŸŠĪ Why this is not folded into {@link resolveChildEnding}
353
+ *
354
+ * That function's branch ORDER is load-bearing and reasoned entirely about
355
+ * process endings and supervisor beliefs. The emptiness of stdout belongs to
356
+ * neither, and threading it through would put an artifact test inside an
357
+ * ordering argument that has already been got wrong twice. It runs AFTER, on the
358
+ * one branch it can change, and it changes no other.
359
+ *
360
+ * ⚠ïļ **Blank, not unparseable.** The parent forwards the child's document
361
+ * verbatim precisely so it stays `--format`-agnostic, so it cannot ask whether
362
+ * the bytes parse without learning the format. A truncated document — an abort
363
+ * that landed mid-write — therefore still forwards, and that is the honest
364
+ * limit of this test rather than an oversight.
365
+ *
366
+ * @param resolution - How the process ended
367
+ * @param stdout - Everything the child wrote to stdout
368
+ * @returns The resolution, with a silent completion re-read as abnormal
369
+ */
370
+ export function resolveSilentCompletion(resolution, stdout) {
371
+ if (resolution.kind !== 'completed' || stdout.trim() !== '')
372
+ return resolution;
373
+ return { kind: 'abnormal', death: { kind: 'no-output', code: resolution.code } };
374
+ }
375
+ /**
376
+ * Run `vat resources check` as a child, bounded by the budget.
377
+ *
378
+ * `stdio` is `['ignore', 'pipe', 'inherit']`: the child's stdout is accumulated
379
+ * so the parent can forward the document verbatim, and its stderr is INHERITED
380
+ * so warnings and blob-stage refusals stream live exactly as they do today.
381
+ *
382
+ * ⚠ïļ Asynchronous `spawn`, never `spawnSync`. The parent's event loop is the
383
+ * thing holding the watchdog timer; a synchronous spawn would block it for
384
+ * precisely as long as the run it is supposed to be bounding.
385
+ *
386
+ * ðŸšĻ There is an `error` listener as well as a `close` one, and it is not
387
+ * optional politeness: without it an unspawnable binary is an unhandled `error`
388
+ * event, which Node turns into a stack dump instead of a report. It fails
389
+ * closed, so this is legibility — but a stack dump is not a report.
390
+ *
391
+ * ## ðŸšĻ `error` is NOT only a spawn-failure listener, and reading it as one
392
+ * ABANDONED A LIVE CHILD
393
+ *
394
+ * Node emits `error` on the ChildProcess when `subprocess.kill()` itself fails.
395
+ * The shipped function ends `else { /* Other error, almost certainly EPERM. *\/
396
+ * this.emit('error', new ErrnoException(err, 'kill')); }`. So: the watchdog
397
+ * breached, `killed` was set, the SIGKILL was refused, `error` fired, the
398
+ * handler recorded a SPAWN failure and resolved immediately — which cleared the
399
+ * watchdog timer, so no further kill could ever be attempted — and the parent
400
+ * published a report saying the child "could not be started at all" and "the
401
+ * watchdog never fired" while the runaway was still executing. The bound this
402
+ * module exists to enforce became an orphaned unbounded hang, described as its
403
+ * own opposite.
404
+ *
405
+ * The handler therefore forks on `killed`, and the two arms are deliberately
406
+ * asymmetric:
407
+ *
408
+ * - **Before the watchdog fired**, an `error` means the child never started.
409
+ * Resolve at once: there is nothing alive to wait for.
410
+ * - **After it fired**, an `error` means the KILL failed and the child is,
411
+ * as far as this process can tell, still running. Do NOT resolve. Resolving
412
+ * is what clears the timer, and clearing the timer is what makes the failure
413
+ * permanent. The poll keeps breaching (the log is not growing and
414
+ * `quietSince` is not reset), so it keeps re-sending SIGKILL, and a transient
415
+ * refusal still lands. Only after {@link KILL_ATTEMPTS_BEFORE_REPORTING}
416
+ * refusals does it give up — and it gives up by REPORTING, naming the pid,
417
+ * never by claiming the child never started.
418
+ *
419
+ * ⚠ïļ Reachability of `EPERM` on one's own child is REASONED rather than
420
+ * reproduced — it is rare on macOS and Linux. Nothing in production was
421
+ * contorted to make it testable; the branch ordering and the message
422
+ * composition are pure functions and are pinned as such.
423
+ *
424
+ * @param options - The run
425
+ * @param options.args - The child's argv after the node binary, `--cost-log` included
426
+ * @param options.logPath - The progress log both sides agreed on
427
+ * @param options.budgetMs - How long silence is allowed to last
428
+ * @returns How the child ended, and what it left behind
429
+ */
430
+ export async function superviseCheck(options) {
431
+ const startedAt = Date.now();
432
+ const binary = resolveVatBinPath();
433
+ const child = spawn(process.execPath, [binary, ...options.args], {
434
+ stdio: ['ignore', 'pipe', 'inherit'],
435
+ });
436
+ const chunks = [];
437
+ child.stdout?.on('data', (chunk) => chunks.push(chunk));
438
+ let killed = false;
439
+ let killAttempts = 0;
440
+ let killFailure;
441
+ let spawnError;
442
+ let state = { bytesSeen: 0, quietSince: startedAt };
443
+ // ðŸŠĪ Declared out here and started INSIDE the promise, so the watchdog can
444
+ // settle the run itself when it runs out of kills. Starting it outside would
445
+ // put the escalation out of the timer's reach and force the `error` handler
446
+ // back into resolving on a child that is still alive.
447
+ let timer;
448
+ const resolution = await new Promise((resolve) => {
449
+ // ðŸŠĪ `error` does not always end the process, and it is not always followed
450
+ // by `close` — so a SPAWN failure is remembered and resolved on immediately.
451
+ // A promise settles once, so whichever event arrives first wins and the
452
+ // other is a no-op. A failed KILL is the opposite case: see this function's
453
+ // header for why it must not settle here.
454
+ child.on('error', (cause) => {
455
+ if (killed) {
456
+ killFailure = { detail: cause.message, pid: child.pid };
457
+ return;
458
+ }
459
+ spawnError = { binary, detail: cause.message };
460
+ resolve(resolveChildEnding({ code: null, signal: null, killed, spawnError }));
461
+ });
462
+ // ⛔ BOTH arguments. `exitCode ?? 0` here read every signal death as a
463
+ // successful run — see {@link resolveChildEnding}.
464
+ child.on('close', (code, signal) => {
465
+ resolve(resolveChildEnding({ code, signal, killed, spawnError, killFailure }));
466
+ });
467
+ timer = setInterval(() => {
468
+ const poll = pollWatchdog(state, {
469
+ bytes: logSize(options.logPath),
470
+ now: Date.now(),
471
+ budgetMs: options.budgetMs,
472
+ });
473
+ state = poll.state;
474
+ if (!poll.breach)
475
+ return;
476
+ killed = true;
477
+ killAttempts += 1;
478
+ // SIGKILL, because no code the child could ever gain can handle, ignore
479
+ // or block it. See this module's header — and note the reason is NOT that
480
+ // SIGTERM fails to reach a blocked process, which was measured false.
481
+ child.kill('SIGKILL');
482
+ if (killFailure !== undefined && killAttempts >= KILL_ATTEMPTS_BEFORE_REPORTING) {
483
+ resolve(resolveChildEnding({ code: null, signal: null, killed, killFailure }));
484
+ }
485
+ }, pollIntervalMs(options.budgetMs));
486
+ });
487
+ clearInterval(timer);
488
+ const stdout = Buffer.concat(chunks).toString('utf-8');
489
+ // ðŸšĻ AFTER the ending is resolved, never inside it. A child that exited with a
490
+ // code and published nothing did not complete, whatever `close` said — see
491
+ // {@link resolveSilentCompletion} for the platform this is about.
492
+ const ending = resolveSilentCompletion(resolution, stdout);
493
+ if (ending.kind === 'completed') {
494
+ return { outcome: 'completed', code: ending.code, stdout };
495
+ }
496
+ const wreckage = { log: readLog(options.logPath), elapsedMs: Date.now() - startedAt };
497
+ return ending.kind === 'killed'
498
+ ? { outcome: 'killed', ...wreckage }
499
+ : { outcome: 'abnormal', death: ending.death, ...wreckage };
500
+ }
501
+ /**
502
+ * How often to look at the log.
503
+ *
504
+ * Derived from the budget rather than fixed, so `--budget 2` notices in 200 ms
505
+ * while `--budget 600` does not wake the event loop 12,000 times for nothing.
506
+ *
507
+ * @param budgetMs - The budget
508
+ * @returns The poll interval in milliseconds
509
+ */
510
+ function pollIntervalMs(budgetMs) {
511
+ return Math.min(MAX_POLL_MS, Math.max(MIN_POLL_MS, budgetMs / POLLS_PER_BUDGET));
512
+ }
513
+ /**
514
+ * The progress log's size, or 0 before the child has written anything.
515
+ *
516
+ * ðŸŠĪ A missing file is 0, not an error. The child creates the log on its first
517
+ * emission, so every poll before that legitimately finds nothing — and throwing
518
+ * there would kill the supervisor instead of the runaway.
519
+ *
520
+ * @param path - The progress log
521
+ * @returns Its size in bytes
522
+ */
523
+ function logSize(path) {
524
+ try {
525
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- a path this process minted for this run
526
+ return statSync(path).size;
527
+ }
528
+ catch {
529
+ return 0;
530
+ }
531
+ }
532
+ /**
533
+ * Whatever of the log survived the kill.
534
+ *
535
+ * @param path - The progress log
536
+ * @returns Its contents, or the empty string when the child never wrote one
537
+ */
538
+ function readLog(path) {
539
+ try {
540
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- a path this process minted for this run
541
+ return readFileSync(path, 'utf-8');
542
+ }
543
+ catch {
544
+ return '';
545
+ }
546
+ }
547
+ /**
548
+ * Run `work` with a fresh progress log, and remove it however that ends.
549
+ *
550
+ * ⚠ïļ Ephemeral, per run, and it carries NO format version — see
551
+ * `check-progress.ts`. It is written and read by one process pair within one run
552
+ * of one build, so the reader's own `.strict()` schema is the entire contract.
553
+ *
554
+ * @param work - Given the log's path
555
+ * @returns Whatever `work` returned
556
+ */
557
+ export async function withProgressLog(work) {
558
+ const dir = mkdtempSync(safePath.join(normalizedTmpdir(), 'vat-check-'));
559
+ try {
560
+ return await work(safePath.join(dir, 'progress.jsonl'));
561
+ }
562
+ finally {
563
+ rmSync(dir, { recursive: true, force: true });
564
+ }
565
+ }
566
+ //# sourceMappingURL=check-supervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-supervisor.js","sourceRoot":"","sources":["../../../src/commands/resources/check-supervisor.ts"],"names":[],"mappings":"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"}