0xray 4.0.15 → 4.0.16

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.15",
3
+ "version": "4.0.16",
4
4
  "description": "0xRay suit for Grok, Hermes, OpenClaw, OpenCode: mill+inspect, Codex, 7 MCP servers. Costume 45/42 is opt-in foundry, not the default wear.",
5
5
  "author": {
6
6
  "name": "0xRay AI",
package/.opencode/init.sh CHANGED
@@ -35,8 +35,15 @@ XRAY_VERSION=$(node -e "console.log(require('$FRAMEWORK_ROOT/package.json').vers
35
35
  # Dedup guard — prevent duplicate runs during startup
36
36
  # Uses a TTL lockfile (10s window) since OpenCode may trigger config hook
37
37
  # from multiple plugin copies in quick succession
38
- # Key by PROJECT_ROOT (md5) so all invocations in the same project share one lock
39
- LOCK_KEY=$(echo -n "$PROJECT_ROOT" | md5 | cut -c1-16)
38
+ # Key by PROJECT_ROOT so all invocations in the same project share one lock.
39
+ # md5 is macOS; Linux has md5sum. Do not fail the boot on a leftover Mac tool.
40
+ if command -v md5 >/dev/null 2>&1; then
41
+ LOCK_KEY=$(echo -n "$PROJECT_ROOT" | md5 | cut -c1-16)
42
+ elif command -v md5sum >/dev/null 2>&1; then
43
+ LOCK_KEY=$(echo -n "$PROJECT_ROOT" | md5sum | awk '{print $1}' | cut -c1-16)
44
+ else
45
+ LOCK_KEY=$(echo -n "$PROJECT_ROOT" | cksum | awk '{print $1}')
46
+ fi
40
47
  LOCK_FILE="/tmp/xray-init-${LOCK_KEY}.lock"
41
48
  LOCK_TTL=10
42
49
  if [ -f "$LOCK_FILE" ]; then
@@ -123,8 +130,11 @@ else
123
130
  PLUGIN_STATUS="❌"
124
131
  fi
125
132
 
126
- # Framework config check
127
- if [ ! -f "$PROJECT_ROOT/.opencode/enforcer-config.json" ]; then
133
+ # Framework config check — consumer wear is .xray/codex.json, not leftover enforcer-config.json
134
+ if [ ! -f "$PROJECT_ROOT/.opencode/enforcer-config.json" ] \
135
+ && [ ! -f "$PROJECT_ROOT/.xray/codex.json" ] \
136
+ && [ ! -f "$PROJECT_ROOT/node_modules/0xray/.xray/codex.json" ] \
137
+ && [ ! -f "$PROJECT_ROOT/.mcp.json" ]; then
128
138
  echo -e "${PURPLE}// ❌ Framework configuration not found //${NC}"
129
139
  exit 1
130
140
  fi
@@ -68,7 +68,8 @@ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `g
68
68
  - **Wear first:** Read `.xray/state/STATION.md`. Same cloud. Same critic (resume only). Dummy Reads Station.
69
69
  - **Dummy tests `SKILLS.md`:** a suited dummy proves the worn catalog. Same-sess bodies keep context and hold a Station card.
70
70
  - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR.
71
- - **Publish:** spawn the OTP browser, watch success, poll `npm view` until the new version is live. Do not move on early. Railway same law.
71
+ - **Publish:** stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY. Paste the clickable `auth/cli` URL. No Enter, no VM browser, no subagent, no 6-digit code in chat. Poll `npm view` until live. Then prove **fresh** and **upgrade** registry installs. `npx 0xray validate` is the wear check (not leftover init.sh). `npm view` is not an install.
72
+ - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
72
73
  - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes.
73
74
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
74
75
  - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.15",
3
+ "version": "4.0.16",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",
package/dist/CHANGELOG.md CHANGED
@@ -17,14 +17,37 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
17
17
  - **Dispatch encode** — lead cards ticket + PR URLs + “Wear, then review.” Critic OP-PROC lives on `SEATS.md` Reviewer. When a law is spoken twice, write it to disk this wake. No new skill.
18
18
  - **Ship decision matrix** — lead-owned. A PR+CI · B pack (`assert-packed-dist-cli` + consumer smoke) · C `npm run release:docs-check` · D `npx @0xray/foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Host Auto Review may still card npm/Railway; that is not the OS decision.
19
19
  - **Metamorphosis** — an LLM becomes OP-PROC through in-context worn seats (same critic, same dummy, four-line dispatch). Spawning more bots is the old skin.
20
+ - **Publish OTP latch** — stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY (no `--auth-type=web`, no `--otp=` from chat, no `tee`). Paste the clickable `auth/cli` URL. Do not ask for a 6-digit authenticator code in chat. Do not press Enter. Do not hand publish to a browser subagent. Poll `npm view` until the version is live. Then prove **fresh** and **upgrade** registry installs. `npm view` is not an install.
21
+ - **`npx 0xray validate` cleansed** — no longer shells leftover `.opencode/init.sh` (macOS `md5` + `enforcer-config.json`). Wear check: `REQUIRED_PACK_PATHS`, Cursor hooks, mill+inspect, repertoire. `init.sh` still boots OpenCode but accepts Linux `md5sum` and consumer `.xray/codex.json`.
22
+ - **Swamp reflection (new arch)** — `docs/reflections/swamp-new-arch-reflection-2026-09-20.md`. Card, organ, hook. Lying metal. Live tarball lag.
20
23
 
21
24
  ### 🔄 Changes
25
+ - **Durable Hold npm** — heat + `cursorBootNeedsRefresh` + `npx 0xray validate` drop/fail `Hold npm` on Station. Identity stays. Mill-gate holds the ship latch. Not a new skill.
22
26
  - **Hangar catalog** — mill hangar docs use Clearing `GET /v1/catalog` as the directory (listed hangars: Groover DID + pin, plus solar + live shop), not a hardcoded extract/witness/pin route table. Groover MCP `list_hangars` reads that catalog. 0xray stays 4.0.15.
23
27
  - **foundry-plant/0** — fasten is a protocol any mill implements, not a 0xray-owned catalog of plant kinds. Builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (alias `"blip"`) fastens whatever that mill package declares. Organs (looker, vibe, mixer) live in the mill; adding one is a mill publish, not an xray catalog PR. Nested mill `@0xray/foundry@0.1.12`. CLI shims `foundry blip|sound` still exist on foundry 0.1.11+. 0xray stays 4.0.15.
24
28
  - **Blip/sound mills moved to `@0xray/blip`** — 4.44s drawers (render, kapow, vibe, wow-pass listen/cel, sound bed/mixer, looker) live in the blip product mill. `@0xray/foundry@0.1.11` shims `foundry blip|sound` including `blip look`. Railway plant consumes the product mill, not a hand-vendored copy. 0xray stays 4.0.15.
25
29
 
26
30
  ---
27
31
 
32
+ ## [4.0.16] - 2026-09-20
33
+
34
+ ### 🔄 Changes
35
+
36
+ ### 🐛 Bug Fixes
37
+ - fix: type validate pack paths — no untyped mjs import in src/cli (ff936b276)
38
+ - fix: cleanse npx 0xray validate — wear check, not leftover init.sh (741cca410)
39
+
40
+ ### 📚 Documentation
41
+ - docs: new-arch reflection after wading part of the swamp (12d1fff69)
42
+ - docs: persist peer-boot seat bc-49e17122 after four-line wear (5c8be98bb)
43
+ - docs: encode registry install as live-verify after npm view (bd32bd1c4)
44
+ - docs: encode npm CLI OTP latch — lead publishes, no subagent (d600d12a2)
45
+
46
+ ### 🔎 Other Changes
47
+ - Merge branch 'cursor/npm-cli-otp-fbe0' — OTP latch, two-path live-verify, cleanse leftover validate (568797952)
48
+
49
+ ---
50
+
28
51
  ## [4.0.15] - 2026-09-17
29
52
 
30
53
  ### ✨ Features
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Consumer wear check — not leftover OpenCode init.sh.
3
+ *
4
+ * `npx 0xray validate` used to shell `.opencode/init.sh` (macOS `md5`,
5
+ * `.opencode/enforcer-config.json`). That is factory boot theater, not wear.
6
+ */
7
+ /** Same paths as `REQUIRED_PACK_PATHS` in assert-packed-dist-cli.mjs — typed here so src/cli does not import untyped .mjs. */
8
+ export declare const VALIDATE_PACK_PATHS: readonly string[];
9
+ export declare const CONSUMER_WEAR_PATHS: readonly ["AGENTS.md", ".mcp.json", ".xray/codex.json", ".xray/features.json", ".cursor/hooks.json"];
10
+ export declare const MILL_PLANT_SKILLS: readonly ["mill", "inspect"];
11
+ export type ValidateCheck = {
12
+ id: string;
13
+ ok: boolean;
14
+ detail: string;
15
+ };
16
+ export type ValidateReport = {
17
+ ok: boolean;
18
+ consumer: boolean;
19
+ packageRoot: string;
20
+ checks: ValidateCheck[];
21
+ };
22
+ export declare function resolveInstalledPackageRoot(cwd: string): string | null;
23
+ export declare function isConsumerInstall(cwd: string, packageRoot: string): boolean;
24
+ export declare function collectValidateReport(cwd: string): ValidateReport;
25
+ export declare function validateCommand(cwd?: string): Promise<ValidateReport>;
26
+ export default validateCommand;
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Consumer wear check — not leftover OpenCode init.sh.
3
+ *
4
+ * `npx 0xray validate` used to shell `.opencode/init.sh` (macOS `md5`,
5
+ * `.opencode/enforcer-config.json`). That is factory boot theater, not wear.
6
+ */
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { frameworkLogger } from "../../core/framework-logger.js";
10
+ /** Same paths as `REQUIRED_PACK_PATHS` in assert-packed-dist-cli.mjs — typed here so src/cli does not import untyped .mjs. */
11
+ export const VALIDATE_PACK_PATHS = [
12
+ "dist/cli/index.js",
13
+ "dist/mcps/orchestrator.server.js",
14
+ "dist/integrations/grok/hooks/session-start.js",
15
+ "dist/integrations/cursor/hooks/hooks.json",
16
+ "dist/integrations/cursor/hooks/pre-tool-use.js",
17
+ "dist/integrations/cursor/hooks/pre-compact.js",
18
+ "dist/integrations/cursor/hooks/after-file-edit.js",
19
+ "dist/integrations/cursor/hooks/cursor-hook-utils.js",
20
+ "dist/integrations/cursor/hooks/cursor-usage-receipt.js",
21
+ ];
22
+ export const CONSUMER_WEAR_PATHS = [
23
+ "AGENTS.md",
24
+ ".mcp.json",
25
+ ".xray/codex.json",
26
+ ".xray/features.json",
27
+ ".cursor/hooks.json",
28
+ ];
29
+ export const MILL_PLANT_SKILLS = ["mill", "inspect"];
30
+ export function resolveInstalledPackageRoot(cwd) {
31
+ const nested = join(cwd, "node_modules", "0xray");
32
+ if (existsSync(join(nested, "package.json"))) {
33
+ return nested;
34
+ }
35
+ const pkgPath = join(cwd, "package.json");
36
+ if (!existsSync(pkgPath)) {
37
+ return null;
38
+ }
39
+ try {
40
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
41
+ if (pkg.name === "0xray") {
42
+ return cwd;
43
+ }
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ return null;
49
+ }
50
+ export function isConsumerInstall(cwd, packageRoot) {
51
+ return packageRoot !== cwd;
52
+ }
53
+ function checkPath(root, rel) {
54
+ return existsSync(join(root, rel));
55
+ }
56
+ function stationDurableHoldsNpm(cwd) {
57
+ const dest = join(cwd, ".xray", "state", "STATION.md");
58
+ if (!existsSync(dest))
59
+ return false;
60
+ try {
61
+ return /\bhold\s+npm\b/i.test(readFileSync(dest, "utf8"));
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ }
67
+ export function collectValidateReport(cwd) {
68
+ const packageRoot = resolveInstalledPackageRoot(cwd);
69
+ const checks = [];
70
+ if (!packageRoot) {
71
+ return {
72
+ ok: false,
73
+ consumer: false,
74
+ packageRoot: cwd,
75
+ checks: [
76
+ {
77
+ id: "package",
78
+ ok: false,
79
+ detail: "0xray package not found in cwd or node_modules/0xray",
80
+ },
81
+ ],
82
+ };
83
+ }
84
+ const consumer = isConsumerInstall(cwd, packageRoot);
85
+ checks.push({
86
+ id: "package",
87
+ ok: true,
88
+ detail: consumer ? `consumer node_modules/0xray at ${packageRoot}` : `exo dogfood at ${packageRoot}`,
89
+ });
90
+ const missingPack = VALIDATE_PACK_PATHS.filter((p) => !checkPath(packageRoot, p));
91
+ checks.push({
92
+ id: "pack-paths",
93
+ ok: missingPack.length === 0,
94
+ detail: missingPack.length === 0
95
+ ? `REQUIRED_PACK_PATHS ${VALIDATE_PACK_PATHS.length}/${VALIDATE_PACK_PATHS.length}`
96
+ : `missing ${missingPack.join(", ")}`,
97
+ });
98
+ if (consumer) {
99
+ const missingWear = CONSUMER_WEAR_PATHS.filter((p) => !checkPath(cwd, p));
100
+ checks.push({
101
+ id: "consumer-wear",
102
+ ok: missingWear.length === 0,
103
+ detail: missingWear.length === 0
104
+ ? "AGENTS.md · .mcp.json · .xray · .cursor/hooks.json"
105
+ : `missing ${missingWear.join(", ")}`,
106
+ });
107
+ const millRoot = join(cwd, ".opencode", "skills");
108
+ const missingMill = MILL_PLANT_SKILLS.filter((name) => !existsSync(join(millRoot, name, "SKILL.md")));
109
+ checks.push({
110
+ id: "mill-plant",
111
+ ok: missingMill.length === 0,
112
+ detail: missingMill.length === 0
113
+ ? "mill + inspect fastened"
114
+ : `missing plant ${missingMill.join(", ")}`,
115
+ });
116
+ const repertoire = existsSync(join(cwd, "node_modules", "@0xray", "repertoire", "package.json")) ||
117
+ existsSync(join(packageRoot, "vendor", "@0xray", "repertoire", "package.json"));
118
+ checks.push({
119
+ id: "repertoire",
120
+ ok: repertoire,
121
+ detail: repertoire ? "repertoire organ on disk" : "missing @0xray/repertoire",
122
+ });
123
+ }
124
+ const stationPath = join(cwd, ".xray", "state", "STATION.md");
125
+ if (existsSync(stationPath)) {
126
+ const staleHold = stationDurableHoldsNpm(cwd);
127
+ checks.push({
128
+ id: "durable-hold",
129
+ ok: !staleHold,
130
+ detail: staleHold
131
+ ? "STATION Durable still says Hold npm — heat should have stripped it"
132
+ : "Durable has no Hold npm",
133
+ });
134
+ }
135
+ return {
136
+ ok: checks.every((c) => c.ok),
137
+ consumer,
138
+ packageRoot,
139
+ checks,
140
+ };
141
+ }
142
+ export async function validateCommand(cwd = process.cwd()) {
143
+ frameworkLogger.log("cli", "validate-start", "info", { cwd });
144
+ const report = collectValidateReport(cwd);
145
+ for (const check of report.checks) {
146
+ const mark = check.ok ? "✅" : "❌";
147
+ console.log(`${mark} ${check.id}: ${check.detail}`);
148
+ }
149
+ if (report.ok) {
150
+ console.log("");
151
+ console.log("🎉 Wear checks passed. This is not leftover init.sh.");
152
+ frameworkLogger.log("cli", "validate-success", "info", { consumer: report.consumer });
153
+ }
154
+ else {
155
+ console.log("");
156
+ console.log("❌ Validation failed. Pack/wear miss — not a Mac init.sh leftover.");
157
+ frameworkLogger.log("cli", "validate-fail", "error", {
158
+ consumer: report.consumer,
159
+ failed: report.checks.filter((c) => !c.ok).map((c) => c.id),
160
+ });
161
+ }
162
+ return report;
163
+ }
164
+ export default validateCommand;
package/dist/cli/index.js CHANGED
@@ -99,23 +99,15 @@ program
99
99
  });
100
100
  program
101
101
  .command("validate")
102
- .description("Validate xray framework installation")
102
+ .description("Validate consumer wear (pack paths, Cursor hooks, mill plant) — not leftover init.sh")
103
103
  .action(async () => {
104
104
  console.log("🔬 xray CLI: Validating installation...");
105
105
  try {
106
- // Run the init.sh script to validate
107
- const initScript = join(packageRoot, ".opencode", "init.sh");
108
- const fs = await import("fs");
109
- if (!fs.existsSync(initScript)) {
110
- console.error("❌ Validation failed: init script not found:", initScript);
106
+ const { validateCommand } = await import("./commands/validate.js");
107
+ const report = await validateCommand(process.cwd());
108
+ if (!report.ok) {
111
109
  process.exit(1);
112
110
  }
113
- // SECURITY: Validate script path before execution
114
- validateScriptPath(initScript, "init script");
115
- execSync(`bash "${initScript}"`, {
116
- stdio: "inherit",
117
- cwd: process.cwd(),
118
- });
119
111
  }
120
112
  catch (error) {
121
113
  console.error("❌ Validation failed:", error instanceof Error ? error.message : String(error));
@@ -25,6 +25,7 @@ import { appendHookActivity } from '../../grok/hooks/grok-hook-activity.js';
25
25
  import {
26
26
  buildRepertoireResume,
27
27
  readGitBrief,
28
+ stationDurableHoldsNpm,
28
29
  } from '../../hooks/station-hook-runtime.mjs';
29
30
 
30
31
  export const CURSOR_HOST = 'cursor';
@@ -147,6 +148,7 @@ export function cursorBootNeedsRefresh(existing, root) {
147
148
  if (liveGit && liveGit.head && bootHead !== liveGit.head) return true;
148
149
  const liveResume = buildRepertoireResume(root);
149
150
  if (liveResume && existing.repertoireResume && liveResume !== existing.repertoireResume) return true;
151
+ if (stationDurableHoldsNpm(root)) return true;
150
152
  return false;
151
153
  }
152
154
 
@@ -383,6 +383,23 @@ function isDurableStationHeading(line) {
383
383
  return /^##\s+(durable|seed)\b/i.test(String(line || "").trim());
384
384
  }
385
385
 
386
+ /** Durable is identity. Hold/ship lives in mill-gate — not on the card. */
387
+ function isHoldNpmLine(line) {
388
+ return /\bhold\s+npm\b/i.test(String(line || "").trim());
389
+ }
390
+
391
+ function stripHoldNpm(line) {
392
+ return String(line || "")
393
+ .replace(/\s*hold\s+npm\.?/gi, "")
394
+ .replace(/[ \t]+$/g, "");
395
+ }
396
+
397
+ function stationDurableHoldsNpm(root) {
398
+ return readExistingStationMarkdown(root)
399
+ .split(/\r?\n/)
400
+ .some((line) => isHoldNpmLine(line));
401
+ }
402
+
386
403
  function isStockStationLine(line) {
387
404
  const trimmed = String(line || "").trim();
388
405
  if (!trimmed) return true;
@@ -411,12 +428,14 @@ function extractPreservedStationLines(existing) {
411
428
  if (otherHeading || isStockStationLine(line)) {
412
429
  inDurable = false;
413
430
  } else {
414
- preserved.push(line);
431
+ const durableLine = stripHoldNpm(line);
432
+ if (durableLine.trim()) preserved.push(durableLine);
415
433
  continue;
416
434
  }
417
435
  }
418
436
  if (isStockStationLine(line)) continue;
419
- preserved.push(line);
437
+ const kept = stripHoldNpm(line);
438
+ if (kept.trim()) preserved.push(kept);
420
439
  }
421
440
  while (preserved.length && !preserved[0].trim()) preserved.shift();
422
441
  while (preserved.length && !preserved[preserved.length - 1].trim()) preserved.pop();
@@ -506,4 +525,6 @@ module.exports = {
506
525
  mergeStationMarkdown,
507
526
  formatStationMarkdown,
508
527
  writeStationMarkdown,
528
+ isHoldNpmLine,
529
+ stationDurableHoldsNpm,
509
530
  };
@@ -24,3 +24,5 @@ export const extractPreservedStationLines = impl.extractPreservedStationLines;
24
24
  export const mergeStationMarkdown = impl.mergeStationMarkdown;
25
25
  export const formatStationMarkdown = impl.formatStationMarkdown;
26
26
  export const writeStationMarkdown = impl.writeStationMarkdown;
27
+ export const isHoldNpmLine = impl.isHoldNpmLine;
28
+ export const stationDurableHoldsNpm = impl.stationDurableHoldsNpm;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.15",
3
+ "version": "4.0.16",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -68,7 +68,8 @@ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `g
68
68
  - **Wear first:** Read `.xray/state/STATION.md`. Same cloud. Same critic (resume only). Dummy Reads Station.
69
69
  - **Dummy tests `SKILLS.md`:** a suited dummy proves the worn catalog. Same-sess bodies keep context and hold a Station card.
70
70
  - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR.
71
- - **Publish:** spawn the OTP browser, watch success, poll `npm view` until the new version is live. Do not move on early. Railway same law.
71
+ - **Publish:** stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY. Paste the clickable `auth/cli` URL. No Enter, no VM browser, no subagent, no 6-digit code in chat. Poll `npm view` until live. Then prove **fresh** and **upgrade** registry installs. `npx 0xray validate` is the wear check (not leftover init.sh). `npm view` is not an install.
72
+ - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
72
73
  - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes.
73
74
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
74
75
  - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.15",
3
+ "version": "4.0.16",
4
4
  "description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
5
5
  "readme": "README.md",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.15",
3
+ "version": "4.0.16",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -68,7 +68,8 @@ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `g
68
68
  - **Wear first:** Read `.xray/state/STATION.md`. Same cloud. Same critic (resume only). Dummy Reads Station.
69
69
  - **Dummy tests `SKILLS.md`:** a suited dummy proves the worn catalog. Same-sess bodies keep context and hold a Station card.
70
70
  - **Ship track:** always branch + worktree/aside + PR. Docs as you go. Builds. Rollback = close the PR.
71
- - **Publish:** spawn the OTP browser, watch success, poll `npm view` until the new version is live. Do not move on early. Railway same law.
71
+ - **Publish:** stay logged in (do not `npm logout`). Every time run `npm publish --access public` in the live TTY. Paste the clickable `auth/cli` URL. No Enter, no VM browser, no subagent, no 6-digit code in chat. Poll `npm view` until live. Then prove **fresh** and **upgrade** registry installs. `npx 0xray validate` is the wear check (not leftover init.sh). `npm view` is not an install.
72
+ - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
72
73
  - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes.
73
74
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
74
75
  - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.15",
3
+ "version": "4.0.16",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",