humanish 0.124.0 → 0.125.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 (41) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/CONTEXT.md +1 -1
  3. package/README.md +2 -2
  4. package/dist/analysis/evidence.js +2 -2
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/observer/pinned-files.d.ts +3 -1
  8. package/dist/observer/pinned-files.js +10 -7
  9. package/dist/observer/run-routes.js +2 -1
  10. package/dist/routes/computer-use/live-flush.d.ts +9 -4
  11. package/dist/routes/computer-use/live-flush.js +16 -3
  12. package/dist/run/bundle-shape.js +2 -2
  13. package/dist/run/bundle.d.ts +10 -3
  14. package/dist/run/bundle.js +11 -2
  15. package/dist/run/contained-output.d.ts +22 -0
  16. package/dist/run/contained-output.js +97 -1
  17. package/dist/run/evidence-files.d.ts +12 -1
  18. package/dist/run/evidence-files.js +70 -40
  19. package/dist/run/live-items.d.ts +48 -0
  20. package/dist/run/live-items.js +242 -0
  21. package/dist/run/locate.d.ts +10 -0
  22. package/dist/run/locate.js +10 -0
  23. package/dist/run/run.d.ts +3 -2
  24. package/dist/run/run.js +29 -8
  25. package/dist/run/sandbox-ids.d.ts +0 -5
  26. package/dist/run/sandbox-ids.js +0 -7
  27. package/dist/run/stream-trace.d.ts +18 -9
  28. package/dist/run/stream-trace.js +113 -22
  29. package/dist/run/streams.d.ts +17 -2
  30. package/dist/study/parse/actors.js +23 -6
  31. package/dist/study/parse/execution.js +6 -0
  32. package/dist/study/plan-base.js +4 -1
  33. package/dist/verify/artifacts.js +39 -51
  34. package/dist/verify/screenshot-reads.d.ts +21 -0
  35. package/dist/verify/screenshot-reads.js +46 -0
  36. package/dist/verify/verify.js +7 -6
  37. package/docs/architecture/github-feedback-loop.md +1 -1
  38. package/docs/contracts/README.md +1 -1
  39. package/docs/contracts/run-bundle.md +75 -13
  40. package/docs/contracts/schemas.md +38 -37
  41. package/package.json +3 -1
@@ -1,6 +1,6 @@
1
1
  # Run Bundle Contract
2
2
 
3
- `humanish.run-bundle.v2` is the evidence contract. The TypeScript shape in `src/run/bundle.ts`
3
+ `humanish.run-bundle.v3` is the evidence contract. The TypeScript shape in `src/run/bundle.ts`
4
4
  (with `streams[]` in `src/run/streams.ts` and `sharedWorld` as `SharedWorldEvidence` in
5
5
  `src/run/shared-world-evidence.ts`) and the fail-closed checks in `src/verify/verify.ts` are the
6
6
  source of truth. This page explains the stable public fields and the extension rules; it does not
@@ -46,7 +46,11 @@ impressions, token usage and estimated cost. Each trace is written once.
46
46
  `src/run/stream-shape.ts` holds the rule, and the writer, the shape check and the loader all use
47
47
  it. Any other path, such as `observer/index.html`, fails the shape check.
48
48
 
49
- Readers load a stream through `loadStreamTrace(runPaths, stream)`. A v1 stream returns as it is.
49
+ A reader outside humanish loads a run through the package's `loadRunBundle(cwd, run)`, with `run`
50
+ a run id or `latest`: it returns run.json with every trace file and live file joined and checked
51
+ as below, for v1, v2 and v3 bundles, and throws an Error named `StreamTraceRefusedError` for a
52
+ file that does not match its index. Inside humanish, readers load a stream through
53
+ `loadStreamTrace(runPaths, stream)`. A v1 stream returns as it is.
50
54
  An indexed stream's file is read under the 32 MiB per-file limit (analysis uses its 16 MiB
51
55
  source limit for each trace) and refused unless its size, sha256, item count and screenshot count
52
56
  match the index. A trace file belongs to one participant: every stream whose index names a file
@@ -60,12 +64,69 @@ apart from its walk of the run folder, so no path exemption the walk makes appli
60
64
  run.json's digest, which an analysis record binds, covers each index and so each trace.
61
65
 
62
66
  Mid-run flushes: the writer indexes every finished participant on every write, flushes included,
63
- so a v2 run.json never holds `actor.items`. A participant still working has its items so far in
64
- `streams[].liveActor.items` (`humanish.live-actor.v1`), which no index binds. A v2 run.json may
65
- carry `liveActor` only while its run has not finished: one whose `outcome.state` is `finished`
66
- and still holds `liveActor` is refused. An unfinished v2 run.json with `liveActor` (a flush, or
67
- the last write of an interrupted run) verifies as `local_only` with the share-safety reason
68
- `RUN_NOT_FINISHED`, never `share_ready`. v1 bundles keep their earlier behavior.
67
+ so a run.json from v2 on never holds `actor.items`. A participant still working has its items so
68
+ far in `streams[].liveActor`. A run.json may carry `liveActor` only while its run has not
69
+ finished: one whose `outcome.state` is `finished` and still holds `liveActor` is refused. An
70
+ unfinished run.json with `liveActor` (a flush, or the last write of an interrupted run) verifies
71
+ as `local_only` with the share-safety reason `RUN_NOT_FINISHED`, never `share_ready`. v1 bundles
72
+ keep their earlier behavior.
73
+
74
+ ## Live items
75
+
76
+ From v3, a running participant's items so far are in a live file, so a flush appends only the
77
+ items recorded since the last one instead of rewriting run.json with every item. The run writer
78
+ (`liveItemsWriter` in `src/run/live-items.ts`, called from `src/run/run.ts`) keeps, for each
79
+ stream with a `liveActor`:
80
+
81
+ - the live file `live/<position>.<generation>.ndjson`, `position` the stream's place in
82
+ `streams[]` (from 1). Each line is one trace item as JSON, scrubbed of the run's raw sandbox ids
83
+ as it is appended. A live file is never truncated or rewritten;
84
+ - in run.json, `liveActor` as `humanish.live-actor.v2`: its summary fields (`updatedAt`,
85
+ `persona`, `tokenUsage`, `ids`, `executionProfile`, `providerRequests`, `historyTurnsOmitted`,
86
+ `estimatedCost`) and, in place of `items`, the index of the prefix written so far:
87
+
88
+ ```yaml
89
+ liveActor:
90
+ schema: humanish.live-actor.v2
91
+ updatedAt: "<ISO timestamp>"
92
+ itemsFile:
93
+ path: live/1.1.ndjson
94
+ generation: 1
95
+ items: 4210 # lines in the indexed prefix
96
+ bytes: 1048211 # the indexed prefix's size
97
+ sha256: "<hex digest of the indexed prefix>"
98
+ ```
99
+
100
+ Each write appends the items past the indexed count, syncs them, then writes run.json, so run.json
101
+ never indexes bytes that are not on disk. The sha256 is a running hash, so no write rehashes a
102
+ file. The writer starts the next generation, holding the participant's full list, when appending
103
+ cannot keep the file equal to that list: the list shrank, an item already written is not the same
104
+ object it wrote, an append failed, or a sandbox id the run learned since occurs in the current
105
+ generation. Once run.json naming the new generation is written, the writer removes every earlier
106
+ one, so at most two generations of a participant exist at once. A failed removal or a failed
107
+ run.json write keeps the earlier generations until the next run.json is written, which removes
108
+ them. The live flush deep-freezes each item it is handed, so a producer that edits an item after
109
+ recording it throws there; a producer records a new item instead.
110
+
111
+ A write that starts a new generation copies the participant's whole list, as every flush did
112
+ before v3. When a participant's generation is replaced on two writes in a row, the run records one
113
+ warn event in `events`, type `live-items.rewritten`, with that stream's `streamId`, and keeps it in
114
+ every later write. A run records at most one.
115
+
116
+ `Run.finish` writes the final trace files and run.json, then removes every live file it wrote and
117
+ `live/`, so a finished v3 bundle holds no live files and differs from v2 only in its schema name.
118
+ A run that ends without its final write (interrupted, or killed) keeps its live files and the
119
+ last run.json that indexes them.
120
+
121
+ Readers load live items through the same loader as traces: `loadStreamTraces` reads exactly the
122
+ indexed bytes of the live file (bytes appended after run.json was written are not read), refuses
123
+ them unless their size, sha256 and line count match the index and each line is a JSON object,
124
+ and returns the stream with `liveActor.items` and without `itemsFile`. It refuses a `liveActor`
125
+ schema it does not know, and inline live items (`humanish.live-actor.v1`) in a v3 run.json. A
126
+ reader that cannot read a live file reads run.json again once and loads that bundle instead, since
127
+ the writer may have removed a superseded generation, or every live file at finish, after the
128
+ reader read run.json. v1 and v2 run.json keep `liveActor.items` inline (`humanish.live-actor.v1`)
129
+ and load as before.
69
130
 
70
131
  Readers that show a run (the Observer server, run detail and the TUI, the review command's
71
132
  provenance) load traces through the same loader and rules. A participant whose trace the loader
@@ -81,10 +142,11 @@ observer-data.json is built from the loaded bundle. From 0.124.0 it is
81
142
  `humanish.observer-data.v2`: the same data without each participant's trace items, which stay in
82
143
  the traces (docs/architecture/observer.md).
83
144
 
84
- Compatibility: humanish 0.122.0 and earlier read only v1 and refuse a v2 run.json by its schema
85
- (`run schema` fails in verify, analysis refuses the source). This release reads v1 bundles as
86
- they are, with no migration. An exported copy (`humanish export --format bundle`) is written as
87
- v2 whatever the source version.
145
+ Compatibility: humanish 0.122.0 and earlier read only v1 and refuse a v2 or v3 run.json by its
146
+ schema (`run schema` fails in verify, analysis refuses the source); 0.123.0 and 0.124.0 read v1
147
+ and v2 and refuse v3 the same way. This release reads v1 and v2 bundles as they are, with no
148
+ migration. An exported copy (`humanish export --format bundle`) is written as v3 whatever the
149
+ source version.
88
150
 
89
151
  ## Purpose
90
152
 
@@ -95,7 +157,7 @@ feedback drafts and future public issues.
95
157
  ## Minimum Bundle Shape
96
158
 
97
159
  ```yaml
98
- schema: humanish.run-bundle.v2 # v1 bundles are still read
160
+ schema: humanish.run-bundle.v3 # v2 and v1 bundles are still read
99
161
  runId: "<core run id>"
100
162
  mode: "dry-run|live"
101
163
  simCount: 1
@@ -24,38 +24,38 @@ workflow without leaking private upstream truth into core.
24
24
 
25
25
  ## Contract Index
26
26
 
27
- | Contract | Schema | Public-safe fixture |
28
- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
29
- | Run bundle | `humanish.run-bundle.v2` (each participant's trace in its own file, indexed by `streams[].trace`; v1 bundles, with traces inline, are still read) | `synthetic-run-bundle` |
30
- | Adapter | `humanish.adapter.v1` | `synthetic-cli-adapter` |
31
- | Study file | `humanish.study.v3` | `first-run` |
32
- | Persona | `humanish.persona.v1` | `synthetic-maintainer` |
33
- | Scenario | `humanish.scenario.v1` | `first-run-smoke` |
34
- | Actor trace | `humanish.actor-trace.v1` | `synthetic-actor-trace` |
35
- | Substrate | reserved (never shipped) | none |
36
- | Evidence stream | reserved (streams live inside the run bundle) | see [`run-bundle.md`](run-bundle.md) |
37
- | Review | `humanish.review.v1` | `contract-proof-review` |
38
- | Study analysis | `humanish.study-analysis.v1` (prompt `study-evidence-7` adds `findings[].headline`, `findings[].experience` and `designFindings[]`; older artifacts omit them; `study-evidence-8` adds participant impressions to the instructions, with no field change) | see [study analysis](study-analysis.md) and synthetic analysis fixtures in `tests/` |
39
- | Study analysis correction | `humanish.study-analysis-correction.v1` | see [study analysis](study-analysis.md#human-review-and-sharing) |
40
- | Analysis findings view | `humanish.analysis-findings.v1` (`review --json` field `analysis`; read-only projection of the selected analysis) | see [study analysis](study-analysis.md#reading-findings) |
41
- | Analysis execution receipt | `humanish.analysis-execution.v1` | see [study analysis](study-analysis.md#durable-records) |
42
- | Analysis execution start | `humanish.analysis-execution-start.v1` | see [study analysis](study-analysis.md#durable-records) |
43
- | Verification | `humanish.verify-result.v1` | `five-check-verify` |
44
- | Policy | `humanish.policy.v1` (fixture-only; not engine-validated) | `public-safety-policy` |
45
- | Feedback | `humanish.feedback.v1` | `public-safe-feedback` |
46
- | Terminal cost ledger | `humanish.terminal-cost-ledger.v1` | see Terminal Cost Ledger below |
47
- | Terminal no-spend proof | `humanish.terminal-no-spend-proof.v1` | see Terminal Cost Ledger below |
48
- | Pricing (operator-editable rates) | `humanish.pricing.v1` (`src/run/pricing.ts`; dated per-model + E2B desktop rates) | see Run Cost Summary And Estimated Actor Cost below |
49
- | Run cost summary | `humanish.run-cost-summary.v1` (additive `RunBundle.cost`; estimate, never a charge) | see Run Cost Summary And Estimated Actor Cost below |
50
- | Estimated actor cost | `humanish.actor-estimated-cost.v1` (additive `ActorTrace.estimatedCost`) | see Run Cost Summary And Estimated Actor Cost below |
51
- | Model settings | `humanish.model-settings.v1` (additive `ActorTrace.modelSettings`; the reasoning effort the request carried) | see Actor Trace below |
52
- | Affordance use | `humanish.affordance-use.v1` (additive `ActorTrace.affordanceUse`; per-class counts of the routes an actor took) | see Affordance Use below |
53
- | Adapter score | `humanish.adapter-score.v1` (`RunBundle.adapterScore`; namespaced; route-specific acceptance semantics) | see Product-Adapter Extension Seam below |
54
- | Adapter artifact | `humanish.adapter-artifact.v1` (`RunBundle.adapterArtifacts[]`; namespaced; local relative proof references) | see Product-Adapter Extension Seam below |
55
- | Shared-world evidence | `humanish.shared-world.v1` (additive `RunBundle.sharedWorld` + `RunBundle.attributionClass`; `topologyMode: sequential \| concurrent`) | see Shared-World Evidence below |
56
- | Comms thread | `humanish.comms-thread.v1` (off-app email/SMS the app sent, captured; a `kind: log` run-dir artifact of digests only: from/to/subject/link digests + one OTP count, never raw) | see `comms` under Study File |
57
- | Serve result | `humanish.serve-result.v1` (`src/observer/serve.ts` is authoritative) | none (command result envelope; see Serve Result below) |
58
- | Serve control plane | reserved (`/_humanish/api/*` answers `501` `HUMANISH_SERVE_CONTROL_PLANE_DISABLED` in v1) | none |
27
+ | Contract | Schema | Public-safe fixture |
28
+ | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------- |
29
+ | Run bundle | `humanish.run-bundle.v3` (each participant's trace in its own file, indexed by `streams[].trace`, and a running participant's items so far in a live file indexed by `streams[].liveActor.itemsFile`; v2 bundles, with running items inline, and v1 bundles, with traces inline, are still read) | `synthetic-run-bundle` |
30
+ | Adapter | `humanish.adapter.v1` | `synthetic-cli-adapter` |
31
+ | Study file | `humanish.study.v3` | `first-run` |
32
+ | Persona | `humanish.persona.v1` | `synthetic-maintainer` |
33
+ | Scenario | `humanish.scenario.v1` | `first-run-smoke` |
34
+ | Actor trace | `humanish.actor-trace.v1` | `synthetic-actor-trace` |
35
+ | Substrate | reserved (never shipped) | none |
36
+ | Evidence stream | reserved (streams live inside the run bundle) | see [`run-bundle.md`](run-bundle.md) |
37
+ | Review | `humanish.review.v1` | `contract-proof-review` |
38
+ | Study analysis | `humanish.study-analysis.v1` (prompt `study-evidence-7` adds `findings[].headline`, `findings[].experience` and `designFindings[]`; older artifacts omit them; `study-evidence-8` adds participant impressions to the instructions, with no field change) | see [study analysis](study-analysis.md) and synthetic analysis fixtures in `tests/` |
39
+ | Study analysis correction | `humanish.study-analysis-correction.v1` | see [study analysis](study-analysis.md#human-review-and-sharing) |
40
+ | Analysis findings view | `humanish.analysis-findings.v1` (`review --json` field `analysis`; read-only projection of the selected analysis) | see [study analysis](study-analysis.md#reading-findings) |
41
+ | Analysis execution receipt | `humanish.analysis-execution.v1` | see [study analysis](study-analysis.md#durable-records) |
42
+ | Analysis execution start | `humanish.analysis-execution-start.v1` | see [study analysis](study-analysis.md#durable-records) |
43
+ | Verification | `humanish.verify-result.v1` | `five-check-verify` |
44
+ | Policy | `humanish.policy.v1` (fixture-only; not engine-validated) | `public-safety-policy` |
45
+ | Feedback | `humanish.feedback.v1` | `public-safe-feedback` |
46
+ | Terminal cost ledger | `humanish.terminal-cost-ledger.v1` | see Terminal Cost Ledger below |
47
+ | Terminal no-spend proof | `humanish.terminal-no-spend-proof.v1` | see Terminal Cost Ledger below |
48
+ | Pricing (operator-editable rates) | `humanish.pricing.v1` (`src/run/pricing.ts`; dated per-model + E2B desktop rates) | see Run Cost Summary And Estimated Actor Cost below |
49
+ | Run cost summary | `humanish.run-cost-summary.v1` (additive `RunBundle.cost`; estimate, never a charge) | see Run Cost Summary And Estimated Actor Cost below |
50
+ | Estimated actor cost | `humanish.actor-estimated-cost.v1` (additive `ActorTrace.estimatedCost`) | see Run Cost Summary And Estimated Actor Cost below |
51
+ | Model settings | `humanish.model-settings.v1` (additive `ActorTrace.modelSettings`; the reasoning effort the request carried) | see Actor Trace below |
52
+ | Affordance use | `humanish.affordance-use.v1` (additive `ActorTrace.affordanceUse`; per-class counts of the routes an actor took) | see Affordance Use below |
53
+ | Adapter score | `humanish.adapter-score.v1` (`RunBundle.adapterScore`; namespaced; route-specific acceptance semantics) | see Product-Adapter Extension Seam below |
54
+ | Adapter artifact | `humanish.adapter-artifact.v1` (`RunBundle.adapterArtifacts[]`; namespaced; local relative proof references) | see Product-Adapter Extension Seam below |
55
+ | Shared-world evidence | `humanish.shared-world.v1` (additive `RunBundle.sharedWorld` + `RunBundle.attributionClass`; `topologyMode: sequential \| concurrent`) | see Shared-World Evidence below |
56
+ | Comms thread | `humanish.comms-thread.v1` (off-app email/SMS the app sent, captured; a `kind: log` run-dir artifact of digests only: from/to/subject/link digests + one OTP count, never raw) | see `comms` under Study File |
57
+ | Serve result | `humanish.serve-result.v1` (`src/observer/serve.ts` is authoritative) | none (command result envelope; see Serve Result below) |
58
+ | Serve control plane | reserved (`/_humanish/api/*` answers `501` `HUMANISH_SERVE_CONTROL_PLANE_DISABLED` in v1) | none |
59
59
 
60
60
  ## Study File
61
61
 
@@ -293,7 +293,8 @@ The rest of this section names keys by their v3 spelling:
293
293
  desktop template (image) name or ID the run launches on, for a subject that
294
294
  needs runtimes the stock `desktop` image lacks (e.g. node/bun/a local Postgres
295
295
  baked into an adopter-maintained image). Any non-empty string is a valid
296
- name/id (no allowlist); a blank/whitespace value is rejected. Threaded to the
296
+ name/id (no allowlist); a blank/whitespace value is rejected, and so is one that
297
+ verify would flag as a secret or local path, as written or encoded. Threaded to the
297
298
  SDK's `Sandbox.create(template, opts)` on every desktop-creating route (the
298
299
  single-participant and fan-out cua participants, and the shared-world subject and every actor
299
300
  sandbox); when absent the call
@@ -471,7 +472,7 @@ A study's result has one schema on every route, `humanish.study-result.v1`
471
472
  (`src/run/study-result.ts`), with `route` and `studyId`. 0.109.0 removed `labId`, which 0.108.0
472
473
  wrote with the same value. Route-specific fields stay on their route's result. `humanish run`
473
474
  with no study, `observe`, and a refusal made before a route is picked keep
474
- `humanish.run-result.v1`. The evidence record stays `humanish.run-bundle.v2` in every case.
475
+ `humanish.run-result.v1`. The evidence record stays `humanish.run-bundle.v3` in every case.
475
476
  The computer-use result carries `plan` (the pre-flight participant table: concurrency, waves,
476
477
  per-participant session budget, worst-case sandbox-minutes), `lanes[]` (always present,
477
478
  length 1 at N=1; per-participant status/session/sandbox/subject), and `laneSummary`
@@ -616,7 +617,7 @@ Adapter-owned fields:
616
617
  Abbreviated synthetic fixture (omits `cwd`, `simulations`, `streams` and `events`):
617
618
 
618
619
  ```yaml
619
- schema: humanish.run-bundle.v2
620
+ schema: humanish.run-bundle.v3
620
621
  runId: synthetic-run-bundle-2026-06-02t10-00-00-000z-proof
621
622
  mode: dry-run
622
623
  simCount: 1
@@ -967,7 +968,7 @@ output all map onto one `ActorTrace`. Registered actors live in
967
968
  `pi-agent-core` or `claude-agent-sdk` fails to parse. There is no
968
969
  `humanish.actor.v1`; that name never shipped.
969
970
 
970
- Where the trace is stored depends on the run bundle version. In `humanish.run-bundle.v2`,
971
+ Where the trace is stored depends on the run bundle version. From `humanish.run-bundle.v2`,
971
972
  `streams[].actor` in run.json is the trace without `items`, and the full trace, with the stream's
972
973
  screenshot entries as `artifacts`, is the file `streams[].trace.path` names (`actor.json`,
973
974
  `actors/<stream>.json` or `actor-<surface>.json`). A v1 run.json holds the full trace inline.
@@ -1829,7 +1830,7 @@ including existence for referenced adapter artifacts.
1829
1830
 
1830
1831
  Reserved: `humanish.evidence-stream.v1` has never shipped as a standalone
1831
1832
  schema, and streams are not standalone artifacts. They are the `streams` array
1832
- inside the run bundle (`humanish.run-bundle.v2`), normalizing UI, browser, terminal, TUI,
1833
+ inside the run bundle (`humanish.run-bundle.v3`), normalizing UI, browser, terminal, TUI,
1833
1834
  code-agent UI, artifact, and summary streams, each with transport, terminal
1834
1835
  tail, completion, meaningful-use verdicts, and artifact pointers. See
1835
1836
  [`run-bundle.md`](run-bundle.md#completion-and-meaningful-use-verdicts) for
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "humanish",
3
- "version": "0.124.0",
3
+ "version": "0.125.0",
4
4
  "description": "Synthetic user research for apps, CLIs, and agent-facing product flows.",
5
5
  "keywords": [
6
6
  "cli",
@@ -70,6 +70,7 @@
70
70
  "public-surface:scan": "node scripts/public-surface-scan.mjs",
71
71
  "api:proof": "node scripts/public-api-proof.mjs",
72
72
  "release:check": "pnpm check:pre && pnpm test && pnpm release:check:rest",
73
+ "gate": "node scripts/gate.mjs",
73
74
  "release:check:rest": "pnpm check:post && pnpm api:proof && pnpm public-surface:scan && pnpm skill:check && npm pack --dry-run",
74
75
  "skill:check": "DISABLE_TELEMETRY=1 pnpm exec skills add . --list",
75
76
  "test": "vitest run",
@@ -78,6 +79,7 @@
78
79
  "tui:smoke": "node scripts/tui-smoke.mjs",
79
80
  "tui:test": "pnpm --filter humanish-tui test",
80
81
  "release:dogfood": "node scripts/release-dogfood.mjs",
82
+ "packed:check": "bash scripts/packed-check.sh",
81
83
  "bench": "tsx bench/run.ts",
82
84
  "arch:bench": "tsx scripts/arch-bench.ts",
83
85
  "browser-control:proof": "node scripts/browser-control-proof.mjs",