picopilot 0.1.4 → 0.2.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 (172) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +111 -16
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/audio.d.ts +3 -3
  5. package/dist/commands/audio.d.ts.map +1 -1
  6. package/dist/commands/audio.js +61 -44
  7. package/dist/commands/audio.js.map +1 -1
  8. package/dist/commands/cart-includes.d.ts +11 -0
  9. package/dist/commands/cart-includes.d.ts.map +1 -0
  10. package/dist/commands/cart-includes.js +26 -0
  11. package/dist/commands/cart-includes.js.map +1 -0
  12. package/dist/commands/doctor.d.ts +22 -0
  13. package/dist/commands/doctor.d.ts.map +1 -0
  14. package/dist/commands/doctor.js +222 -0
  15. package/dist/commands/doctor.js.map +1 -0
  16. package/dist/commands/export.d.ts +3 -4
  17. package/dist/commands/export.d.ts.map +1 -1
  18. package/dist/commands/export.js +66 -86
  19. package/dist/commands/export.js.map +1 -1
  20. package/dist/commands/gfx.d.ts +2 -2
  21. package/dist/commands/gfx.d.ts.map +1 -1
  22. package/dist/commands/gfx.js +3 -2
  23. package/dist/commands/gfx.js.map +1 -1
  24. package/dist/commands/label-cart.d.ts +72 -0
  25. package/dist/commands/label-cart.d.ts.map +1 -0
  26. package/dist/commands/label-cart.js +228 -0
  27. package/dist/commands/label-cart.js.map +1 -0
  28. package/dist/commands/lint.d.ts +2 -2
  29. package/dist/commands/lint.d.ts.map +1 -1
  30. package/dist/commands/lint.js +3 -2
  31. package/dist/commands/lint.js.map +1 -1
  32. package/dist/commands/minify.d.ts +2 -2
  33. package/dist/commands/minify.d.ts.map +1 -1
  34. package/dist/commands/minify.js +3 -2
  35. package/dist/commands/minify.js.map +1 -1
  36. package/dist/commands/pico8-env.d.ts +76 -0
  37. package/dist/commands/pico8-env.d.ts.map +1 -0
  38. package/dist/commands/pico8-env.js +71 -0
  39. package/dist/commands/pico8-env.js.map +1 -0
  40. package/dist/commands/playtest.d.ts +2 -2
  41. package/dist/commands/playtest.d.ts.map +1 -1
  42. package/dist/commands/playtest.js +6 -32
  43. package/dist/commands/playtest.js.map +1 -1
  44. package/dist/commands/run.d.ts +3 -4
  45. package/dist/commands/run.d.ts.map +1 -1
  46. package/dist/commands/run.js +46 -19
  47. package/dist/commands/run.js.map +1 -1
  48. package/dist/commands/serve.d.ts +2 -2
  49. package/dist/commands/serve.d.ts.map +1 -1
  50. package/dist/commands/serve.js +65 -19
  51. package/dist/commands/serve.js.map +1 -1
  52. package/dist/commands/shrinko-env.d.ts +22 -0
  53. package/dist/commands/shrinko-env.d.ts.map +1 -0
  54. package/dist/commands/shrinko-env.js +15 -0
  55. package/dist/commands/shrinko-env.js.map +1 -0
  56. package/dist/commands/tokens.d.ts +4 -4
  57. package/dist/commands/tokens.d.ts.map +1 -1
  58. package/dist/commands/tokens.js +3 -2
  59. package/dist/commands/tokens.js.map +1 -1
  60. package/dist/commands/verify.d.ts +2 -2
  61. package/dist/commands/verify.d.ts.map +1 -1
  62. package/dist/commands/verify.js +3 -2
  63. package/dist/commands/verify.js.map +1 -1
  64. package/dist/engine/child-env.d.ts +14 -0
  65. package/dist/engine/child-env.d.ts.map +1 -0
  66. package/dist/engine/child-env.js +21 -0
  67. package/dist/engine/child-env.js.map +1 -0
  68. package/dist/engine/gfx/label.d.ts +15 -9
  69. package/dist/engine/gfx/label.d.ts.map +1 -1
  70. package/dist/engine/gfx/label.js +130 -38
  71. package/dist/engine/gfx/label.js.map +1 -1
  72. package/dist/engine/pico8/adapter.d.ts +23 -3
  73. package/dist/engine/pico8/adapter.d.ts.map +1 -1
  74. package/dist/engine/pico8/adapter.js.map +1 -1
  75. package/dist/engine/pico8/cleanup.d.ts +16 -0
  76. package/dist/engine/pico8/cleanup.d.ts.map +1 -0
  77. package/dist/engine/pico8/cleanup.js +74 -0
  78. package/dist/engine/pico8/cleanup.js.map +1 -0
  79. package/dist/engine/pico8/display.d.ts +149 -0
  80. package/dist/engine/pico8/display.d.ts.map +1 -0
  81. package/dist/engine/pico8/display.js +311 -0
  82. package/dist/engine/pico8/display.js.map +1 -0
  83. package/dist/engine/pico8/drive.d.ts.map +1 -1
  84. package/dist/engine/pico8/drive.js +28 -2
  85. package/dist/engine/pico8/drive.js.map +1 -1
  86. package/dist/engine/pico8/harness.d.ts +8 -0
  87. package/dist/engine/pico8/harness.d.ts.map +1 -1
  88. package/dist/engine/pico8/harness.js +9 -1
  89. package/dist/engine/pico8/harness.js.map +1 -1
  90. package/dist/engine/pico8/index.d.ts +3 -0
  91. package/dist/engine/pico8/index.d.ts.map +1 -1
  92. package/dist/engine/pico8/index.js +3 -0
  93. package/dist/engine/pico8/index.js.map +1 -1
  94. package/dist/engine/pico8/session-daemon-entry.d.ts +1 -1
  95. package/dist/engine/pico8/session-daemon-entry.js +1 -1
  96. package/dist/engine/pico8/session-daemon-main.d.ts +1 -1
  97. package/dist/engine/pico8/session-daemon-main.js +1 -1
  98. package/dist/engine/pico8/session-daemon.d.ts +1 -1
  99. package/dist/engine/pico8/session-daemon.d.ts.map +1 -1
  100. package/dist/engine/pico8/session-daemon.js +19 -19
  101. package/dist/engine/pico8/session-daemon.js.map +1 -1
  102. package/dist/engine/pico8/session.d.ts +1 -1
  103. package/dist/engine/pico8/session.js +1 -1
  104. package/dist/engine/pico8/shell.d.ts +56 -3
  105. package/dist/engine/pico8/shell.d.ts.map +1 -1
  106. package/dist/engine/pico8/shell.js +188 -24
  107. package/dist/engine/pico8/shell.js.map +1 -1
  108. package/dist/engine/pico8/supervisor.d.ts +1 -1
  109. package/dist/engine/pico8/supervisor.js +1 -1
  110. package/dist/engine/shrinko/adapter.d.ts +1 -1
  111. package/dist/engine/shrinko/shell.d.ts +3 -3
  112. package/dist/engine/shrinko/shell.js +3 -3
  113. package/package.json +2 -1
  114. package/src/cli.test.ts +188 -0
  115. package/src/cli.ts +122 -16
  116. package/src/commands/audio.test.ts +76 -1
  117. package/src/commands/audio.ts +79 -57
  118. package/src/commands/cart-includes.ts +27 -0
  119. package/src/commands/doctor.test.ts +149 -0
  120. package/src/commands/doctor.ts +280 -0
  121. package/src/commands/export.test.ts +327 -3
  122. package/src/commands/export.ts +81 -99
  123. package/src/commands/gfx.ts +7 -6
  124. package/src/commands/label-cart.ts +304 -0
  125. package/src/commands/lint.test.ts +6 -0
  126. package/src/commands/lint.ts +7 -6
  127. package/src/commands/minify.test.ts +6 -0
  128. package/src/commands/minify.ts +7 -6
  129. package/src/commands/pico8-env.ts +124 -0
  130. package/src/commands/playtest.test.ts +3 -0
  131. package/src/commands/playtest.ts +10 -34
  132. package/src/commands/run.test.ts +116 -2
  133. package/src/commands/run.ts +62 -24
  134. package/src/commands/serve.test.ts +138 -2
  135. package/src/commands/serve.ts +80 -21
  136. package/src/commands/shrinko-env.test.ts +68 -0
  137. package/src/commands/shrinko-env.ts +40 -0
  138. package/src/commands/tokens.test.ts +19 -0
  139. package/src/commands/tokens.ts +9 -6
  140. package/src/commands/verify.test.ts +12 -0
  141. package/src/commands/verify.ts +7 -4
  142. package/src/engine/child-env.ts +22 -0
  143. package/src/engine/gfx/fixtures/pico8-screenshot-384.png +0 -0
  144. package/src/engine/gfx/label.test.ts +467 -1
  145. package/src/engine/gfx/label.ts +147 -41
  146. package/src/engine/pico8/adapter.ts +25 -3
  147. package/src/engine/pico8/cleanup.test.ts +28 -0
  148. package/src/engine/pico8/cleanup.ts +76 -0
  149. package/src/engine/pico8/display.test.ts +210 -0
  150. package/src/engine/pico8/display.ts +429 -0
  151. package/src/engine/pico8/drive.test.ts +20 -0
  152. package/src/engine/pico8/drive.ts +25 -2
  153. package/src/engine/pico8/fake-xvfb.test-support.ts +55 -0
  154. package/src/engine/pico8/harness.test.ts +26 -0
  155. package/src/engine/pico8/harness.ts +18 -2
  156. package/src/engine/pico8/index.ts +3 -0
  157. package/src/engine/pico8/session-daemon-entry.ts +1 -1
  158. package/src/engine/pico8/session-daemon-main.ts +1 -1
  159. package/src/engine/pico8/session-daemon.test.ts +32 -1
  160. package/src/engine/pico8/session-daemon.ts +25 -17
  161. package/src/engine/pico8/session.test.ts +1 -1
  162. package/src/engine/pico8/session.ts +1 -1
  163. package/src/engine/pico8/shell.test.ts +449 -10
  164. package/src/engine/pico8/shell.ts +255 -26
  165. package/src/engine/pico8/supervisor.ts +1 -1
  166. package/src/engine/pico8/virtual-display.process.test.ts +206 -0
  167. package/src/engine/shrinko/adapter.ts +1 -1
  168. package/src/engine/shrinko/shell.ts +3 -3
  169. package/src/engine/skills/skills.test.ts +10 -0
  170. package/src/skills/picopilot-audio/SKILL.md +4 -8
  171. package/src/skills/picopilot-debug/SKILL.md +18 -1
  172. package/src/skills/picopilot-overview/SKILL.md +9 -1
@@ -1,8 +1,11 @@
1
1
  import { spawn } from 'node:child_process';
2
- import { existsSync, mkdirSync, mkdtempSync, readdirSync, statSync, } from 'node:fs';
2
+ import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
4
  import { join } from 'node:path';
5
5
  import { EXPORT_HTML_NAME, pico8NotFound, RECORD_WAV_BASENAME, } from './adapter.js';
6
+ import { DEFAULT_DISPLAY_MODE, findExecutable, needsVirtualDisplay, startVirtualDisplay, } from './display.js';
7
+ import { overlayEnv } from '../child-env.js';
8
+ import { killOnAbort } from './cleanup.js';
6
9
  import { SentinelWatcher } from './sentinel.js';
7
10
  /**
8
11
  * The default {@link SpawnRunner}: `spawn` with stdin detached (`ignore`) so the
@@ -39,6 +42,63 @@ export function withPico8Home(args) {
39
42
  mkdirSync(home, { recursive: true });
40
43
  return ['-home', home, ...args];
41
44
  }
45
+ /**
46
+ * The environment PICO-8 is spawned with: the parent env overlaid with the
47
+ * picopilot-resolved values ({@link overlayEnv}). A `-run` session cannot open a
48
+ * window or an audio device without DISPLAY, HOME, XDG_RUNTIME_DIR, SDL_*, ...
49
+ */
50
+ export function pico8ChildEnv(resolved, parent) {
51
+ return overlayEnv(resolved, parent);
52
+ }
53
+ /**
54
+ * A private `XDG_RUNTIME_DIR` (mode 0700, one per picopilot process) for a
55
+ * PICO-8 launched without one. SDL logs "XDG_RUNTIME_DIR is invalid or not set"
56
+ * otherwise, which is noise in every headless report.
57
+ */
58
+ let cachedRuntimeDir;
59
+ export function pico8RuntimeDir() {
60
+ if (cachedRuntimeDir !== undefined && existsSync(cachedRuntimeDir)) {
61
+ return cachedRuntimeDir;
62
+ }
63
+ cachedRuntimeDir = mkdtempSync(join(tmpdir(), 'picopilot-xdg-runtime-'));
64
+ return cachedRuntimeDir;
65
+ }
66
+ /** `env` with a private {@link pico8RuntimeDir} filled in when XDG_RUNTIME_DIR is absent. */
67
+ export function withRuntimeDir(env) {
68
+ const current = env.XDG_RUNTIME_DIR;
69
+ if (current !== undefined && current.trim() !== '')
70
+ return env;
71
+ return { ...env, XDG_RUNTIME_DIR: pico8RuntimeDir() };
72
+ }
73
+ /** How many lines of PICO-8's `log.txt` a failed record reports. */
74
+ const LOG_TAIL_LINES = 25;
75
+ /** The last lines of PICO-8's `log.txt` in the isolated `-home`, or undefined if absent. */
76
+ export function readPico8LogTail(home = pico8HomeDir(), lines = LOG_TAIL_LINES) {
77
+ try {
78
+ const text = readFileSync(join(home, 'log.txt'), 'utf8');
79
+ const all = text.trimEnd().split('\n');
80
+ return all.slice(-lines).join('\n');
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ }
86
+ /**
87
+ * Says WHY a record run produced no WAV, from how it ended. The sentinel is the
88
+ * harness's last act (after `audio_end`), so anything other than a sentinel
89
+ * means the harness never finished; a sentinel with no WAV means `audio_end`
90
+ * saved nothing usable.
91
+ */
92
+ export function explainNoWav(exitReason, ctx) {
93
+ switch (exitReason) {
94
+ case 'timeout':
95
+ return `the backstop fired after ${ctx.backstopMs}ms before the record harness printed its done-sentinel: the cart never reached audio_end (it failed to load, errored at runtime, or its game loop never ran). See pico8LogTail and printh.`;
96
+ case 'exit':
97
+ return 'PICO-8 exited before the record harness printed its done-sentinel: the cart failed to load or crashed, or PICO-8 itself could not start (e.g. no display or audio device). See pico8LogTail and printh.';
98
+ case 'sentinel':
99
+ return `the record harness reached its done-sentinel but no non-empty ${ctx.basename}.wav was written to ${ctx.wavDir}: audio_end saved nothing usable (an empty 0-frame capture).`;
100
+ }
101
+ }
42
102
  export const spawnRunner = (file, args, env, options) => {
43
103
  // `drive` pipes fixed-size command blocks to stdin; `run`/`record` detach it so
44
104
  // the cart never blocks on console input.
@@ -69,14 +129,14 @@ export const spawnRunner = (file, args, env, options) => {
69
129
  // A closed stdin (the cart exited) is not fatal to the run.
70
130
  }
71
131
  },
72
- kill() {
132
+ kill(signal = 'SIGKILL') {
73
133
  try {
74
134
  // Negative pid kills the process GROUP (detached), so any child dies too.
75
135
  if (child.pid !== undefined)
76
- process.kill(-child.pid, 'SIGKILL');
136
+ process.kill(-child.pid, signal);
77
137
  }
78
138
  catch {
79
- child.kill('SIGKILL'); // fall back to killing just the process
139
+ child.kill(signal); // fall back to killing just the process
80
140
  }
81
141
  },
82
142
  };
@@ -143,6 +203,8 @@ function collectWav(wavDir, basename) {
143
203
  }
144
204
  return path;
145
205
  }
206
+ /** The default SIGTERM-to-SIGKILL grace for a gracefully-ended run. */
207
+ export const DEFAULT_KILL_GRACE_MS = 2_000;
146
208
  /**
147
209
  * The v1 {@link Pico8Adapter}: shells out to the user's native `pico8 -x`
148
210
  * (ADR-0006, native path first). It owns the ORCHESTRATION the command should
@@ -156,9 +218,15 @@ function collectWav(wavDir, basename) {
156
218
  export class ShellPico8Adapter {
157
219
  env;
158
220
  spawnRun;
221
+ display;
222
+ virtualDisplay;
223
+ killGraceMs;
159
224
  constructor(options) {
225
+ this.killGraceMs = options.killGraceMs ?? DEFAULT_KILL_GRACE_MS;
160
226
  this.env = options.env;
161
227
  this.spawnRun = options.spawn ?? spawnRunner;
228
+ this.display = options.display ?? DEFAULT_DISPLAY_MODE;
229
+ this.virtualDisplay = options.virtualDisplay ?? {};
162
230
  }
163
231
  run(options) {
164
232
  const [file] = pico8Candidates(this.env);
@@ -246,20 +314,80 @@ export class ShellPico8Adapter {
246
314
  });
247
315
  }
248
316
  record(options) {
317
+ if (needsVirtualDisplay(this.display, this.env)) {
318
+ return this.recordOnVirtualDisplay(options);
319
+ }
320
+ return this.recordWith(options, 'native');
321
+ }
322
+ /**
323
+ * The record session on a private virtual display (ADR-0017): start Xvfb
324
+ * (or fall back to `xvfb-run`), run PICO-8 on it with a dummy SDL audio
325
+ * driver (unless the caller chose one; `audio_rec` captures PICO-8's own
326
+ * mixer, not the device), and ALWAYS stop the display afterwards, however
327
+ * the run ended (sentinel, backstop, crash, spawn failure).
328
+ */
329
+ async recordOnVirtualDisplay(options) {
330
+ const [file] = pico8Candidates(this.env);
331
+ // Absent PICO-8 is reported as such BEFORE paying for (or failing on) a
332
+ // display, and wrapped in xvfb-run a missing binary would not ENOENT.
333
+ const find = this.virtualDisplay.find ?? findExecutable;
334
+ if (find(file, this.env) === undefined)
335
+ return pico8NotFound();
336
+ const started = await startVirtualDisplay(this.env, this.virtualDisplay);
337
+ if (!started.ok)
338
+ return started;
339
+ const vd = started.display;
340
+ try {
341
+ const env = { ...this.env, ...vd.env };
342
+ const audioDriver = env.SDL_AUDIODRIVER;
343
+ if (audioDriver === undefined || audioDriver.trim() === '') {
344
+ env.SDL_AUDIODRIVER = 'dummy';
345
+ }
346
+ return await this.recordWith(options, vd.backend, {
347
+ env,
348
+ wrap: (f, a) => vd.wrap(f, a),
349
+ // xvfb-run's Xvfb lives in PICO-8's process group: SIGTERM first so it
350
+ // removes its /tmp/.X<n>-lock and socket (a SIGKILL leaves them behind).
351
+ endGracefully: vd.backend === 'xvfb-run',
352
+ });
353
+ }
354
+ finally {
355
+ await vd.stop();
356
+ }
357
+ }
358
+ /** The record launch itself, natively or under a virtual display's env/wrapper. */
359
+ recordWith(options, display, launch) {
249
360
  const [file] = pico8Candidates(this.env);
250
361
  const basename = options.wavBasename ?? RECORD_WAV_BASENAME;
251
362
  // `-root_path <wavDir>` steers the `audio_end(1)`-to-current-folder WAV into
252
363
  // the isolated temp dir (never ~/Desktop or the carts root). `-run` is a real
253
364
  // A/V session (recording needs audio to capture; `-x` yields an empty WAV).
254
365
  const args = ['-root_path', options.wavDir, '-run', options.cartPath];
255
- return this.orchestrate(file, args, { sentinel: options.sentinel, backstopMs: options.backstopMs }, (exitReason, printh) => ({
256
- ok: true,
257
- value: {
258
- wavPath: collectWav(options.wavDir, basename),
259
- printh,
260
- exitReason,
261
- },
262
- }));
366
+ // The `-home` is shared by every launch in this process: drop the previous
367
+ // log.txt so a failed record never reports another run's log as its own.
368
+ rmSync(join(pico8HomeDir(), 'log.txt'), { force: true });
369
+ return this.orchestrate(file, args, { sentinel: options.sentinel, backstopMs: options.backstopMs }, (exitReason, printh) => {
370
+ const wavPath = collectWav(options.wavDir, basename);
371
+ if (wavPath !== undefined) {
372
+ return { ok: true, value: { wavPath, printh, exitReason, display } };
373
+ }
374
+ const pico8LogTail = readPico8LogTail();
375
+ return {
376
+ ok: true,
377
+ value: {
378
+ wavPath,
379
+ printh,
380
+ exitReason,
381
+ display,
382
+ noWavReason: explainNoWav(exitReason, {
383
+ backstopMs: options.backstopMs,
384
+ wavDir: options.wavDir,
385
+ basename,
386
+ }),
387
+ ...(pico8LogTail !== undefined ? { pico8LogTail } : {}),
388
+ },
389
+ };
390
+ }, launch);
263
391
  }
264
392
  /**
265
393
  * The shared launch/sentinel-watch/backstop/collect loop behind both
@@ -274,16 +402,49 @@ export class ShellPico8Adapter {
274
402
  return new Promise((resolve) => {
275
403
  let settled = false;
276
404
  let backstop;
277
- const proc = this.spawnRun(file, withPico8Home(args), this.env, {
278
- stdin: spawnOpts?.stdin,
279
- });
280
- const finish = (exitReason) => {
405
+ const homeArgs = withPico8Home(args);
406
+ const launch = spawnOpts?.wrap !== undefined
407
+ ? spawnOpts.wrap(file, homeArgs)
408
+ : { file, args: homeArgs };
409
+ const proc = this.spawnRun(launch.file, launch.args, withRuntimeDir(spawnOpts?.env ?? this.env), { stdin: spawnOpts?.stdin });
410
+ // If picopilot itself is stopped mid-run, take PICO-8 down with it.
411
+ const disposeAbort = killOnAbort(() => proc.kill());
412
+ let onClosed;
413
+ /**
414
+ * Ends the run once. `kill` = PICO-8 is still running (sentinel/backstop):
415
+ * SIGKILL its group, or for a graceful end SIGTERM it and resolve when it
416
+ * has closed (SIGKILL after the grace period).
417
+ */
418
+ const finish = (exitReason, kill = false) => {
281
419
  if (settled)
282
420
  return;
283
421
  settled = true;
284
422
  if (backstop !== undefined)
285
423
  clearTimeout(backstop);
286
- resolve(buildOk(exitReason, watcher.text));
424
+ let resolved = false;
425
+ const done = () => {
426
+ if (resolved)
427
+ return;
428
+ resolved = true;
429
+ // Only now: a signal during the graceful wait must still kill PICO-8.
430
+ disposeAbort();
431
+ resolve(buildOk(exitReason, watcher.text));
432
+ };
433
+ if (!kill)
434
+ return done();
435
+ if (spawnOpts?.endGracefully !== true) {
436
+ proc.kill();
437
+ return done();
438
+ }
439
+ proc.kill('SIGTERM');
440
+ const hard = setTimeout(() => {
441
+ proc.kill();
442
+ done();
443
+ }, this.killGraceMs);
444
+ onClosed = () => {
445
+ clearTimeout(hard);
446
+ done();
447
+ };
287
448
  };
288
449
  proc.onError((err) => {
289
450
  // A spawn ENOENT ⇒ PICO-8 is absent (a bad PICO8_PATH surfaces as absence
@@ -293,6 +454,7 @@ export class ShellPico8Adapter {
293
454
  return;
294
455
  if (err.code === 'ENOENT') {
295
456
  settled = true;
457
+ disposeAbort();
296
458
  if (backstop !== undefined)
297
459
  clearTimeout(backstop);
298
460
  resolve(pico8NotFound());
@@ -302,12 +464,15 @@ export class ShellPico8Adapter {
302
464
  }
303
465
  });
304
466
  proc.onStdout((chunk) => {
305
- if (watcher.push(chunk) && !settled) {
306
- proc.kill(); // sentinel matched: end the run promptly
307
- finish('sentinel');
308
- }
467
+ // sentinel matched: end the run promptly
468
+ if (watcher.push(chunk) && !settled)
469
+ finish('sentinel', true);
470
+ });
471
+ proc.onClose(() => {
472
+ if (onClosed !== undefined)
473
+ return onClosed();
474
+ finish('exit'); // PICO-8 exited on its own
309
475
  });
310
- proc.onClose(() => finish('exit')); // PICO-8 exited on its own
311
476
  // For `drive`: write the command blocks to the live stdin now that it is
312
477
  // spawned. A spawn ENOENT resolves via onError before this matters.
313
478
  spawnOpts?.onSpawn?.(proc);
@@ -315,8 +480,7 @@ export class ShellPico8Adapter {
315
480
  backstop = setTimeout(() => {
316
481
  if (settled)
317
482
  return;
318
- proc.kill();
319
- finish('timeout');
483
+ finish('timeout', true);
320
484
  }, opts.backstopMs);
321
485
  });
322
486
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/engine/pico8/shell.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/engine/pico8/shell.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The playtest SESSION SUPERVISOR (ADR-0011, prd US #6): the daemon that keeps a
2
+ * The playtest SESSION SUPERVISOR (ADR-0011, spec US #6): the daemon that keeps a
3
3
  * driven PICO-8 process ALIVE + PAUSED across the agent's separate CLI turns, and
4
4
  * the client the per-verb sub-invocations use to address it BY ID.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The playtest SESSION SUPERVISOR (ADR-0011, prd US #6): the daemon that keeps a
2
+ * The playtest SESSION SUPERVISOR (ADR-0011, spec US #6): the daemon that keeps a
3
3
  * driven PICO-8 process ALIVE + PAUSED across the agent's separate CLI turns, and
4
4
  * the client the per-verb sub-invocations use to address it BY ID.
5
5
  *
@@ -23,7 +23,7 @@ export declare const SHRINKO_REMEDY: "uv pip install shrinko";
23
23
  export declare const SHRINKO_NEEDS: readonly ["python>=3.8"];
24
24
  /**
25
25
  * The structured "shrinko is not installed" failure (ADR-0002). Its shape is
26
- * fixed by the prd's two-tier contract (US #17): `ok:false`, a machine-readable
26
+ * fixed by the spec's two-tier contract (US #17): `ok:false`, a machine-readable
27
27
  * `reason`, the EXACT `remedy` string, and the `needs` list. A command turns
28
28
  * this into an incur `error({ code: reason, ... })` with a nonzero exit.
29
29
  */
@@ -23,9 +23,9 @@ export type ChildRunner = (file: string, args: string[], env: NodeJS.ProcessEnv)
23
23
  * The default {@link ChildRunner}: an `execFile` that captures stdout/stderr and
24
24
  * NEVER rejects. A failed spawn (ENOENT) becomes `spawnError`; a nonzero exit
25
25
  * becomes a `code`, so both outcomes are data the adapter maps to a structured
26
- * result. The child inherits ONLY the `env` it is handed (the command layer
27
- * passes the incur-resolved env, whose `PATH` a test can override) so there is
28
- * no ambient-environment leak.
26
+ * result. The child gets exactly the `env` it is handed and reads nothing
27
+ * ambiently; the command layer builds that env as the parent env overlaid with
28
+ * the resolved `PATH` (`commands/shrinko-env.ts`), and a test injects its own.
29
29
  */
30
30
  export declare const execFileRunner: ChildRunner;
31
31
  /** Options for {@link ShellShrinkoAdapter}. */
@@ -4,9 +4,9 @@ import { parseCount, parseLint, shrinkoNotFound, } from './adapter.js';
4
4
  * The default {@link ChildRunner}: an `execFile` that captures stdout/stderr and
5
5
  * NEVER rejects. A failed spawn (ENOENT) becomes `spawnError`; a nonzero exit
6
6
  * becomes a `code`, so both outcomes are data the adapter maps to a structured
7
- * result. The child inherits ONLY the `env` it is handed (the command layer
8
- * passes the incur-resolved env, whose `PATH` a test can override) so there is
9
- * no ambient-environment leak.
7
+ * result. The child gets exactly the `env` it is handed and reads nothing
8
+ * ambiently; the command layer builds that env as the parent env overlaid with
9
+ * the resolved `PATH` (`commands/shrinko-env.ts`), and a test injects its own.
10
10
  */
11
11
  export const execFileRunner = (file, args, env) => new Promise((resolve) => {
12
12
  execFile(file, args, { env, encoding: 'utf8' }, (error, stdout, stderr) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picopilot",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "An agent-first toolchain for PICO-8 game development, built on the incur CLI framework.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -42,6 +42,7 @@
42
42
  },
43
43
  "scripts": {
44
44
  "build": "tsc -p tsconfig.build.json",
45
+ "typecheck": "tsc -p tsconfig.json",
45
46
  "dev": "as-soon -w src pnpm build",
46
47
  "test": "vitest run",
47
48
  "test:watch": "vitest",
@@ -0,0 +1,188 @@
1
+ import {mkdtempSync, rmSync, writeFileSync} from 'node:fs';
2
+ import {tmpdir} from 'node:os';
3
+ import {join} from 'node:path';
4
+ import {z} from 'incur';
5
+ import {afterEach, beforeEach, describe, expect, it} from 'vitest';
6
+ import {createCli} from './cli.js';
7
+ import {displayModeOf} from './commands/pico8-env.js';
8
+
9
+ /**
10
+ * The display mode (ADR-0017) is resolved ONCE, globally, by the root CLI:
11
+ * `--display` > `PICOPILOT_DISPLAY` > picopilot.json `display` > `auto`. A probe
12
+ * command mounted on the real CLI reports what a command handler sees.
13
+ */
14
+
15
+ let dir: string;
16
+ beforeEach(() => {
17
+ dir = mkdtempSync(join(tmpdir(), 'picopilot-cli-'));
18
+ });
19
+ afterEach(() => rmSync(dir, {recursive: true, force: true}));
20
+
21
+ async function probe(
22
+ argv: string[],
23
+ env: Record<string, string | undefined> = {},
24
+ config?: unknown,
25
+ ) {
26
+ const cli = createCli();
27
+ cli.command('probe-display', {
28
+ run: (c) => ({display: displayModeOf(c.var)}),
29
+ });
30
+ const args = [...argv];
31
+ if (config !== undefined) {
32
+ const path = join(dir, 'picopilot.json');
33
+ writeFileSync(path, JSON.stringify(config));
34
+ args.push('--config', path);
35
+ }
36
+ let stdout = '';
37
+ let exitCode = 0;
38
+ await cli.serve([...args, '--json'], {
39
+ stdout(s) {
40
+ stdout += s;
41
+ },
42
+ exit(code) {
43
+ exitCode = code;
44
+ },
45
+ env,
46
+ });
47
+ return {out: JSON.parse(stdout), exitCode};
48
+ }
49
+
50
+ describe('display mode resolution through the CLI', () => {
51
+ it('defaults to auto', async () => {
52
+ expect((await probe(['probe-display'])).out.display).toBe('auto');
53
+ });
54
+
55
+ it('reads picopilot.json "display"', async () => {
56
+ const {out} = await probe(['probe-display'], {}, {display: 'native'});
57
+ expect(out.display).toBe('native');
58
+ });
59
+
60
+ it('PICOPILOT_DISPLAY beats picopilot.json', async () => {
61
+ const {out} = await probe(
62
+ ['probe-display'],
63
+ {PICOPILOT_DISPLAY: 'xvfb'},
64
+ {display: 'native'},
65
+ );
66
+ expect(out.display).toBe('xvfb');
67
+ });
68
+
69
+ it('--display beats both, before or after the command', async () => {
70
+ for (const argv of [
71
+ ['--display', 'native', 'probe-display'],
72
+ ['probe-display', '--display', 'native'],
73
+ ]) {
74
+ const {out} = await probe(
75
+ argv,
76
+ {PICOPILOT_DISPLAY: 'xvfb'},
77
+ {display: 'xvfb'},
78
+ );
79
+ expect(out.display).toBe('native');
80
+ }
81
+ });
82
+
83
+ it('an invalid PICOPILOT_DISPLAY is an error for a display command, not a silent auto', async () => {
84
+ const cli = createCli();
85
+ let stdout = '';
86
+ let exitCode = 0;
87
+ await cli.serve(['run', join(dir, 'none.p8'), '--json'], {
88
+ stdout(s) {
89
+ stdout += s;
90
+ },
91
+ exit(code) {
92
+ exitCode = code;
93
+ },
94
+ env: {PICOPILOT_DISPLAY: 'xfvb'},
95
+ });
96
+ expect(exitCode).not.toBe(0);
97
+ const out = JSON.parse(stdout);
98
+ expect(out.code).toBe('invalid-display-mode');
99
+ expect(out.message).toContain('PICOPILOT_DISPLAY');
100
+ });
101
+
102
+ it('an invalid value does not break commands that never use the display', async () => {
103
+ const cli = createCli();
104
+ let stdout = '';
105
+ let exitCode = 0;
106
+ await cli.serve(['version', '--json'], {
107
+ stdout(s) {
108
+ stdout += s;
109
+ },
110
+ exit(code) {
111
+ exitCode = code;
112
+ },
113
+ env: {PICOPILOT_DISPLAY: 'xfvb'},
114
+ });
115
+ expect(exitCode).toBe(0);
116
+ expect(JSON.parse(stdout).name).toBe('picopilot');
117
+ });
118
+
119
+ it('--no-config ignores the picopilot.json display key', async () => {
120
+ const path = join(dir, 'picopilot.json');
121
+ writeFileSync(path, JSON.stringify({display: 'native'}));
122
+ // First load it (so a stale value could leak), then disable config.
123
+ const cli = createCli();
124
+ cli.command('probe-display', {
125
+ run: (c) => ({display: displayModeOf(c.var)}),
126
+ });
127
+ const outs: string[] = [];
128
+ for (const argv of [
129
+ ['probe-display', '--config', path, '--json'],
130
+ ['probe-display', '--no-config', '--json'],
131
+ ]) {
132
+ let stdout = '';
133
+ await cli.serve(argv, {
134
+ stdout(s) {
135
+ stdout += s;
136
+ },
137
+ exit() {},
138
+ env: {},
139
+ });
140
+ outs.push(JSON.parse(stdout).display);
141
+ }
142
+ expect(outs).toEqual(['native', 'auto']);
143
+ });
144
+
145
+ it('--config naming a missing file is an error', async () => {
146
+ const cli = createCli();
147
+ let stdout = '';
148
+ let exitCode = 0;
149
+ await cli.serve(['version', '--config', join(dir, 'nope.json'), '--json'], {
150
+ stdout(s) {
151
+ stdout += s;
152
+ },
153
+ exit(code) {
154
+ exitCode = code;
155
+ },
156
+ env: {},
157
+ });
158
+ expect(exitCode).not.toBe(0);
159
+ expect(stdout).toContain('not found');
160
+ });
161
+
162
+ it('a per-command config option still loads next to the display key', async () => {
163
+ // The custom config loader must keep incur's per-command option defaults.
164
+ const cli = createCli();
165
+ let seen: unknown;
166
+ cli.command('probe-opt', {
167
+ options: z.object({flag: z.boolean().default(false)}),
168
+ run: (c) => {
169
+ seen = c.options.flag;
170
+ return {};
171
+ },
172
+ });
173
+ const path = join(dir, 'picopilot.json');
174
+ writeFileSync(
175
+ path,
176
+ JSON.stringify({
177
+ display: 'native',
178
+ commands: {'probe-opt': {options: {flag: true}}},
179
+ }),
180
+ );
181
+ await cli.serve(['probe-opt', '--config', path, '--json'], {
182
+ stdout() {},
183
+ exit() {},
184
+ env: {},
185
+ });
186
+ expect(seen).toBe(true);
187
+ });
188
+ });