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
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Kill-on-abort for child processes picopilot owns while a run is in flight
3
+ * (the PICO-8 process group, a private Xvfb). Normal endings (sentinel,
4
+ * backstop, crash) are handled by the run itself; this covers picopilot being
5
+ * stopped mid-run: `process.exit`, an uncaught throw, or SIGINT / SIGTERM /
6
+ * SIGHUP sent to picopilot alone (an agent harness or `timeout` killing it).
7
+ * Without it, a detached PICO-8 or an Xvfb would outlive picopilot.
8
+ *
9
+ * `kill` must be synchronous (it runs inside an `exit` handler). On a signal,
10
+ * the hook kills, then re-raises the signal with picopilot's handler removed so
11
+ * the default behaviour (terminate) still happens, unless some other listener
12
+ * owns that signal (an MCP server, a test runner), which then decides.
13
+ */
14
+ const SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'];
15
+ /**
16
+ * The kill functions of every run in flight. ONE listener per event serves them
17
+ * all (installed while the set is non-empty), so many concurrent runs (an MCP
18
+ * server) never trip Node's MaxListeners warning.
19
+ */
20
+ const pending = new Set();
21
+ const signalHandlers = new Map();
22
+ function killAll() {
23
+ for (const kill of [...pending]) {
24
+ pending.delete(kill);
25
+ try {
26
+ kill();
27
+ }
28
+ catch {
29
+ // best effort: the process may already be gone
30
+ }
31
+ }
32
+ }
33
+ function onExit() {
34
+ killAll();
35
+ }
36
+ function install() {
37
+ process.on('exit', onExit);
38
+ for (const signal of SIGNALS) {
39
+ const handler = () => {
40
+ killAll();
41
+ uninstall();
42
+ // Re-raise for the default behaviour (terminate) unless another listener
43
+ // (an MCP server, a test runner) owns this signal.
44
+ if (process.listenerCount(signal) === 0) {
45
+ process.kill(process.pid, signal);
46
+ }
47
+ };
48
+ signalHandlers.set(signal, handler);
49
+ process.on(signal, handler);
50
+ }
51
+ }
52
+ function uninstall() {
53
+ process.removeListener('exit', onExit);
54
+ for (const [signal, handler] of signalHandlers) {
55
+ process.removeListener(signal, handler);
56
+ }
57
+ signalHandlers.clear();
58
+ }
59
+ /** Registers `kill` to run if picopilot exits or is signalled; returns the disposer. */
60
+ export function killOnAbort(kill) {
61
+ let entry = () => kill();
62
+ if (pending.size === 0)
63
+ install();
64
+ pending.add(entry);
65
+ return () => {
66
+ if (entry === undefined)
67
+ return;
68
+ pending.delete(entry);
69
+ entry = undefined;
70
+ if (pending.size === 0)
71
+ uninstall();
72
+ };
73
+ }
74
+ //# sourceMappingURL=cleanup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../../../src/engine/pico8/cleanup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,OAAO,GAA8B,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAE3E;;;;GAIG;AACH,MAAM,OAAO,GAAG,IAAI,GAAG,EAAc,CAAC;AACtC,MAAM,cAAc,GAAG,IAAI,GAAG,EAA8B,CAAC;AAE7D,SAAS,OAAO;IACf,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,CAAC;YACJ,IAAI,EAAE,CAAC;QACR,CAAC;QAAC,MAAM,CAAC;YACR,+CAA+C;QAChD,CAAC;IACF,CAAC;AACF,CAAC;AAED,SAAS,MAAM;IACd,OAAO,EAAE,CAAC;AACX,CAAC;AAED,SAAS,OAAO;IACf,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,GAAG,EAAE;YACpB,OAAO,EAAE,CAAC;YACV,SAAS,EAAE,CAAC;YACZ,yEAAyE;YACzE,mDAAmD;YACnD,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACnC,CAAC;QACF,CAAC,CAAC;QACF,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,CAAC;AACF,CAAC;AAED,SAAS,SAAS;IACjB,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,cAAc,EAAE,CAAC;QAChD,OAAO,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IACD,cAAc,CAAC,KAAK,EAAE,CAAC;AACxB,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC3C,IAAI,KAAK,GAA6B,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;IACnD,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,OAAO,GAAG,EAAE;QACX,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtB,KAAK,GAAG,SAAS,CAAC;QAClB,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,SAAS,EAAE,CAAC;IACrC,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * The DISPLAY MODE seam (ADR-0017): how a PICO-8 `-run` session (a real
3
+ * audio+video session, today only the audio-record path) gets a display on a
4
+ * machine that may have none (a server, CI, an agent sandbox).
5
+ *
6
+ * - `native`: spawn PICO-8 as-is (it uses whatever DISPLAY/WAYLAND_DISPLAY the
7
+ * caller has, or fails to open a window if there is none).
8
+ * - `xvfb`: always run a `-run` session on a private virtual X display.
9
+ * - `auto`: the default. Use a virtual display only when the session needs one
10
+ * and none is available (no DISPLAY and no WAYLAND_DISPLAY); otherwise native.
11
+ *
12
+ * Headless `-x` passes (run screenshots, playtest, export, the label capture)
13
+ * never need a display, so they never consult this module and never pay the
14
+ * Xvfb startup cost.
15
+ *
16
+ * The virtual display prefers spawning `Xvfb -displayfd <fd>` directly: the X
17
+ * server picks a free display number itself and writes it back on the fd, so
18
+ * parallel runs never race for a fixed `:99`. When only the Debian `xvfb-run`
19
+ * script exists, it is the fallback (it wraps the PICO-8 command instead).
20
+ * Either way the virtual display lives exactly as long as the run.
21
+ */
22
+ /** The three display modes. `auto` is the default. */
23
+ export declare const DISPLAY_MODES: readonly ["auto", "xvfb", "native"];
24
+ /** A display mode: how a `-run` session gets a display (see the module doc). */
25
+ export type DisplayMode = (typeof DISPLAY_MODES)[number];
26
+ /** The default display mode when no flag, env var or config sets one. */
27
+ export declare const DEFAULT_DISPLAY_MODE: DisplayMode;
28
+ /** The env var that sets the display mode (below the `--display` flag, above picopilot.json). */
29
+ export declare const DISPLAY_ENV_VAR: "PICOPILOT_DISPLAY";
30
+ /** The top-level picopilot.json key that sets the display mode (lowest precedence). */
31
+ export declare const DISPLAY_CONFIG_KEY: "display";
32
+ /** Whether `value` names a valid {@link DisplayMode}. */
33
+ export declare function isDisplayMode(value: unknown): value is DisplayMode;
34
+ /** The outcome of {@link resolveDisplayMode}: a mode and where it came from, or an invalid value. */
35
+ export type DisplayModeResolution = {
36
+ readonly ok: true;
37
+ readonly mode: DisplayMode;
38
+ readonly source: 'flag' | 'env' | 'config' | 'default';
39
+ } | {
40
+ readonly ok: false;
41
+ readonly source: 'flag' | 'env' | 'config';
42
+ readonly value: string;
43
+ };
44
+ /**
45
+ * Resolves the display mode with the precedence `flag > env > config > default`
46
+ * (the same order every picopilot setting uses). An empty/whitespace value is
47
+ * treated as unset; an unknown value is reported (never silently ignored), so a
48
+ * typo like `PICOPILOT_DISPLAY=xfvb` is a visible error rather than `auto`.
49
+ */
50
+ export declare function resolveDisplayMode(sources: {
51
+ readonly flag?: unknown;
52
+ readonly env?: unknown;
53
+ readonly config?: unknown;
54
+ }): DisplayModeResolution;
55
+ /** Whether the environment already offers a display (X11 `DISPLAY` or a Wayland socket). */
56
+ export declare function hasNativeDisplay(env: NodeJS.ProcessEnv): boolean;
57
+ /**
58
+ * Whether a `-run` session in this `mode` + `env` should run on a virtual
59
+ * display: always for `xvfb`, never for `native`, and for `auto` only when
60
+ * there is no native display.
61
+ */
62
+ export declare function needsVirtualDisplay(mode: DisplayMode, env: NodeJS.ProcessEnv): boolean;
63
+ /**
64
+ * Finds an executable the way a shell would: a name containing `/` is checked
65
+ * as a path, anything else is searched on `env.PATH`. Returns the resolved path,
66
+ * or `undefined`. Pure lookup (no spawn), so it is cheap enough for `doctor` and
67
+ * for the failure path.
68
+ */
69
+ export declare function findExecutable(name: string, env: NodeJS.ProcessEnv): string | undefined;
70
+ /** Which virtual-display backend this machine offers, if any (direct Xvfb is preferred). */
71
+ export type VirtualDisplayBackend = 'Xvfb' | 'xvfb-run';
72
+ /** Detects the best available virtual-display backend on `env.PATH`. */
73
+ export declare function detectVirtualDisplayBackend(env: NodeJS.ProcessEnv, find?: (name: string, env: NodeJS.ProcessEnv) => string | undefined): VirtualDisplayBackend | undefined;
74
+ /** The remedy a `display-unavailable` error names. */
75
+ export declare const DISPLAY_REMEDY: "install Xvfb (Debian/Ubuntu: apt install xvfb; Fedora: dnf install xorg-x11-server-Xvfb; NixOS: add xvfb-run or xorg.xvfb), or run under a desktop session (DISPLAY or WAYLAND_DISPLAY set)";
76
+ /**
77
+ * The structured "this session needs a display and there is none" failure
78
+ * (mirrors {@link import('./adapter.js').Pico8NotFound}). `detail` says what was
79
+ * tried (Xvfb missing, or Xvfb failed to start and why).
80
+ */
81
+ export interface DisplayUnavailable {
82
+ readonly ok: false;
83
+ readonly reason: 'display-unavailable';
84
+ readonly remedy: typeof DISPLAY_REMEDY;
85
+ readonly detail: string;
86
+ }
87
+ /** Builds a {@link DisplayUnavailable} value. */
88
+ export declare function displayUnavailable(detail: string): DisplayUnavailable;
89
+ /**
90
+ * A running virtual display, scoped to ONE PICO-8 session. `env` holds the
91
+ * variables the child must see (DISPLAY for direct Xvfb); `wrap` rewrites the
92
+ * PICO-8 command (identity for direct Xvfb, `xvfb-run -a ...` for the fallback);
93
+ * `stop` tears the X server down and is idempotent.
94
+ */
95
+ export interface VirtualDisplay {
96
+ readonly backend: VirtualDisplayBackend;
97
+ readonly env: Readonly<Record<string, string>>;
98
+ wrap(file: string, args: string[]): {
99
+ file: string;
100
+ args: string[];
101
+ };
102
+ stop(): Promise<void>;
103
+ }
104
+ /**
105
+ * A spawned Xvfb process, abstracted so tests inject a fake. `onDisplayFd`
106
+ * delivers what the server writes on its `-displayfd` pipe (the display number
107
+ * followed by a newline); `onExit` fires when it exits; `kill` sends a signal.
108
+ */
109
+ export interface XvfbProcess {
110
+ readonly pid: number | undefined;
111
+ onDisplayFd(cb: (chunk: string) => void): void;
112
+ onStderr(cb: (chunk: string) => void): void;
113
+ onExit(cb: (code: number | null) => void): void;
114
+ onError(cb: (err: NodeJS.ErrnoException) => void): void;
115
+ kill(signal: NodeJS.Signals): void;
116
+ }
117
+ /** The Xvfb spawn seam: tests pass a fake that writes a display number (or never does). */
118
+ export type XvfbSpawner = (file: string, args: string[], env: NodeJS.ProcessEnv) => XvfbProcess;
119
+ /**
120
+ * The real {@link XvfbSpawner}: stdio `[ignore, ignore, pipe, pipe]` so fd 3 is
121
+ * the display-number pipe. NOT detached, so a terminal Ctrl-C reaches it with
122
+ * the rest of picopilot's process group.
123
+ */
124
+ export declare const spawnXvfb: XvfbSpawner;
125
+ /** Dependencies for {@link startVirtualDisplay}, injectable for tests. */
126
+ export interface VirtualDisplayDeps {
127
+ /** Locates `Xvfb` / `xvfb-run` (defaults to a PATH search). */
128
+ readonly find?: (name: string, env: NodeJS.ProcessEnv) => string | undefined;
129
+ /** Spawns Xvfb (defaults to {@link spawnXvfb}). */
130
+ readonly spawnXvfb?: XvfbSpawner;
131
+ /** How long to wait for Xvfb to report its display number (ms). */
132
+ readonly startTimeoutMs?: number;
133
+ /** How long to wait after SIGTERM before SIGKILL on stop (ms). */
134
+ readonly stopGraceMs?: number;
135
+ }
136
+ /**
137
+ * Starts a private virtual display for one PICO-8 session. Prefers `Xvfb
138
+ * -displayfd` (no fixed display number, so parallel runs never collide), falls
139
+ * back to wrapping the command in `xvfb-run -a`, and resolves the structured
140
+ * {@link DisplayUnavailable} when neither exists or Xvfb fails to start. Never
141
+ * throws. The returned display MUST be stopped by the caller (the shell adapter
142
+ * does it in a `finally`); a kill-on-abort hook also kills a direct Xvfb so an
143
+ * abrupt picopilot exit or signal never leaves one behind.
144
+ */
145
+ export declare function startVirtualDisplay(env: NodeJS.ProcessEnv, deps?: VirtualDisplayDeps): Promise<{
146
+ ok: true;
147
+ display: VirtualDisplay;
148
+ } | DisplayUnavailable>;
149
+ //# sourceMappingURL=display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../../src/engine/pico8/display.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * The DISPLAY MODE seam (ADR-0017): how a PICO-8 `-run` session (a real
3
+ * audio+video session, today only the audio-record path) gets a display on a
4
+ * machine that may have none (a server, CI, an agent sandbox).
5
+ *
6
+ * - `native`: spawn PICO-8 as-is (it uses whatever DISPLAY/WAYLAND_DISPLAY the
7
+ * caller has, or fails to open a window if there is none).
8
+ * - `xvfb`: always run a `-run` session on a private virtual X display.
9
+ * - `auto`: the default. Use a virtual display only when the session needs one
10
+ * and none is available (no DISPLAY and no WAYLAND_DISPLAY); otherwise native.
11
+ *
12
+ * Headless `-x` passes (run screenshots, playtest, export, the label capture)
13
+ * never need a display, so they never consult this module and never pay the
14
+ * Xvfb startup cost.
15
+ *
16
+ * The virtual display prefers spawning `Xvfb -displayfd <fd>` directly: the X
17
+ * server picks a free display number itself and writes it back on the fd, so
18
+ * parallel runs never race for a fixed `:99`. When only the Debian `xvfb-run`
19
+ * script exists, it is the fallback (it wraps the PICO-8 command instead).
20
+ * Either way the virtual display lives exactly as long as the run.
21
+ */
22
+ import { spawn } from 'node:child_process';
23
+ import { accessSync, constants, statSync } from 'node:fs';
24
+ import { delimiter, join } from 'node:path';
25
+ import { killOnAbort } from './cleanup.js';
26
+ /** The three display modes. `auto` is the default. */
27
+ export const DISPLAY_MODES = ['auto', 'xvfb', 'native'];
28
+ /** The default display mode when no flag, env var or config sets one. */
29
+ export const DEFAULT_DISPLAY_MODE = 'auto';
30
+ /** The env var that sets the display mode (below the `--display` flag, above picopilot.json). */
31
+ export const DISPLAY_ENV_VAR = 'PICOPILOT_DISPLAY';
32
+ /** The top-level picopilot.json key that sets the display mode (lowest precedence). */
33
+ export const DISPLAY_CONFIG_KEY = 'display';
34
+ /** Whether `value` names a valid {@link DisplayMode}. */
35
+ export function isDisplayMode(value) {
36
+ return (typeof value === 'string' &&
37
+ DISPLAY_MODES.includes(value));
38
+ }
39
+ /**
40
+ * Resolves the display mode with the precedence `flag > env > config > default`
41
+ * (the same order every picopilot setting uses). An empty/whitespace value is
42
+ * treated as unset; an unknown value is reported (never silently ignored), so a
43
+ * typo like `PICOPILOT_DISPLAY=xfvb` is a visible error rather than `auto`.
44
+ */
45
+ export function resolveDisplayMode(sources) {
46
+ const ordered = [
47
+ ['flag', sources.flag],
48
+ ['env', sources.env],
49
+ ['config', sources.config],
50
+ ];
51
+ for (const [source, raw] of ordered) {
52
+ if (raw === undefined || raw === null)
53
+ continue;
54
+ const value = String(raw).trim();
55
+ if (value.length === 0)
56
+ continue;
57
+ if (isDisplayMode(value))
58
+ return { ok: true, mode: value, source };
59
+ return { ok: false, source, value };
60
+ }
61
+ return { ok: true, mode: DEFAULT_DISPLAY_MODE, source: 'default' };
62
+ }
63
+ /** Whether the environment already offers a display (X11 `DISPLAY` or a Wayland socket). */
64
+ export function hasNativeDisplay(env) {
65
+ const set = (v) => v !== undefined && v.trim() !== '';
66
+ return set(env.DISPLAY) || set(env.WAYLAND_DISPLAY);
67
+ }
68
+ /**
69
+ * Whether a `-run` session in this `mode` + `env` should run on a virtual
70
+ * display: always for `xvfb`, never for `native`, and for `auto` only when
71
+ * there is no native display.
72
+ */
73
+ export function needsVirtualDisplay(mode, env) {
74
+ if (mode === 'xvfb')
75
+ return true;
76
+ if (mode === 'native')
77
+ return false;
78
+ return !hasNativeDisplay(env);
79
+ }
80
+ /**
81
+ * Finds an executable the way a shell would: a name containing `/` is checked
82
+ * as a path, anything else is searched on `env.PATH`. Returns the resolved path,
83
+ * or `undefined`. Pure lookup (no spawn), so it is cheap enough for `doctor` and
84
+ * for the failure path.
85
+ */
86
+ export function findExecutable(name, env) {
87
+ const isExec = (p) => {
88
+ try {
89
+ if (!statSync(p).isFile())
90
+ return false;
91
+ accessSync(p, constants.X_OK);
92
+ return true;
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ };
98
+ if (name.includes('/'))
99
+ return isExec(name) ? name : undefined;
100
+ for (const dir of (env.PATH ?? '').split(delimiter)) {
101
+ if (dir === '')
102
+ continue;
103
+ const candidate = join(dir, name);
104
+ if (isExec(candidate))
105
+ return candidate;
106
+ }
107
+ return undefined;
108
+ }
109
+ /** Detects the best available virtual-display backend on `env.PATH`. */
110
+ export function detectVirtualDisplayBackend(env, find = findExecutable) {
111
+ if (find('Xvfb', env) !== undefined)
112
+ return 'Xvfb';
113
+ if (find('xvfb-run', env) !== undefined)
114
+ return 'xvfb-run';
115
+ return undefined;
116
+ }
117
+ /** The remedy a `display-unavailable` error names. */
118
+ export const DISPLAY_REMEDY = 'install Xvfb (Debian/Ubuntu: apt install xvfb; Fedora: dnf install xorg-x11-server-Xvfb; NixOS: add xvfb-run or xorg.xvfb), or run under a desktop session (DISPLAY or WAYLAND_DISPLAY set)';
119
+ /** Builds a {@link DisplayUnavailable} value. */
120
+ export function displayUnavailable(detail) {
121
+ return {
122
+ ok: false,
123
+ reason: 'display-unavailable',
124
+ remedy: DISPLAY_REMEDY,
125
+ detail,
126
+ };
127
+ }
128
+ /** The fd number Xvfb writes its display number to (`-displayfd 3`). */
129
+ const DISPLAY_FD = 3;
130
+ /** The screen geometry for the virtual display (PICO-8's default window fits easily). */
131
+ const XVFB_SCREEN = '640x540x24';
132
+ /**
133
+ * The real {@link XvfbSpawner}: stdio `[ignore, ignore, pipe, pipe]` so fd 3 is
134
+ * the display-number pipe. NOT detached, so a terminal Ctrl-C reaches it with
135
+ * the rest of picopilot's process group.
136
+ */
137
+ export const spawnXvfb = (file, args, env) => {
138
+ const child = spawn(file, args, {
139
+ env,
140
+ stdio: ['ignore', 'ignore', 'pipe', 'pipe'],
141
+ });
142
+ const fd = child.stdio[DISPLAY_FD];
143
+ fd?.setEncoding('utf8');
144
+ child.stderr?.setEncoding('utf8');
145
+ return {
146
+ pid: child.pid,
147
+ onDisplayFd(cb) {
148
+ fd?.on('data', cb);
149
+ },
150
+ onStderr(cb) {
151
+ child.stderr?.on('data', cb);
152
+ },
153
+ onExit(cb) {
154
+ child.on('exit', cb);
155
+ },
156
+ onError(cb) {
157
+ child.on('error', cb);
158
+ },
159
+ kill(signal) {
160
+ try {
161
+ child.kill(signal);
162
+ }
163
+ catch {
164
+ // already gone
165
+ }
166
+ },
167
+ };
168
+ };
169
+ /** The default time Xvfb gets to come up before the start is declared failed. */
170
+ const DEFAULT_XVFB_START_TIMEOUT_MS = 10_000;
171
+ /** The default time Xvfb gets to exit on SIGTERM before SIGKILL. */
172
+ const DEFAULT_XVFB_STOP_GRACE_MS = 2_000;
173
+ /**
174
+ * Starts a private virtual display for one PICO-8 session. Prefers `Xvfb
175
+ * -displayfd` (no fixed display number, so parallel runs never collide), falls
176
+ * back to wrapping the command in `xvfb-run -a`, and resolves the structured
177
+ * {@link DisplayUnavailable} when neither exists or Xvfb fails to start. Never
178
+ * throws. The returned display MUST be stopped by the caller (the shell adapter
179
+ * does it in a `finally`); a kill-on-abort hook also kills a direct Xvfb so an
180
+ * abrupt picopilot exit or signal never leaves one behind.
181
+ */
182
+ export async function startVirtualDisplay(env, deps = {}) {
183
+ const find = deps.find ?? findExecutable;
184
+ const xvfb = find('Xvfb', env);
185
+ if (xvfb !== undefined) {
186
+ return startDirectXvfb(xvfb, env, deps);
187
+ }
188
+ const xvfbRun = find('xvfb-run', env);
189
+ if (xvfbRun !== undefined) {
190
+ return { ok: true, display: xvfbRunDisplay(xvfbRun) };
191
+ }
192
+ return displayUnavailable('there is no display (DISPLAY and WAYLAND_DISPLAY are unset) and neither Xvfb nor xvfb-run is on PATH to provide a virtual one');
193
+ }
194
+ /**
195
+ * The `xvfb-run` fallback: no server to manage here, the script starts Xvfb,
196
+ * runs the command with DISPLAY set, and kills Xvfb when the command exits. The
197
+ * whole thing runs in PICO-8's process group, so the adapter's group kill
198
+ * (sentinel / backstop) takes Xvfb down with it.
199
+ */
200
+ function xvfbRunDisplay(xvfbRun) {
201
+ return {
202
+ backend: 'xvfb-run',
203
+ env: {},
204
+ wrap(file, args) {
205
+ return {
206
+ file: xvfbRun,
207
+ args: [
208
+ '-a',
209
+ '-s',
210
+ `-screen 0 ${XVFB_SCREEN} -nolisten tcp`,
211
+ file,
212
+ ...args,
213
+ ],
214
+ };
215
+ },
216
+ async stop() { },
217
+ };
218
+ }
219
+ /** Starts `Xvfb -displayfd 3` and waits for it to report the display number it picked. */
220
+ function startDirectXvfb(file, env, deps) {
221
+ const spawner = deps.spawnXvfb ?? spawnXvfb;
222
+ const startTimeoutMs = deps.startTimeoutMs ?? DEFAULT_XVFB_START_TIMEOUT_MS;
223
+ const stopGraceMs = deps.stopGraceMs ?? DEFAULT_XVFB_STOP_GRACE_MS;
224
+ const args = [
225
+ '-displayfd',
226
+ String(DISPLAY_FD),
227
+ '-screen',
228
+ '0',
229
+ XVFB_SCREEN,
230
+ '-nolisten',
231
+ 'tcp',
232
+ ];
233
+ return new Promise((resolve) => {
234
+ let exited = false;
235
+ let settled = false;
236
+ let fdText = '';
237
+ let stderr = '';
238
+ const exitWaiters = [];
239
+ let timer;
240
+ const proc = spawner(file, args, env);
241
+ // Safety net: if picopilot exits or is signalled mid-run, kill the server
242
+ // synchronously so no stray Xvfb is left behind.
243
+ const disposeAbort = killOnAbort(() => proc.kill('SIGKILL'));
244
+ const stop = () => {
245
+ disposeAbort();
246
+ if (exited)
247
+ return Promise.resolve();
248
+ return new Promise((done) => {
249
+ exitWaiters.push(done);
250
+ proc.kill('SIGTERM');
251
+ const hard = setTimeout(() => {
252
+ if (!exited)
253
+ proc.kill('SIGKILL');
254
+ }, stopGraceMs);
255
+ exitWaiters.push(() => clearTimeout(hard));
256
+ });
257
+ };
258
+ const fail = (detail) => {
259
+ if (settled)
260
+ return;
261
+ settled = true;
262
+ clearTimeout(timer);
263
+ void stop().then(() => resolve(displayUnavailable(detail)));
264
+ };
265
+ proc.onExit(() => {
266
+ exited = true;
267
+ for (const w of exitWaiters.splice(0))
268
+ w();
269
+ if (!settled) {
270
+ disposeAbort();
271
+ fail(`Xvfb exited before reporting a display${stderrTail(stderr)}`);
272
+ }
273
+ });
274
+ proc.onError((err) => {
275
+ exited = true;
276
+ for (const w of exitWaiters.splice(0))
277
+ w();
278
+ fail(`Xvfb failed to start (${err.code ?? err.message})`);
279
+ });
280
+ proc.onStderr((chunk) => {
281
+ stderr += chunk;
282
+ });
283
+ proc.onDisplayFd((chunk) => {
284
+ if (settled)
285
+ return;
286
+ fdText += chunk;
287
+ const m = /^\s*(\d+)\s*\n/.exec(fdText);
288
+ if (m === null)
289
+ return;
290
+ settled = true;
291
+ clearTimeout(timer);
292
+ const display = `:${m[1]}`;
293
+ resolve({
294
+ ok: true,
295
+ display: {
296
+ backend: 'Xvfb',
297
+ env: { DISPLAY: display },
298
+ wrap: (f, a) => ({ file: f, args: a }),
299
+ stop,
300
+ },
301
+ });
302
+ });
303
+ timer = setTimeout(() => fail(`Xvfb did not report a display within ${startTimeoutMs}ms${stderrTail(stderr)}`), startTimeoutMs);
304
+ });
305
+ }
306
+ /** The last few lines of Xvfb's stderr, as a `: ...` suffix (or empty). */
307
+ function stderrTail(stderr) {
308
+ const lines = stderr.trim().split('\n').filter(Boolean).slice(-3);
309
+ return lines.length === 0 ? '' : `: ${lines.join(' | ')}`;
310
+ }
311
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../../../src/engine/pico8/display.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"drive.d.ts","sourceRoot":"","sources":["../../../src/engine/pico8/drive.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"drive.d.ts","sourceRoot":"","sources":["../../../src/engine/pico8/drive.ts"],"names":[],"mappings":"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"}
@@ -353,13 +353,39 @@ export function resolveIncludes(lua, readInclude, seen = new Set()) {
353
353
  const path = m[1];
354
354
  if (seen.has(path))
355
355
  return line; // cycle guard: leave it
356
- const content = readInclude(path);
357
- if (content === undefined)
356
+ // `#include other.p8` takes that cart's code, `other.p8:n` only tab n.
357
+ const p8 = /^(.+\.p8)(?::(\d+))?$/i.exec(path);
358
+ const raw = readInclude(p8 !== null ? p8[1] : path);
359
+ if (raw === undefined)
358
360
  return line; // unreadable: leave verbatim
361
+ const content = p8 !== null ? p8Code(raw, p8[2]) : raw;
362
+ if (content === undefined)
363
+ return line;
359
364
  return resolveIncludes(content, readInclude, new Set([...seen, path]));
360
365
  })
361
366
  .join('\n');
362
367
  }
368
+ /**
369
+ * The code an `#include` of a `.p8` cart pulls in: its `__lua__` section, or
370
+ * only tab `tab` (tabs are separated by `-->8` lines). `undefined` when the
371
+ * text does not parse as a cart or the tab does not exist.
372
+ */
373
+ function p8Code(cartText, tab) {
374
+ let lua;
375
+ try {
376
+ lua = Cart.parse(cartText).getSection('lua');
377
+ }
378
+ catch {
379
+ return undefined;
380
+ }
381
+ if (lua === undefined)
382
+ return undefined;
383
+ const body = lua.replace(/\n$/, '');
384
+ if (tab === undefined)
385
+ return body;
386
+ const tabs = body.split(/\r?\n-->8\r?\n/);
387
+ return tabs[Number(tab)];
388
+ }
363
389
  /** The default base filename SHOT names each screenshot (`play0.png`, ...). */
364
390
  export const SHOT_BASENAME = 'play';
365
391
  /**