johns-harness 2026.9.23 → 2026.9.24

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026.9.24
4
+
5
+ - Family 71: native-first Jiti plugin loading (Family 68) is now standard on `latest`. The `extended` dist-tag moves to this same version, so both lines converge at 2026.9.24. Node loads already-built JavaScript plugin code natively first and keeps Babel only for TypeScript plugin entries; `JITI_TRY_NATIVE` is no longer needed and is harmless if set.
6
+ - New packed-artifact gate `scripts/check-packed-artifact.mjs` inspects the real `npm pack` output (and registry tarballs) and fails closed unless all ten plugin-loader copies carry the Family 68 option. Releases 2026.9.22 and 2026.9.23 were cut from the pre-68 base, so their tarballs lacked it while main carried it; this gate makes that impossible to repeat.
7
+ - Roll back with `npm i -g johns-harness@2026.9.23`.
8
+
3
9
  ## 2026.9.23
4
10
 
5
11
  - Family 70: ship the `orchestrator` skill as a bundled, always-eligible skill so every harness install loads the delegation and briefing protocol implicitly (pass the user's words through when they are clear, expand when they are vague, keep briefings brief). Workspace overrides, `enabled: false` and `allowBundled` still apply. `RULES.md` points at the bundled copy.
@@ -8,6 +14,11 @@
8
14
 
9
15
  - Family 69: enforce the latest DeepSeek Flash/Pro, Muse and Gemini Lite alias targets across all 14 shipped copies; document `/model deepseek` and retain Family 68 on the separate `extended` release line.
10
16
 
17
+ ## 2026.9.21-extended.1
18
+
19
+ - Family 68: bake `tryNative: true` into every plugin-loader `createJiti` options object so Node loads already-built JavaScript natively first and keeps Babel only as fallback for TypeScript plugin entries. This is the Path-1 1 GiB cold-start fix; Telegram, WhatsApp and memory stay enabled.
20
+ - Published on the `extended` dist-tag only. `latest` remains `2026.9.20`.
21
+
11
22
  ## 2026.9.20
12
23
 
13
24
  - Family 67: native DeepSeek V4.1 Flash/V4 Pro catalog, environment auth, aliases, model-specific effort mapping and tool/reasoning replay through the supported Chat Completions transport.
package/README.md CHANGED
@@ -85,8 +85,8 @@ node johnness.mjs --help
85
85
  ### Verify
86
86
 
87
87
  ```bash
88
- npm test # 887 tests against the installed dependency tree
89
- bash scripts/verify-patches.sh # 437 checks across every patch family
88
+ npm test # 909 tests against the installed dependency tree
89
+ bash scripts/verify-patches.sh # 443 checks across every patch family
90
90
  ```
91
91
 
92
92
  ## Launch a swarm with one command
@@ -132,7 +132,7 @@ Coding agents today run as isolated processes. Two agents on the same repository
132
132
  - **Memory built for production.** Tiered recall that traces from consolidated reflections down to the verbatim record, surviving compaction and shared across the swarm. Installed and enabled by default.
133
133
  - **Production authority per commit.** Promotion is granted to an exact SHA, never to a branch name, so one worker's authorization never covers another worker's commits.
134
134
  - **An append-only action log.** Agents record every consequential action to `ACTION_LOG.md` and read it before acting.
135
- - **A fixed runtime surface.** The core does not grow on a schedule. New mechanisms enter only to solve a demonstrated production failure, one narrow, tested, reversible patch at a time: 68 patch families, each with a regression test and a rollback path.
135
+ - **A fixed runtime surface.** The core does not grow on a schedule. New mechanisms enter only to solve a demonstrated production failure, one narrow, tested, reversible patch at a time: 71 patch families, each with a regression test and a rollback path.
136
136
  - **Reliability with a definition.** Bounded retries, explicit failure states, exact-once continuation, context-pressure recovery, durable delivery, and supervised gateway recovery.
137
137
  - **Coding first, phone optional.** Direct the work at a high level from a chat channel while agents plan, implement, test, coordinate, and stage releases unattended.
138
138
  - **Local voice.** Optional native Whisper transcription of inbound audio, entirely on your machine. Off by default. [Setup](docs/NATIVE-WHISPER-MUSE.md).
@@ -199,7 +199,7 @@ The log is a [`RULES.md`](RULES.md) workspace convention enforced through the ac
199
199
 
200
200
  ## Patch families
201
201
 
202
- The runtime carries 68 patch families plus the 65.1 safe-update amendment. Each is a production fix applied at the source with a regression test, a durable patch marker, and a rollback path. A verifier runs 437 checks against the package tree and installed dependencies, and 887 tests run against the installed dependency tree.
202
+ The runtime carries 71 patch families plus the 65.1 safe-update amendment. Each is a production fix applied at the source with a regression test, a durable patch marker, and a rollback path. A verifier runs 443 checks against the package tree and installed dependencies, and 909 tests run against the installed dependency tree.
203
203
 
204
204
  Every family follows the same six steps: reproduce the failure, trace the exact runtime path, make the smallest source-level change that restores the invariant, add a regression test and a patch marker, run the verifier, and retain rollback artifacts. The full index: [`docs/PATCHES.md`](docs/PATCHES.md).
205
205
 
@@ -217,7 +217,7 @@ Every family follows the same six steps: reproduce the failure, trace the exact
217
217
  ## Documentation
218
218
 
219
219
  - [`docs/index.md`](docs/index.md): runtime docs, from gateway and channels to plugins, nodes, and CLI reference.
220
- - [`docs/PATCHES.md`](docs/PATCHES.md): the 68 patch families, one record each.
220
+ - [`docs/PATCHES.md`](docs/PATCHES.md): the 71 patch families, one record each.
221
221
  - [`docs/NATIVE-WHISPER-MUSE.md`](docs/NATIVE-WHISPER-MUSE.md): local Whisper transcription setup.
222
222
  - [`RULES.md`](RULES.md): the default operating rules, including Rule Zero on production authorization.
223
223
 
@@ -92823,6 +92823,7 @@ function loadJohnnessPlugins(options = {}) {
92823
92823
  ...resolvePluginSdkScopedAliasMap()
92824
92824
  };
92825
92825
  jitiLoader = createJiti(import.meta.url, {
92826
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
92826
92827
  interopDefault: true,
92827
92828
  extensions: [
92828
92829
  ".ts",
@@ -91543,6 +91543,7 @@ function loadJohnnessPlugins(options = {}) {
91543
91543
  ...resolvePluginSdkScopedAliasMap()
91544
91544
  };
91545
91545
  jitiLoader = createJiti(import.meta.url, {
91546
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
91546
91547
  interopDefault: true,
91547
91548
  extensions: [
91548
91549
  ".ts",
@@ -91533,6 +91533,7 @@ function loadJohnnessPlugins(options = {}) {
91533
91533
  ...resolvePluginSdkScopedAliasMap()
91534
91534
  };
91535
91535
  jitiLoader = createJiti(import.meta.url, {
91536
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
91536
91537
  interopDefault: true,
91537
91538
  extensions: [
91538
91539
  ".ts",
@@ -59018,6 +59018,7 @@ function loadJohnnessPlugins(options = {}) {
59018
59018
  ...resolvePluginSdkScopedAliasMap()
59019
59019
  };
59020
59020
  jitiLoader = createJiti(import.meta.url, {
59021
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
59021
59022
  interopDefault: true,
59022
59023
  extensions: [
59023
59024
  ".ts",
@@ -59018,6 +59018,7 @@ function loadJohnnessPlugins(options = {}) {
59018
59018
  ...resolvePluginSdkScopedAliasMap()
59019
59019
  };
59020
59020
  jitiLoader = createJiti(import.meta.url, {
59021
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
59021
59022
  interopDefault: true,
59022
59023
  extensions: [
59023
59024
  ".ts",
@@ -59420,6 +59420,7 @@ function loadJohnnessPlugins(options = {}) {
59420
59420
  ...resolvePluginSdkScopedAliasMap()
59421
59421
  };
59422
59422
  jitiLoader = createJiti(import.meta.url, {
59423
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
59423
59424
  interopDefault: true,
59424
59425
  extensions: [
59425
59426
  ".ts",
@@ -59059,6 +59059,7 @@ function loadJohnnessPlugins(options = {}) {
59059
59059
  ...resolvePluginSdkScopedAliasMap()
59060
59060
  };
59061
59061
  jitiLoader = createJiti(import.meta.url, {
59062
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
59062
59063
  interopDefault: true,
59063
59064
  extensions: [
59064
59065
  ".ts",
@@ -59018,6 +59018,7 @@ function loadJohnnessPlugins(options = {}) {
59018
59018
  ...resolvePluginSdkScopedAliasMap()
59019
59019
  };
59020
59020
  jitiLoader = createJiti(import.meta.url, {
59021
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
59021
59022
  interopDefault: true,
59022
59023
  extensions: [
59023
59024
  ".ts",
@@ -63115,6 +63115,7 @@ function loadJohnnessPlugins(options = {}) {
63115
63115
  ...resolvePluginSdkScopedAliasMap()
63116
63116
  };
63117
63117
  jitiLoader = createJiti(import.meta.url, {
63118
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
63118
63119
  interopDefault: true,
63119
63120
  extensions: [
63120
63121
  ".ts",
@@ -55779,6 +55779,7 @@ function loadJohnnessPlugins(options = {}) {
55779
55779
  ...resolvePluginSdkScopedAliasMap()
55780
55780
  };
55781
55781
  jitiLoader = createJiti(import.meta.url, {
55782
+ tryNative: true, // JOHNNESS_PATCH_JITI_TRY_NATIVE_68
55782
55783
  interopDefault: true,
55783
55784
  extensions: [
55784
55785
  ".ts",
@@ -0,0 +1,31 @@
1
+ # MemoryRouter doctor reconciliation safety
2
+
3
+ Verified on John's Harness 2026.9.23 for the mr-memory 3.13.3 read-only boot change.
4
+
5
+ ## Finding: no runtime patch needed
6
+
7
+ `doctor --fix` does **not** prune or disable `plugins.entries.mr-memory` in the current harness. Removing mr-memory's old boot-time config rewrite does not remove a required harness safeguard.
8
+
9
+ - Both `dist/doctor-config-flow-*.js` variants run `loadAndMaybeMigrateDoctorConfig` and `stripUnknownConfigKeys` against the host schema. The plugin entries schema is a string-keyed record, and a plugin's `config` is itself an open record. An entry is not an unknown schema property merely because its ID is not a built-in channel.
10
+ - Plugin-aware validation obtains IDs and schemas from the manifest registry. The harness ships `extensions/mr-memory/johnness.plugin.json`, so mr-memory is known even without a separately installed external copy.
11
+ - `validateConfigObjectWithPlugins` treats an unavailable plugin entry as a warning, not an instruction to delete its configuration. It validates an installed plugin's own config using its manifest.
12
+ - `applyPluginAutoEnable` can enable eligible plugins; it does not disable mr-memory. Explicitly disabled entries remain disabled. Doctor should not override an intentional user opt-out.
13
+ - Patch 59's mr-memory installation adapter remains useful for native namespace adoption, but doctor safety does not depend on plugin entrypoint execution or that plugin writing config at startup.
14
+
15
+ ## Regression evidence
16
+
17
+ `node --test tests/mr-memory-doctor.test.mjs`
18
+
19
+ Eight isolated tests execute both real bundled doctor config flows, then the real host config writer and validator, twice each. They cover enabled and intentionally disabled memory, with and without an installed external mr-memory manifest. The external plugin entrypoint deliberately throws if loaded: no test can pass because boot-time self-healing put a removed entry back.
20
+
21
+ Each fixture includes an invalid top-level key, forcing the actual `--fix` unknown-key reconciliation path. Tests assert that this key is removed while mr-memory's complete configuration (fixture key, per-agent keys, density, endpoint), enabled state, allowlist and memory slot survive. Native search stays disabled, native memory flush stays enabled, unrelated plugin entries survive, the persisted config validates, and the second doctor pass is idempotent.
22
+
23
+ Child processes have isolated HOME/state/config/temp paths. Node's permission model grants filesystem writes only inside the disposable fixture directory and denies child processes. No live gateway, service, fleet config, or real credentials are used.
24
+
25
+ Additional release-artifact verification:
26
+
27
+ - The two doctor entrypoint bundles, two config-flow bundles, and two config/validation bundles in the published `johns-harness@2026.9.23` tarball are byte-identical to the tested checkout.
28
+ - A fresh Docker container installed the published harness tarball, then the exact candidate `mr-memory@3.13.3` tarball through `johnness plugins install`. With a fixture key and an invalid top-level property, two complete `johnness doctor --fix --non-interactive` runs preserved the full mr-memory entry and memory slot, kept native search disabled and memory flush enabled, and removed only the invalid property. No `.openclaw/openclaw.json` was created. The run ended `HARNESS_DOCTOR_CLI_MEMORY_PRESERVED`.
29
+ - Full checkout test suite: **900 pass, 0 fail** (including the eight new tests). Patch verifier: **440 pass, 0 fail**.
30
+
31
+ Because no real gap was found, there is no new patch family and no 2026.9.24 runtime release for this investigation. `latest` and `extended` are unchanged.
package/docs/PATCHES.md CHANGED
@@ -2567,7 +2567,21 @@ The 65.1 updater budgets fresh installs from the old dependency size. A very ful
2567
2567
 
2568
2568
  ## Family 67: native DeepSeek and current provider catalog
2569
2569
 
2570
- Verified September 13, 2026 against official provider catalogs and harmless live API probes. Adds DeepSeek V4.1 Flash/V4 Pro via the existing supported Chat Completions adapter, Gemini Flash-Lite, current prices and Claude xhigh mappings. Preserves all legacy IDs, configured selection, deliberate context budgets and provider-default omission. [Full source/evidence/limits](PROVIDER-CATALOG.md). Canonical adapters live in the version-checked pi-ai overlay; `patch-provider-catalog.py --check` validates exact registry/auth/alias/adapter snapshots without network or secrets. Historical reconstruction retains exact byte comparisons through the Family 67 helper.
2570
+ Verified September 13, 2026 against official provider catalogs and harmless live API probes. Adds DeepSeek V4.1 Flash/V4 Pro via the existing supported Chat Completions adapter, Gemini Flash-Lite, current prices and Claude xhigh mappings. Preserves all legacy IDs, configured selection, deliberate context budgets and provider-default omission. [Full source/evidence/limits](PROVIDER-CATALOG.md). Canonical adapters live in the version-checked pi-ai overlay; `patch-provider-catalog.py --check` validates exact registry/auth/alias/adapter snapshots without network or secrets. Historical reconstruction retains exact byte comparisons through the Family 67 helper. Family 68 later adds one native-Jiti options line in the ten loader copies; Family 67 hash checks compare the Family-67 surface (that line stripped) so the reviewed catalog snapshot stays fail-closed.
2571
+
2572
+ ## 68 Native-first Jiti plugin load
2573
+
2574
+ **Marker:** `JOHNNESS_PATCH_JITI_TRY_NATIVE_68`
2575
+ **Release:** `johns-harness@2026.9.21-extended.1` (`extended` dist-tag; `latest` stays `2026.9.20`)
2576
+ **Patcher:** `scripts/patch-jiti-try-native.py [root] [--check] [--present-only]`. Plans all ten plugin-loader copies before writing, rejects missing/ambiguous `createJiti` anchors, and is byte-idempotent.
2577
+
2578
+ Jiti 2.x defaults `tryNative` on only for Bun. On Node the plugin loader Babel-transforms already-built JavaScript, including Telegram's pull of `dist/plugin-sdk/dispatch-Cerq29sy.js` (~3.84M chars). Family 68 bakes `tryNative: true` into every live `createJiti(import.meta.url, { interopDefault, extensions, alias })` options object used by the plugin loader. Existing options stay. Babel fallback remains for TypeScript plugin entries. Telegram, WhatsApp, and memory are not disabled.
2579
+
2580
+ Isolated 1 GiB lab (env-only predecessor): three cold VM/cache starts plus one warm restart, peak RSS 312–327 MiB, health plus mock tool turn passed. This family makes that behavior the shipped default instead of an operator env flag.
2581
+
2582
+ **Tests:** `tests/jiti-try-native.test.mjs` covers presence of the option in all ten copies, `--check` cleanliness, idempotent replay, and fail-closed preflight. Historical family reconstructions apply Family 68 after Family 67 so byte-exact comparisons keep working. Verifier checks the marker, `tryNative: true`, and exact read-only replay.
2583
+
2584
+ Roll back the package with `npm i -g johns-harness@2026.9.20`. This extended release does not move `latest`.
2571
2585
 
2572
2586
  ## Family 69: DeepSeek alias contract
2573
2587
 
@@ -2577,7 +2591,7 @@ Release: `johns-harness@2026.9.22` (`latest`). Extends the release gate, not the
2577
2591
  All 14 alias copies must match these exact targets, agree with each other, and resolve every shipped alias in the catalog.
2578
2592
  Verifier checks 69.1 and 69.2 enforce the contract and exactly one DeepSeek Flash alias per copy.
2579
2593
  Future catalog releases must move the matching contract targets; user-configured aliases still win.
2580
- Family 68 remains on the `extended` release line and is not included in this `latest` artifact.
2594
+ Family 68 remains on the `extended` release line and is not included in this `latest` artifact. (Superseded by Family 71: from `2026.9.24` Family 68 ships on `latest` as well.)
2581
2595
 
2582
2596
  ## Family 70: bundled orchestrator skill
2583
2597
 
@@ -2586,3 +2600,21 @@ The skill is the delegation protocol: orchestrate rather than work; pass the use
2586
2600
  It is marked `always: true` so no bin, env or config gate hides it. The ordinary precedence still applies: a workspace `skills/orchestrator` or managed copy overrides it, `skills.entries.orchestrator.enabled: false` turns it off, and an `allowBundled` allowlist that omits it is respected.
2587
2601
  `RULES.md` section 5 and its skill table point at the bundled skill. No runtime code changes. Verifier checks 70.1 through 70.5 cover presence, the always flag, the briefing rule, the generic wording and the RULES pointer; `tests/orchestrator-skill.test.mjs` proves every skills chunk loads it from an empty workspace, into the prompt snapshot, and that the override and disable paths still work.
2588
2602
  Family 68 remains on the `extended` release line and is not included in this `latest` artifact.
2603
+
2604
+ ## Family 71: native-first Jiti standard on latest
2605
+
2606
+ **Marker:** `JOHNNESS_PATCH_NATIVE_JITI_STANDARD_71` (gate and tests; the runtime change is Family 68's own marker in the ten loader copies)
2607
+ **Release:** `johns-harness@2026.9.24`. Published as `latest` and the `extended` dist-tag is moved to the same version, so the two lines converge here.
2608
+ **Gate:** `scripts/check-packed-artifact.mjs [root] | --tarball <file.tgz> [--expect-version <v>]`
2609
+
2610
+ What had been excluding Family 68 from `latest`: not a build step or a strip pass, a branch point. Releases `2026.9.22` and `2026.9.23` were cut from `6427b26` (the pre-68 base of `2026.9.20`), packed and published from that tree, and only then no-ff merged into main. Main carried Family 68 the whole time; the tarballs never did. Every check ran against a working tree, so nothing could notice that the artifact differed from the tree.
2611
+
2612
+ Family 71 closes that gap from the artifact side. The gate runs `npm pack --ignore-scripts`, extracts the tarball, and fails closed unless every one of the ten plugin-loader copies inside it carries exactly one `JOHNNESS_PATCH_JITI_TRY_NATIVE_68` marker and exactly one `tryNative: true`, the tarball version equals the tree version, and no loader copy is missing. The same module inspects a tarball fetched from the registry, which is how the published artifact is proven after `npm publish`. On an installed target the verifier applies the same ten-copy rule to the installed tree.
2613
+
2614
+ Effect: Node loads already-built JavaScript plugin code natively first on every install, with Babel kept only as the fallback for TypeScript plugin entries. Measured on the fleet before this release: gateway RSS 464 MB and 446 MB on `latest` (2026.9.23 and 2026.9.19) against 355 MB on `extended`; isolated 1 GiB lab peak RSS 312 to 327 MiB. The `JITI_TRY_NATIVE=1` environment variable is no longer needed and is harmless if still set. Telegram, WhatsApp and memory stay enabled.
2615
+
2616
+ Family 67 hash checks continue to compare the Family-67 surface with the Family 68 line stripped, unchanged from `2026.9.21-extended.1`; no further adjustment was needed because the loader bytes on main were already the released bytes.
2617
+
2618
+ **Tests:** `tests/native-jiti-standard.test.mjs` proves the gate passes a complete tarball, fails a tarball packed without Family 68 (the 2026.9.22 and 2026.9.23 shape), fails when one copy lacks the option or is absent, fails on a version mismatch, exits non-zero from the CLI, and that the real `npm pack` output of this tree carries the marker in all ten copies. Verifier checks 71.1 through 71.3 cover the shipped gate, the packed or installed artifact, and the absence of a separate extended pin in `package.json`.
2619
+
2620
+ Roll back with `npm i -g johns-harness@2026.9.23` (no native-first Jiti) or `npm i -g johns-harness@2026.9.21-extended.1` (Family 68 without Families 69 and 70).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "johns-harness",
3
- "version": "2026.9.23",
3
+ "version": "2026.9.24",
4
4
  "description": "John's Harness: a production agent harness that runs autonomous coding agents as one cooperative swarm.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -42,6 +42,7 @@
42
42
  "scripts/postinstall.mjs",
43
43
  "scripts/prepare-slim-bundles.mjs",
44
44
  "scripts/strip-sourcemaps.mjs",
45
+ "scripts/check-packed-artifact.mjs",
45
46
  "scripts/slim-bundles.json",
46
47
  "!extensions/**/node_modules/.ignored*/**",
47
48
  "!extensions/**/node_modules/.bin/**",
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ // JOHNNESS_PATCH_NATIVE_JITI_STANDARD_71
3
+ // Family 71: native-first Jiti is standard on every artifact.
4
+ //
5
+ // Family 68 bakes `tryNative: true` into the ten plugin-loader copies. Releases 2026.9.22 and
6
+ // 2026.9.23 were branched from the pre-68 base and packed from that tree, so the `latest`
7
+ // tarballs shipped without it while the working tree on main carried it. Working-tree checks
8
+ // cannot catch that. This gate inspects the real packed artifact: it runs `npm pack` (or takes
9
+ // an existing tarball), extracts it, and fails closed unless every loader copy in the tarball
10
+ // carries exactly one Family 68 marker and exactly one `tryNative: true`, the tarball version
11
+ // matches the tree version, and no copy is missing.
12
+ //
13
+ // Usage:
14
+ // node scripts/check-packed-artifact.mjs [package root] pack the tree, then inspect
15
+ // node scripts/check-packed-artifact.mjs --tarball <file.tgz> inspect a tarball (for example
16
+ // one fetched from the registry)
17
+ // --expect-version <v> require this package.json version inside the tarball
18
+
19
+ import fs from "node:fs";
20
+ import os from "node:os";
21
+ import path from "node:path";
22
+ import { execFileSync } from "node:child_process";
23
+ import { fileURLToPath } from "node:url";
24
+
25
+ export const MARKER_68 = "JOHNNESS_PATCH_JITI_TRY_NATIVE_68";
26
+ export const OPTION_68 = "tryNative: true";
27
+ // Mirrors ALL_FILES in scripts/patch-jiti-try-native.py.
28
+ export const LOADERS10 = [
29
+ "dist/compact-B247y5Qt.js",
30
+ "dist/pi-embedded-C6ITuRXf.js",
31
+ "dist/pi-embedded-DoQsYfIY.js",
32
+ "dist/plugin-sdk/dispatch-BP0viZiL.js",
33
+ "dist/plugin-sdk/dispatch-CQsjmw7g.js",
34
+ "dist/plugin-sdk/dispatch-Cerq29sy.js",
35
+ "dist/plugin-sdk/dispatch-Cndjtt0g.js",
36
+ "dist/plugin-sdk/dispatch-UogiJYul.js",
37
+ "dist/plugin-sdk/reply-DbZnH8-h.js",
38
+ "dist/reply-C5LKjXcC.js",
39
+ ];
40
+
41
+ const count = (text, needle) => text.split(needle).length - 1;
42
+
43
+ /** Inspect an extracted package directory (the `package/` folder of a tarball). Throws on any gap. */
44
+ export function inspectExtracted71(pkgDir, { expectVersion } = {}) {
45
+ const manifestPath = path.join(pkgDir, "package.json");
46
+ if (!fs.existsSync(manifestPath)) throw new Error(`Family 71: tarball has no package.json at ${manifestPath}`);
47
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
48
+ if (manifest.name !== "johns-harness") throw new Error(`Family 71: tarball is ${manifest.name}, expected johns-harness`);
49
+ if (expectVersion && manifest.version !== expectVersion) {
50
+ throw new Error(`Family 71: tarball version ${manifest.version} does not match expected ${expectVersion}`);
51
+ }
52
+ const problems = [];
53
+ let markers = 0;
54
+ for (const rel of LOADERS10) {
55
+ const file = path.join(pkgDir, rel);
56
+ if (!fs.existsSync(file)) { problems.push(`${rel}: missing from artifact`); continue; }
57
+ const text = fs.readFileSync(file, "utf8");
58
+ const m = count(text, MARKER_68);
59
+ const o = count(text, OPTION_68);
60
+ if (m !== 1) problems.push(`${rel}: ${m} Family 68 markers (expected 1)`);
61
+ if (o !== 1) problems.push(`${rel}: ${o} tryNative: true (expected 1)`);
62
+ if (m === 1 && o === 1) markers += 1;
63
+ }
64
+ if (problems.length) throw new Error(`Family 71: packed artifact lacks native-first Jiti:\n ${problems.join("\n ")}`);
65
+ return { version: manifest.version, loaders: LOADERS10.length, markers };
66
+ }
67
+
68
+ /** Extract a tarball into a temp dir and inspect it. */
69
+ export function inspectTarball71(tarball, options = {}) {
70
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "johnness-f71-"));
71
+ try {
72
+ execFileSync("tar", ["-xzf", path.resolve(tarball), "-C", tmp], { stdio: ["ignore", "pipe", "pipe"] });
73
+ return { tarball: path.resolve(tarball), ...inspectExtracted71(path.join(tmp, "package"), options) };
74
+ } finally {
75
+ fs.rmSync(tmp, { recursive: true, force: true });
76
+ }
77
+ }
78
+
79
+ /** Pack the tree with npm (scripts ignored; same method as the Family 66 Linux gate) and inspect the result. */
80
+ export function packAndInspect71(root) {
81
+ const tree = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
82
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "johnness-f71-pack-"));
83
+ try {
84
+ const pack = JSON.parse(execFileSync("npm", ["pack", "--json", "--ignore-scripts", "--pack-destination", tmp], {
85
+ cwd: root, encoding: "utf8", maxBuffer: 20e6, stdio: ["ignore", "pipe", "pipe"],
86
+ }))[0];
87
+ const result = inspectTarball71(path.join(tmp, pack.filename), { expectVersion: tree.version });
88
+ return { ...result, tarball: pack.filename, bytes: pack.size, entries: pack.entryCount };
89
+ } finally {
90
+ fs.rmSync(tmp, { recursive: true, force: true });
91
+ }
92
+ }
93
+
94
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
95
+ const args = process.argv.slice(2);
96
+ const flag = (name) => { const i = args.indexOf(name); return i >= 0 ? args[i + 1] : undefined; };
97
+ const tarball = flag("--tarball");
98
+ const expectVersion = flag("--expect-version");
99
+ try {
100
+ let result;
101
+ if (tarball) {
102
+ result = inspectTarball71(tarball, { expectVersion });
103
+ } else {
104
+ const positional = args.filter((a, i) => !a.startsWith("--") && args[i - 1] !== "--tarball" && args[i - 1] !== "--expect-version");
105
+ const root = path.resolve(positional[0] || path.join(path.dirname(fileURLToPath(import.meta.url)), ".."));
106
+ result = packAndInspect71(root);
107
+ }
108
+ console.log(`Family 71: ${result.markers}/${result.loaders} loader copies carry native-first Jiti in ${path.basename(result.tarball)} (version ${result.version})`);
109
+ } catch (error) {
110
+ console.error(error.message);
111
+ process.exit(1);
112
+ }
113
+ }