picopilot 0.0.0 → 0.1.1
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.
- package/LICENSE +661 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +59 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/audio.d.ts +17 -0
- package/dist/commands/audio.d.ts.map +1 -0
- package/dist/commands/audio.js +315 -0
- package/dist/commands/audio.js.map +1 -0
- package/dist/commands/export.d.ts +36 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +257 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/gfx.d.ts +28 -0
- package/dist/commands/gfx.d.ts.map +1 -0
- package/dist/commands/gfx.js +521 -0
- package/dist/commands/gfx.js.map +1 -0
- package/dist/commands/init.d.ts +34 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +151 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +20 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +90 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/minify.d.ts +20 -0
- package/dist/commands/minify.d.ts.map +1 -0
- package/dist/commands/minify.js +129 -0
- package/dist/commands/minify.js.map +1 -0
- package/dist/commands/music.d.ts +13 -0
- package/dist/commands/music.d.ts.map +1 -0
- package/dist/commands/music.js +241 -0
- package/dist/commands/music.js.map +1 -0
- package/dist/commands/playtest.d.ts +29 -0
- package/dist/commands/playtest.d.ts.map +1 -0
- package/dist/commands/playtest.js +631 -0
- package/dist/commands/playtest.js.map +1 -0
- package/dist/commands/run.d.ts +30 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +224 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/serve.d.ts +50 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +213 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/sfx.d.ts +13 -0
- package/dist/commands/sfx.d.ts.map +1 -0
- package/dist/commands/sfx.js +254 -0
- package/dist/commands/sfx.js.map +1 -0
- package/dist/commands/tokens.d.ts +36 -0
- package/dist/commands/tokens.d.ts.map +1 -0
- package/dist/commands/tokens.js +129 -0
- package/dist/commands/tokens.js.map +1 -0
- package/dist/commands/verify.d.ts +57 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +213 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/version.d.ts +12 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +24 -0
- package/dist/commands/version.js.map +1 -0
- package/dist/engine/audio/index.d.ts +14 -0
- package/dist/engine/audio/index.d.ts.map +1 -0
- package/dist/engine/audio/index.js +14 -0
- package/dist/engine/audio/index.js.map +1 -0
- package/dist/engine/audio/music.d.ts +116 -0
- package/dist/engine/audio/music.d.ts.map +1 -0
- package/dist/engine/audio/music.js +138 -0
- package/dist/engine/audio/music.js.map +1 -0
- package/dist/engine/audio/section.d.ts +34 -0
- package/dist/engine/audio/section.d.ts.map +1 -0
- package/dist/engine/audio/section.js +67 -0
- package/dist/engine/audio/section.js.map +1 -0
- package/dist/engine/audio/sfx.d.ts +141 -0
- package/dist/engine/audio/sfx.d.ts.map +1 -0
- package/dist/engine/audio/sfx.js +506 -0
- package/dist/engine/audio/sfx.js.map +1 -0
- package/dist/engine/cart/cart.d.ts +75 -0
- package/dist/engine/cart/cart.d.ts.map +1 -0
- package/dist/engine/cart/cart.js +153 -0
- package/dist/engine/cart/cart.js.map +1 -0
- package/dist/engine/cart/errors.d.ts +29 -0
- package/dist/engine/cart/errors.d.ts.map +1 -0
- package/dist/engine/cart/errors.js +26 -0
- package/dist/engine/cart/errors.js.map +1 -0
- package/dist/engine/cart/gfx.d.ts +79 -0
- package/dist/engine/cart/gfx.d.ts.map +1 -0
- package/dist/engine/cart/gfx.js +171 -0
- package/dist/engine/cart/gfx.js.map +1 -0
- package/dist/engine/cart/index.d.ts +15 -0
- package/dist/engine/cart/index.d.ts.map +1 -0
- package/dist/engine/cart/index.js +15 -0
- package/dist/engine/cart/index.js.map +1 -0
- package/dist/engine/cart/map.d.ts +46 -0
- package/dist/engine/cart/map.d.ts.map +1 -0
- package/dist/engine/cart/map.js +118 -0
- package/dist/engine/cart/map.js.map +1 -0
- package/dist/engine/config/config.d.ts +74 -0
- package/dist/engine/config/config.d.ts.map +1 -0
- package/dist/engine/config/config.js +103 -0
- package/dist/engine/config/config.js.map +1 -0
- package/dist/engine/config/index.d.ts +7 -0
- package/dist/engine/config/index.d.ts.map +1 -0
- package/dist/engine/config/index.js +7 -0
- package/dist/engine/config/index.js.map +1 -0
- package/dist/engine/gfx/grid.d.ts +51 -0
- package/dist/engine/gfx/grid.d.ts.map +1 -0
- package/dist/engine/gfx/grid.js +116 -0
- package/dist/engine/gfx/grid.js.map +1 -0
- package/dist/engine/gfx/index.d.ts +17 -0
- package/dist/engine/gfx/index.d.ts.map +1 -0
- package/dist/engine/gfx/index.js +17 -0
- package/dist/engine/gfx/index.js.map +1 -0
- package/dist/engine/gfx/label.d.ts +34 -0
- package/dist/engine/gfx/label.d.ts.map +1 -0
- package/dist/engine/gfx/label.js +190 -0
- package/dist/engine/gfx/label.js.map +1 -0
- package/dist/engine/gfx/overlap.d.ts +42 -0
- package/dist/engine/gfx/overlap.d.ts.map +1 -0
- package/dist/engine/gfx/overlap.js +57 -0
- package/dist/engine/gfx/overlap.js.map +1 -0
- package/dist/engine/gfx/palette.d.ts +29 -0
- package/dist/engine/gfx/palette.d.ts.map +1 -0
- package/dist/engine/gfx/palette.js +46 -0
- package/dist/engine/gfx/palette.js.map +1 -0
- package/dist/engine/gfx/png.d.ts +31 -0
- package/dist/engine/gfx/png.d.ts.map +1 -0
- package/dist/engine/gfx/png.js +165 -0
- package/dist/engine/gfx/png.js.map +1 -0
- package/dist/engine/gfx/render.d.ts +42 -0
- package/dist/engine/gfx/render.d.ts.map +1 -0
- package/dist/engine/gfx/render.js +72 -0
- package/dist/engine/gfx/render.js.map +1 -0
- package/dist/engine/index.d.ts +22 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +22 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/pico8/adapter.d.ts +267 -0
- package/dist/engine/pico8/adapter.d.ts.map +1 -0
- package/dist/engine/pico8/adapter.js +37 -0
- package/dist/engine/pico8/adapter.js.map +1 -0
- package/dist/engine/pico8/drive.d.ts +308 -0
- package/dist/engine/pico8/drive.d.ts.map +1 -0
- package/dist/engine/pico8/drive.js +581 -0
- package/dist/engine/pico8/drive.js.map +1 -0
- package/dist/engine/pico8/harness.d.ts +146 -0
- package/dist/engine/pico8/harness.d.ts.map +1 -0
- package/dist/engine/pico8/harness.js +251 -0
- package/dist/engine/pico8/harness.js.map +1 -0
- package/dist/engine/pico8/index.d.ts +21 -0
- package/dist/engine/pico8/index.d.ts.map +1 -0
- package/dist/engine/pico8/index.js +21 -0
- package/dist/engine/pico8/index.js.map +1 -0
- package/dist/engine/pico8/sentinel.d.ts +63 -0
- package/dist/engine/pico8/sentinel.d.ts.map +1 -0
- package/dist/engine/pico8/sentinel.js +86 -0
- package/dist/engine/pico8/sentinel.js.map +1 -0
- package/dist/engine/pico8/session-daemon-entry.d.ts +10 -0
- package/dist/engine/pico8/session-daemon-entry.d.ts.map +1 -0
- package/dist/engine/pico8/session-daemon-entry.js +11 -0
- package/dist/engine/pico8/session-daemon-entry.js.map +1 -0
- package/dist/engine/pico8/session-daemon-main.d.ts +44 -0
- package/dist/engine/pico8/session-daemon-main.d.ts.map +1 -0
- package/dist/engine/pico8/session-daemon-main.js +71 -0
- package/dist/engine/pico8/session-daemon-main.js.map +1 -0
- package/dist/engine/pico8/session-daemon.d.ts +68 -0
- package/dist/engine/pico8/session-daemon.d.ts.map +1 -0
- package/dist/engine/pico8/session-daemon.js +264 -0
- package/dist/engine/pico8/session-daemon.js.map +1 -0
- package/dist/engine/pico8/session.d.ts +140 -0
- package/dist/engine/pico8/session.d.ts.map +1 -0
- package/dist/engine/pico8/session.js +250 -0
- package/dist/engine/pico8/session.js.map +1 -0
- package/dist/engine/pico8/shell.d.ts +103 -0
- package/dist/engine/pico8/shell.d.ts.map +1 -0
- package/dist/engine/pico8/shell.js +324 -0
- package/dist/engine/pico8/shell.js.map +1 -0
- package/dist/engine/pico8/supervisor.d.ts +137 -0
- package/dist/engine/pico8/supervisor.d.ts.map +1 -0
- package/dist/engine/pico8/supervisor.js +140 -0
- package/dist/engine/pico8/supervisor.js.map +1 -0
- package/dist/engine/scaffold/index.d.ts +8 -0
- package/dist/engine/scaffold/index.d.ts.map +1 -0
- package/dist/engine/scaffold/index.js +8 -0
- package/dist/engine/scaffold/index.js.map +1 -0
- package/dist/engine/scaffold/scaffold.d.ts +49 -0
- package/dist/engine/scaffold/scaffold.d.ts.map +1 -0
- package/dist/engine/scaffold/scaffold.js +259 -0
- package/dist/engine/scaffold/scaffold.js.map +1 -0
- package/dist/engine/shrinko/adapter.d.ts +167 -0
- package/dist/engine/shrinko/adapter.d.ts.map +1 -0
- package/dist/engine/shrinko/adapter.js +107 -0
- package/dist/engine/shrinko/adapter.js.map +1 -0
- package/dist/engine/shrinko/index.d.ts +13 -0
- package/dist/engine/shrinko/index.d.ts.map +1 -0
- package/dist/engine/shrinko/index.js +13 -0
- package/dist/engine/shrinko/index.js.map +1 -0
- package/dist/engine/shrinko/shell.d.ts +69 -0
- package/dist/engine/shrinko/shell.d.ts.map +1 -0
- package/dist/engine/shrinko/shell.js +156 -0
- package/dist/engine/shrinko/shell.js.map +1 -0
- package/dist/engine/skills/index.d.ts +8 -0
- package/dist/engine/skills/index.d.ts.map +1 -0
- package/dist/engine/skills/index.js +8 -0
- package/dist/engine/skills/index.js.map +1 -0
- package/dist/engine/skills/skills.d.ts +104 -0
- package/dist/engine/skills/skills.d.ts.map +1 -0
- package/dist/engine/skills/skills.js +149 -0
- package/dist/engine/skills/skills.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +19 -0
- package/dist/version.js.map +1 -0
- package/package.json +48 -2
- package/src/bin.ts +4 -0
- package/src/cli.ts +61 -0
- package/src/commands/audio.test.ts +280 -0
- package/src/commands/audio.ts +410 -0
- package/src/commands/export.test.ts +310 -0
- package/src/commands/export.ts +316 -0
- package/src/commands/gfx-io.test.ts +178 -0
- package/src/commands/gfx.test.ts +470 -0
- package/src/commands/gfx.ts +645 -0
- package/src/commands/init.test.ts +482 -0
- package/src/commands/init.ts +193 -0
- package/src/commands/lint.test.ts +137 -0
- package/src/commands/lint.ts +117 -0
- package/src/commands/minify.test.ts +166 -0
- package/src/commands/minify.ts +156 -0
- package/src/commands/music.test.ts +272 -0
- package/src/commands/music.ts +288 -0
- package/src/commands/playtest.test.ts +317 -0
- package/src/commands/playtest.ts +773 -0
- package/src/commands/run.test.ts +264 -0
- package/src/commands/run.ts +285 -0
- package/src/commands/serve.test.ts +227 -0
- package/src/commands/serve.ts +272 -0
- package/src/commands/sfx.test.ts +349 -0
- package/src/commands/sfx.ts +300 -0
- package/src/commands/tokens.test.ts +212 -0
- package/src/commands/tokens.ts +168 -0
- package/src/commands/verify.test.ts +238 -0
- package/src/commands/verify.ts +256 -0
- package/src/commands/version.test.ts +70 -0
- package/src/commands/version.ts +24 -0
- package/src/engine/audio/index.ts +47 -0
- package/src/engine/audio/music.test.ts +188 -0
- package/src/engine/audio/music.ts +218 -0
- package/src/engine/audio/section.test.ts +124 -0
- package/src/engine/audio/section.ts +79 -0
- package/src/engine/audio/sfx.test.ts +410 -0
- package/src/engine/audio/sfx.ts +694 -0
- package/src/engine/cart/cart.test.ts +304 -0
- package/src/engine/cart/cart.ts +211 -0
- package/src/engine/cart/errors.ts +39 -0
- package/src/engine/cart/fixtures/crlf.p8 +6 -0
- package/src/engine/cart/fixtures/full.p8 +174 -0
- package/src/engine/cart/fixtures/header-only.p8 +2 -0
- package/src/engine/cart/fixtures/malformed-no-header.p8 +2 -0
- package/src/engine/cart/fixtures/minimal.p8 +10 -0
- package/src/engine/cart/fixtures/no-trailing-newline.p8 +6 -0
- package/src/engine/cart/gfx.ts +195 -0
- package/src/engine/cart/index.ts +27 -0
- package/src/engine/cart/map.ts +134 -0
- package/src/engine/config/config.ts +115 -0
- package/src/engine/config/index.ts +12 -0
- package/src/engine/gfx/grid.test.ts +128 -0
- package/src/engine/gfx/grid.ts +136 -0
- package/src/engine/gfx/index.ts +34 -0
- package/src/engine/gfx/label.test.ts +105 -0
- package/src/engine/gfx/label.ts +229 -0
- package/src/engine/gfx/overlap.test.ts +71 -0
- package/src/engine/gfx/overlap.ts +66 -0
- package/src/engine/gfx/palette.test.ts +35 -0
- package/src/engine/gfx/palette.ts +54 -0
- package/src/engine/gfx/png.test.ts +111 -0
- package/src/engine/gfx/png.ts +196 -0
- package/src/engine/gfx/render.test.ts +180 -0
- package/src/engine/gfx/render.ts +106 -0
- package/src/engine/index.ts +21 -0
- package/src/engine/pico8/adapter.ts +303 -0
- package/src/engine/pico8/drive.test.ts +415 -0
- package/src/engine/pico8/drive.ts +729 -0
- package/src/engine/pico8/harness.test.ts +181 -0
- package/src/engine/pico8/harness.ts +354 -0
- package/src/engine/pico8/index.ts +20 -0
- package/src/engine/pico8/sentinel.test.ts +80 -0
- package/src/engine/pico8/sentinel.ts +93 -0
- package/src/engine/pico8/session-daemon-entry.ts +12 -0
- package/src/engine/pico8/session-daemon-main.ts +98 -0
- package/src/engine/pico8/session-daemon.test.ts +212 -0
- package/src/engine/pico8/session-daemon.ts +306 -0
- package/src/engine/pico8/session.test.ts +239 -0
- package/src/engine/pico8/session.ts +321 -0
- package/src/engine/pico8/shell.test.ts +583 -0
- package/src/engine/pico8/shell.ts +412 -0
- package/src/engine/pico8/supervisor.test.ts +105 -0
- package/src/engine/pico8/supervisor.ts +197 -0
- package/src/engine/scaffold/index.ts +15 -0
- package/src/engine/scaffold/scaffold.ts +278 -0
- package/src/engine/shrinko/adapter.ts +241 -0
- package/src/engine/shrinko/fixtures/count-no-compressed.txt +2 -0
- package/src/engine/shrinko/fixtures/count-over-budget.txt +3 -0
- package/src/engine/shrinko/fixtures/count-under-budget.txt +3 -0
- package/src/engine/shrinko/index.ts +33 -0
- package/src/engine/shrinko/shell.ts +224 -0
- package/src/engine/shrinko/shrinko.test.ts +182 -0
- package/src/engine/skills/index.ts +14 -0
- package/src/engine/skills/skills.test.ts +376 -0
- package/src/engine/skills/skills.ts +205 -0
- package/src/index.ts +13 -0
- package/src/skills/game-design-reference/SKILL.md +70 -0
- package/src/skills/game-jam/SKILL.md +45 -0
- package/src/skills/picopilot-art/SKILL.md +62 -0
- package/src/skills/picopilot-audio/SKILL.md +194 -0
- package/src/skills/picopilot-code/SKILL.md +97 -0
- package/src/skills/picopilot-code/reference/README.md +42 -0
- package/src/skills/picopilot-code/reference/mode7-racing.md +95 -0
- package/src/skills/picopilot-code/reference/platformer.md +119 -0
- package/src/skills/picopilot-code/reference/puzzle-grid.md +106 -0
- package/src/skills/picopilot-code/reference/rpg-menus-dialog.md +122 -0
- package/src/skills/picopilot-code/reference/top-down-adventure.md +117 -0
- package/src/skills/picopilot-code/reference/twin-stick-arcade.md +128 -0
- package/src/skills/picopilot-debug/SKILL.md +195 -0
- package/src/skills/picopilot-overview/SKILL.md +52 -0
- package/src/version.ts +22 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: picopilot-debug
|
|
3
|
+
description: Close the run-test loop for a PICO-8 cart with picopilot. Run the cart headless and read printh output, use the static verify gate honestly (well-formed is not proven-to-run), and understand the structured pico8-not-found / shrinko-not-found boundaries. Use when a cart misbehaves or you need to confirm it boots.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# picopilot debug
|
|
7
|
+
|
|
8
|
+
Static checks tell you a cart is well-formed; only running it tells you it works.
|
|
9
|
+
picopilot gives you both a static gate and a headless run so you can drive a
|
|
10
|
+
closed loop. (See `picopilot-overview` for the `#include` discipline and
|
|
11
|
+
`picopilot-code` for the token loop.)
|
|
12
|
+
|
|
13
|
+
## Static first: `picopilot verify`
|
|
14
|
+
|
|
15
|
+
`picopilot verify` runs tokens + integrity and returns ONE structured pass/fail
|
|
16
|
+
envelope. It is STATIC and NEVER runs the cart, so:
|
|
17
|
+
|
|
18
|
+
- A green verify means "well-formed", NOT "it runs". The passing result points
|
|
19
|
+
you at `picopilot run` to confirm the cart boots. Do not stop at green.
|
|
20
|
+
- A fail lists WHICH check flunked (over budget, or a malformed cart), so you fix
|
|
21
|
+
the named thing.
|
|
22
|
+
- With shrinko absent, verify is `gate-incapable` (a distinct nonzero outcome,
|
|
23
|
+
NEVER green): it cannot check token bloat, so it refuses to report pass.
|
|
24
|
+
|
|
25
|
+
## Then run it: `picopilot run`
|
|
26
|
+
|
|
27
|
+
`picopilot run <cart>` launches PICO-8 headless (`pico8 -x`), streams stdout,
|
|
28
|
+
ENDS the run the moment the cart prints a done-sentinel, and collects one
|
|
29
|
+
structured result: the screenshot PNG paths, the captured `printh` stdout, and
|
|
30
|
+
the exit reason (`sentinel` / `timeout` / `exit`). Read the screenshots to SEE
|
|
31
|
+
the running game; read printh for text traces. On a backstop `timeout` it CTAs
|
|
32
|
+
you to `verify`/`tokens` to catch a code fault.
|
|
33
|
+
|
|
34
|
+
`run` requires PICO-8 (a licensed, paid binary with no pip/npm path). If PICO-8
|
|
35
|
+
is absent, `run` returns a structured `pico8-not-found` result with a remedy
|
|
36
|
+
(`set PICO8_PATH or install PICO-8`) and a nonzero exit, not a crash or a hang.
|
|
37
|
+
Use the static `verify` loop while PICO-8 is unavailable; it never needs it.
|
|
38
|
+
|
|
39
|
+
### NEVER run `pico8 --help` / `--version` / bare `pico8` (they BLOCK your tool call)
|
|
40
|
+
|
|
41
|
+
PICO-8 is a GUI app with NO headless diagnostic mode. `pico8 --help`,
|
|
42
|
+
`pico8 --version`, and bare `pico8` do NOT print text and exit like a normal
|
|
43
|
+
CLI, they LAUNCH THE INTERACTIVE APP and hang forever (verified: `timeout 5
|
|
44
|
+
pico8 --help` exits 124 with zero output). Running one from an agent/automation
|
|
45
|
+
context STALLS your own tool call indefinitely (it has already bitten this
|
|
46
|
+
project's agents more than once, hanging a whole build). Do NOT invoke `pico8`
|
|
47
|
+
to "see its flags" or check it works. The only safe, non-blocking calls are the
|
|
48
|
+
automation ones, ALWAYS with `</dev/null` + a `timeout` backstop:
|
|
49
|
+
`pico8 -x <cart>`, `pico8 -run <cart>`, `pico8 <cart> -export foo.p8.png`. And
|
|
50
|
+
prefer to let picopilot (`run`, `audio render`, etc.) shell out for you rather
|
|
51
|
+
than calling `pico8` by hand. To learn a CLI flag, read the PICO-8 manual, never
|
|
52
|
+
ask the binary.
|
|
53
|
+
|
|
54
|
+
### The cart must COOPERATE (the recipe `run` orchestrates)
|
|
55
|
+
|
|
56
|
+
There is no "screenshot an arbitrary running cart" hook and a cart CANNOT quit
|
|
57
|
+
the PICO-8 app itself (`extcmd("shutdown")` works only in EXPORTED binaries).
|
|
58
|
+
So the cart takes its own screenshots and signals when it is done, and `run`
|
|
59
|
+
does the watch + kill + collect. Add these debug lines to the cart, run, then
|
|
60
|
+
remove them:
|
|
61
|
+
|
|
62
|
+
```lua
|
|
63
|
+
-- screenshot on a frame timer (the verb is "screen", NOT "screenshot")
|
|
64
|
+
if t==20 then extcmd("set_filename","frame_0") extcmd("screen") end
|
|
65
|
+
if t==40 then extcmd("set_filename","frame_1") extcmd("screen") end
|
|
66
|
+
-- signal done so run kills PICO-8 promptly (it can't self-quit)
|
|
67
|
+
if t==45 then printh("__PICOPILOT_DONE__") end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Load-bearing details (each an easy wrong guess, all tested):
|
|
71
|
+
|
|
72
|
+
- The screenshot verb is **`extcmd("screen")`**. `extcmd("screenshot")` ERRORS
|
|
73
|
+
("unknown extcmd"). `extcmd("set_filename","frame_0")` before it names the next
|
|
74
|
+
shot deterministically (so you can read `frame_0.png`, `frame_1.png`, ... in
|
|
75
|
+
order and PERCEIVE MOTION by comparing frames).
|
|
76
|
+
- The done-sentinel is the default `__PICOPILOT_DONE__` on its OWN line via
|
|
77
|
+
`printh`. `run` kills PICO-8 the instant it matches, so the run lasts exactly
|
|
78
|
+
as long as the cart's logic needs, no blind wait. `--sentinel` changes it.
|
|
79
|
+
- A cart that never prints the sentinel is killed by the backstop
|
|
80
|
+
(`--backstop-ms`, default 15000) and reported as `exitReason: timeout`.
|
|
81
|
+
- `-x` IS genuinely headless (runs with no display); the external kill is needed
|
|
82
|
+
only because a cart cannot self-quit, NOT because of a window.
|
|
83
|
+
- Screenshots go to a run-controlled dir (`--shot-dir`, default an isolated temp
|
|
84
|
+
dir), never `~/Desktop`.
|
|
85
|
+
|
|
86
|
+
To SEE the game actually being PLAYED (drive input + capture gameplay), use
|
|
87
|
+
`picopilot playtest`, next. (`run` boots the cart and captures what it does on
|
|
88
|
+
its own; `playtest` drives it.) There is also a legacy `run --input` that passes
|
|
89
|
+
a one-shot `-p`/`stat(6)` string, but it only works if the cart hand-decodes
|
|
90
|
+
`stat(6)`; for driving an arbitrary game, `playtest` is the tool, not `run
|
|
91
|
+
--input`.
|
|
92
|
+
|
|
93
|
+
## Actually PLAY it: `picopilot playtest`
|
|
94
|
+
|
|
95
|
+
`picopilot playtest` drives ANY normally-written cart (one that reads real
|
|
96
|
+
`btn`/`btnp`) with NO change to it: on a THROWAWAY copy it redefines `btn`/`btnp`
|
|
97
|
+
to read a harness-piped held-buttons byte (reconstructing `btnp` edges) and OWNS the frame
|
|
98
|
+
loop, so it advances an exact number of frames, PAUSES (freezing all state,
|
|
99
|
+
including logic in `_draw`) for a clean screenshot, and captures gameplay (not
|
|
100
|
+
the title). Your `main.p8` is never mutated. `playtest` requires PICO-8 and
|
|
101
|
+
returns the same structured `pico8-not-found` boundary as `run` when it is
|
|
102
|
+
absent. (Mechanism: ADR-0011.)
|
|
103
|
+
|
|
104
|
+
There are three ways to drive a cart; pick by how much continuity you need.
|
|
105
|
+
|
|
106
|
+
### One-shot: `picopilot playtest run <cart>`
|
|
107
|
+
|
|
108
|
+
The whole scripted input is known up front, so the cart replays it to completion
|
|
109
|
+
and exits, returning ONE envelope (screenshot paths + captured printh + the
|
|
110
|
+
steps run). Great for a scripted playtest or benchmark judging.
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
picopilot playtest run main.p8 # generic driver (press-to-start + gentle presses)
|
|
114
|
+
picopilot playtest run game.p8 --input "z" # just press O (a bare button = a press at frame 0)
|
|
115
|
+
picopilot playtest run game.p8 --input "3:o, 18-22:o, 20:right" # a timeline: press/hold at specific frames
|
|
116
|
+
picopilot playtest run game.p8 --seed 1 --input "o" # opt-in srand for deterministic replay
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`--input` accepts EITHER a bare list of buttons (`"z"`, `"o right"`, pressed at
|
|
120
|
+
frame 0, the same "just press these" form as the session `input` verb) OR a
|
|
121
|
+
timeline of `frame:button` (a single press, one clean `btnp` edge) /
|
|
122
|
+
`from-to:button` (a hold). A button is a NAME (`o x left right up down`, aliases
|
|
123
|
+
`l r u d`, PICO-8 keys `z`/`x`) or a bit `0..5`. Omit `--input` for the generic
|
|
124
|
+
one-button/runner/flappy driver. `--seed n` injects `srand(n)` at cart start
|
|
125
|
+
(never silent) so a random cart replays identically. Screenshots go to
|
|
126
|
+
`--shot-dir` (default an isolated temp dir, NEVER `~/Desktop`).
|
|
127
|
+
|
|
128
|
+
### (A) Resumable LIVE session: `start` -> `step`/`input`/`shot` -> `stop`
|
|
129
|
+
|
|
130
|
+
When you want to PLAY across turns (look at the last frame, decide, inject input,
|
|
131
|
+
step, look again), keep the game ALIVE and PAUSED between your turns. `start`
|
|
132
|
+
launches a persistent driven PICO-8 and returns a SESSION ID; every other verb
|
|
133
|
+
addresses that id in a SEPARATE invocation, and the game stays alive + paused in
|
|
134
|
+
between. Stepping is deterministic via a stdout ACK handshake (the host waits for
|
|
135
|
+
the cart's ack before returning), so you always act on a settled, known frame, no
|
|
136
|
+
wall-clock guessing.
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
ID=$(picopilot playtest start main.p8 --format json | jq -r .id) # launch, get the id
|
|
140
|
+
picopilot playtest input $ID "right o" # hold buttons for the next steps (names: left/right/up/down/o/x)
|
|
141
|
+
picopilot playtest step $ID --frames 30 # advance EXACTLY 30 frames, then pause
|
|
142
|
+
picopilot playtest shot $ID # screenshot the current frozen frame -> a PNG path
|
|
143
|
+
picopilot playtest status $ID # is it alive? how many frames in?
|
|
144
|
+
picopilot playtest stop $ID # tear it down (quit PICO-8, reap the dir)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Lifecycle notes (each verified/handled, not a hope):
|
|
148
|
+
|
|
149
|
+
- Each verb WRITES a fixed-size command block and WAITS for the cart's ACK, so a
|
|
150
|
+
`step N` advances exactly N frames and a `shot` between steps captures the
|
|
151
|
+
frozen intended frame. Between verbs the game is frozen (stable framebuffer).
|
|
152
|
+
- ONE session per id; MULTIPLE concurrent sessions are allowed (distinct ids get
|
|
153
|
+
distinct daemons/dirs). Omit `--id` for a fresh random id; pass `--id name` for
|
|
154
|
+
a stable one.
|
|
155
|
+
- ORPHAN reaping: a session you never `stop` self-reaps after an idle window
|
|
156
|
+
(`--idle-timeout-ms`, default 10 min), so a walked-away session cannot leak a
|
|
157
|
+
live PICO-8 forever. `stop` is idempotent (safe on an already-dead session).
|
|
158
|
+
- PICO-8 dying mid-session surfaces as a STRUCTURED error on the next verb
|
|
159
|
+
(`playtest-session-process-dead`), never a hang; a command with no ACK by the
|
|
160
|
+
deadline is `playtest-session-ack-timeout`. `start` with PICO-8 absent is
|
|
161
|
+
`pico8-not-found`, same as `run`.
|
|
162
|
+
- Screenshots + the throwaway driven cart live under a controlled temp session
|
|
163
|
+
dir, never `~/Desktop` or your carts root.
|
|
164
|
+
|
|
165
|
+
### (C) Stateless REPLAY (the free fallback, no daemon)
|
|
166
|
+
|
|
167
|
+
You do NOT always need a live session. Because the one-shot is deterministic
|
|
168
|
+
under `--seed`, you can "resume" by RE-INVOKING `playtest run` with an
|
|
169
|
+
ACCUMULATING script each turn: re-run from frame 0 with the same seed plus the
|
|
170
|
+
new presses appended. It is cheap, reproducible, and daemon-free.
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
picopilot playtest run game.p8 --seed 1 --input "3:4" # turn 1
|
|
174
|
+
picopilot playtest run game.p8 --seed 1 --input "3:4, 40:1" # turn 2 (replays turn 1, then the new press)
|
|
175
|
+
picopilot playtest run game.p8 --seed 1 --input "3:4, 40:1, 55:5" # turn 3 ...
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Prefer (C) for short, replay-safe games (it needs no live process). Use the live
|
|
179
|
+
session (A) for true continuity: long games, or games that reseed from a
|
|
180
|
+
NON-deterministic source (wall-clock/entropy) mid-run and so cannot be replayed
|
|
181
|
+
from frame 0. Both drive the SAME cart-side transform; only the host lifecycle
|
|
182
|
+
differs.
|
|
183
|
+
|
|
184
|
+
## The two structured boundaries
|
|
185
|
+
|
|
186
|
+
Both dependency boundaries are soft and well-signposted, so read the result, do
|
|
187
|
+
not guess:
|
|
188
|
+
|
|
189
|
+
- `shrinko-not-found` (remedy `uv pip install shrinko`): gates the token/lint
|
|
190
|
+
commands and therefore `verify`.
|
|
191
|
+
- `pico8-not-found` (remedy `set PICO8_PATH or install PICO-8`): gates `run`,
|
|
192
|
+
`playtest`, `audio render`, and binary/PNG exports.
|
|
193
|
+
|
|
194
|
+
Each is a structured `{ ok: false, reason, remedy }` envelope with a nonzero
|
|
195
|
+
exit, telling you exactly which capability is gated and how to enable it.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: picopilot-overview
|
|
3
|
+
description: Start here for any PICO-8 cart built with picopilot. The #include discipline (edit main.lua, never the .p8 binary sections), the per-iteration verify loop, and which deeper skill to load for code, art, audio, or debugging. Use when you open a picopilot cart folder or run picopilot init.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# picopilot overview
|
|
7
|
+
|
|
8
|
+
picopilot is the transpile-and-verify layer between what you are good at (text)
|
|
9
|
+
and PICO-8's reality (binary cart sections). It gives you eyes (render sprites to
|
|
10
|
+
a viewable PNG), token-bloat detection, safe cart editing, and one static
|
|
11
|
+
acceptance gate, so you can build a PICO-8 game and self-correct.
|
|
12
|
+
|
|
13
|
+
Load this skill first. Then load the group skill for whatever you are doing:
|
|
14
|
+
`picopilot-code`, `picopilot-art`, `picopilot-audio`, or `picopilot-debug`.
|
|
15
|
+
|
|
16
|
+
## The #include discipline (how every picopilot cart is laid out)
|
|
17
|
+
|
|
18
|
+
- `main.p8` is the cart. Its `__lua__` section is a single line: `#include main.lua`.
|
|
19
|
+
- `main.lua` is the plain Lua you EDIT. You work in ordinary Lua and never
|
|
20
|
+
hand-write the cart's binary hex sections (`__gfx__`, `__map__`, `__sfx__`,
|
|
21
|
+
`__music__`).
|
|
22
|
+
- To touch a binary section, use picopilot's commands (`gfx set`, the audio
|
|
23
|
+
transpiles). They edit those sections safely and round-trippably. Editing hex
|
|
24
|
+
by hand is how art and audio silently break.
|
|
25
|
+
|
|
26
|
+
`picopilot init` scaffolds this layout: `main.p8`, `main.lua`, an `AGENTS.md`
|
|
27
|
+
PICO-8 reference you should read, and a `picopilot.json` config.
|
|
28
|
+
|
|
29
|
+
## The iteration loop
|
|
30
|
+
|
|
31
|
+
Every change follows the same shape:
|
|
32
|
+
|
|
33
|
+
1. Edit `main.lua` (or a cart section via a picopilot command).
|
|
34
|
+
2. `picopilot tokens` to watch the 8,192-token budget (see `picopilot-code`).
|
|
35
|
+
3. `picopilot verify` as the single static acceptance gate.
|
|
36
|
+
|
|
37
|
+
`picopilot verify` is STATIC: it runs tokens + integrity and NEVER runs the cart.
|
|
38
|
+
A green verify means "well-formed", not "it works", so a passing verify points
|
|
39
|
+
you at `picopilot run` to confirm the cart actually boots. Never treat a green
|
|
40
|
+
static gate as done.
|
|
41
|
+
|
|
42
|
+
If shrinko is not installed, token-backed commands (and therefore `verify`) fail
|
|
43
|
+
with a structured `shrinko-not-found` result carrying the exact remedy
|
|
44
|
+
`uv pip install shrinko`. `verify` in that state returns `gate-incapable`, never
|
|
45
|
+
green, so the gate can never pass by skipping its most important check.
|
|
46
|
+
|
|
47
|
+
## Making your agent discover picopilot
|
|
48
|
+
|
|
49
|
+
`picopilot init` PRINTS how to make your agent discover these skills; it does not
|
|
50
|
+
silently write into your shared skill dirs. To actually install them, run
|
|
51
|
+
`picopilot init --install-skills` (or `picopilot skills add`). That is the one
|
|
52
|
+
deliberate, opt-in write to a shared location.
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {readFileSync} from 'node:fs';
|
|
2
|
+
import {dirname, join} from 'node:path';
|
|
3
|
+
import {fileURLToPath} from 'node:url';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The installed picopilot version, read from the package manifest at load time.
|
|
7
|
+
*
|
|
8
|
+
* Single source of truth: the version lives only in `package.json`. The manifest
|
|
9
|
+
* sits one level above the compiled module (`dist/version.js` → `package.json`)
|
|
10
|
+
* and one level above the source module (`src/version.ts` → `package.json`), so
|
|
11
|
+
* the same relative lookup works for both the built binary and `tsx` dev runs.
|
|
12
|
+
*/
|
|
13
|
+
function readVersion(): string {
|
|
14
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const manifestPath = join(here, '..', 'package.json');
|
|
16
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as {
|
|
17
|
+
version?: string;
|
|
18
|
+
};
|
|
19
|
+
return manifest.version ?? '0.0.0';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const VERSION = readVersion();
|