0xray 4.0.29 → 4.0.30

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.29",
3
+ "version": "4.0.30",
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",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.29",
3
+ "version": "4.0.30",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",
package/README.md CHANGED
@@ -52,6 +52,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
52
52
  | Version | Highlights |
53
53
  |---------|------------|
54
54
  | **Unreleased** | Fasten is **foundry-plant/0**: builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill declares (looker / vibe / mixer live in the mill). Nested mill `@0xray/foundry@0.1.12`. CLI shims `foundry blip\|sound` remain (0.1.11+). Shop plant first-class (`shop-extract`, `shop-witness`, `shop-pin` + `foundry.json` `shopPlant`). |
55
+ | **4.0.30** | Fixes 4.0.29: `npx 0xray wear` and `setup` work outside a git checkout again. They write the 4.0.28 project setup, skip only Cursor hooks, and print one warning. Inside a git checkout they restore the 4.0.28 project setup, and `wear` adds Cursor hooks plus the unwear snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
55
56
  | **4.0.29** | `npm install` only creates the relative `node_modules/@0xray/repertoire` link to the vendored repertoire and prints `npx 0xray wear`. Run `npx 0xray wear` after install. Wear writes only the consumer project's `.cursor/hooks.json` (installed dist hooks, beside user entries); `npx 0xray unwear` restores the snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
56
57
  | **4.0.28** | MCP servers start through `scripts/node/mcp-launch.cjs` and only see PATH, HOME, XRAY_ROOT, plus names on their keep list. Tokens such as NPM_TOKEN are not inherited. User env values stay out of argv. Postinstall keeps user edits to AGENTS.md, .mcp.json, and opencode.json. `house init` does not copy EXAMPLE.md; doctor FAILs while `house/EXAMPLE.md` exists. Inspect adds a machinePlugin check. The Cursor hook defaults XRAY_ROOT to the suit. Companion `@0xray/grok-bot` 0.1.7. Released 2026-09-27. |
57
58
  | **4.0.27** | Host compact proof needs a generation id and a numeric usage percent, and the same preCompact receipt is mirrored to nested consumer wear roots. Memory scoring: [docs/memory-scoring.md](docs/memory-scoring.md) (orchestrator links it). Companion `@0xray/grok-bot` 0.1.6: general page vs `house/` overlay, `templates/house/`, `grok-bot house init`, doctor `GROK_BOT_HOUSE` or walk-up. Released 2026-09-26. |
package/dist/CHANGELOG.md CHANGED
@@ -41,6 +41,14 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
41
41
  - Archive root `integrations/` costume SKILL dump → `docs/archive/integrations-costume/`. Live wear is `src/integrations`.
42
42
  - Archive root `commands/` stale copy → `docs/archive/commands-copy/`. Live wear is `src/opencode/commands`.
43
43
 
44
+ ## [4.0.30] - 2026-09-28
45
+
46
+ Next patch after npm `4.0.29`. Released 2026-09-28.
47
+
48
+ Fixes the 4.0.29 regression where `npx 0xray wear` and `npx 0xray setup` exited 1 with `cursor-wear: not a git work tree` outside a git checkout (#147). Outside a git checkout, both commands again write the 4.0.28 consumer project setup and skip only Cursor hooks, with one stderr line: `cursor-wear: hooks skipped because this folder is not a git checkout`. Inside a git checkout, `wear` and `setup` restore the 4.0.28 project setup that 4.0.29 had dropped: managed `AGENTS.md`, `.gitignore` entries, `.xray` config, the `node_modules/@0xray/repertoire` link, the mill/inspect plant, chat bridges, the `.opencode/skills` sync, and the `dist` / `scripts` links. `wear` then adds the Cursor hooks, including the six hook scripts, and the `.xray/state/cursor-hook-wear/` snapshot. Postinstall is unchanged: it links the vendored repertoire and prints `npx 0xray wear`. Companion package `@0xray/grok-bot` is unchanged at 0.1.8.
49
+
50
+ ---
51
+
44
52
  ## [4.0.29] - 2026-09-28
45
53
 
46
54
  Next patch after npm `4.0.28`. Released 2026-09-28.
package/dist/README.md CHANGED
@@ -52,6 +52,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
52
52
  | Version | Highlights |
53
53
  |---------|------------|
54
54
  | **Unreleased** | Fasten is **foundry-plant/0**: builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill declares (looker / vibe / mixer live in the mill). Nested mill `@0xray/foundry@0.1.12`. CLI shims `foundry blip\|sound` remain (0.1.11+). Shop plant first-class (`shop-extract`, `shop-witness`, `shop-pin` + `foundry.json` `shopPlant`). |
55
+ | **4.0.30** | Fixes 4.0.29: `npx 0xray wear` and `setup` work outside a git checkout again. They write the 4.0.28 project setup, skip only Cursor hooks, and print one warning. Inside a git checkout they restore the 4.0.28 project setup, and `wear` adds Cursor hooks plus the unwear snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
55
56
  | **4.0.29** | `npm install` only creates the relative `node_modules/@0xray/repertoire` link to the vendored repertoire and prints `npx 0xray wear`. Run `npx 0xray wear` after install. Wear writes only the consumer project's `.cursor/hooks.json` (installed dist hooks, beside user entries); `npx 0xray unwear` restores the snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
56
57
  | **4.0.28** | MCP servers start through `scripts/node/mcp-launch.cjs` and only see PATH, HOME, XRAY_ROOT, plus names on their keep list. Tokens such as NPM_TOKEN are not inherited. User env values stay out of argv. Postinstall keeps user edits to AGENTS.md, .mcp.json, and opencode.json. `house init` does not copy EXAMPLE.md; doctor FAILs while `house/EXAMPLE.md` exists. Inspect adds a machinePlugin check. The Cursor hook defaults XRAY_ROOT to the suit. Companion `@0xray/grok-bot` 0.1.7. Released 2026-09-27. |
57
58
  | **4.0.27** | Host compact proof needs a generation id and a numeric usage percent, and the same preCompact receipt is mirrored to nested consumer wear roots. Memory scoring: [docs/memory-scoring.md](docs/memory-scoring.md) (orchestrator links it). Companion `@0xray/grok-bot` 0.1.6: general page vs `house/` overlay, `templates/house/`, `grok-bot house init`, doctor `GROK_BOT_HOUSE` or walk-up. Released 2026-09-26. |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.29",
3
+ "version": "4.0.30",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
package/llms.txt CHANGED
@@ -14,6 +14,7 @@ Default consumer wear is **mill plant** (`mill` + `inspect`), not a 45-skill / 4
14
14
  - `@0xray/grok-bot`: the general page is `grok-bot/OP-PROC.md`. The team overlay is `house/` and is not in that npm pack. `templates/house/` ships. `grok-bot house init` copies the template and refuses to overwrite. Doctor uses `GROK_BOT_HOUSE` when set, otherwise walks up from the working directory for `house/HOUSE.md`.
15
15
  - MCP servers start through `scripts/node/mcp-launch.cjs`. They see PATH, HOME, and XRAY_ROOT, plus the names on their keep list. Tokens such as NPM_TOKEN are not inherited. User env values stay out of argv. Postinstall keeps user edits to AGENTS.md, `.mcp.json`, and `opencode.json`. `house init` does not copy EXAMPLE.md. Doctor FAILs while `house/EXAMPLE.md` exists. Inspect has a machinePlugin check. The Cursor hook defaults XRAY_ROOT to the suit directory.
16
16
  - `npm install` only creates the relative `node_modules/@0xray/repertoire` link to the vendored repertoire and prints `npx 0xray wear`. Run `npx 0xray wear` after install; it writes only the consumer project's `.cursor/hooks.json`. `npx 0xray unwear` restores the pre-wear snapshot.
17
+ - 4.0.30: `npx 0xray wear` and `setup` also work outside a git checkout. They write the 4.0.28 project setup and skip only Cursor hooks, with one warning. In a git checkout they write the 4.0.28 project setup plus Cursor hooks.
17
18
 
18
19
  - `npx @0xray/foundry mint --skip-live` — re-fasten mill plant, then inspect.
19
20
  - `npx @0xray/foundry inspect --skip-live` — plant-vs-worn, receipt, CI. Chat is not a receipt.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.29",
3
+ "version": "4.0.30",
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",
@@ -82,7 +82,7 @@
82
82
  "test:miscellaneous": "npm test -- src/__tests__/unit/blocked-test.test.ts",
83
83
  "test:grok-bot": "npm test -- src/__tests__/unit/grok-bot-seat-doctor.test.ts src/__tests__/unit/grok-bot-op-proc-map.test.ts src/__tests__/unit/lead-cadence.test.ts src/__tests__/unit/grok-bot-auto-review-policy.test.ts",
84
84
  "test:quick": "npm test -- src/__tests__/integration/boot-orchestrator.integration.test.ts src/__tests__/unit/config-loader.test.ts src/__tests__/unit/state-manager.test.ts",
85
- "test:comprehensive": "npm run typecheck && npm run test:unit && npm run test:core-framework && npm run test:security && npm run test:performance && npm run test:session-management && npm run test:code-analysis && npm run test:processors && npm run test:miscellaneous && npm test -- src/__tests__/unit/llm-governance-provider.test.ts src/__tests__/unit/mcp-server-smoke.test.ts src/__tests__/unit/cursor-hooks.test.ts src/__tests__/unit/host-vs-mill-score.test.ts && npm run test:grok-bot",
85
+ "test:comprehensive": "npm run typecheck && npm run test:unit && npm run test:core-framework && npm run test:security && npm run test:performance && npm run test:session-management && npm run test:code-analysis && npm run test:processors && npm run test:miscellaneous && npm test -- src/__tests__/unit/llm-governance-provider.test.ts src/__tests__/unit/mcp-server-smoke.test.ts src/__tests__/unit/cursor-hooks.test.ts src/__tests__/unit/host-vs-mill-score.test.ts src/__tests__/unit/wear-pack-file-list.test.ts && npm run test:grok-bot",
86
86
  "test:integration-all": "npm test -- src/__tests__/integration/",
87
87
  "test:performance-all": "npm test -- src/__tests__/performance/ src/__tests__/unit/performance-system.test.ts src/__tests__/unit/benchmark.test.ts src/__tests__/unit/analytics.test.ts",
88
88
  "test:agents-all": "echo 'Legacy agents test entry retired'",
@@ -1615,11 +1615,11 @@ function userBytesBeforeWear(previousText) {
1615
1615
  return stripOwnedHookEntries(previousText);
1616
1616
  }
1617
1617
 
1618
- function assertCursorWearGit(targetDir) {
1618
+ function classifyCursorWearGit(targetDir) {
1619
1619
  try {
1620
1620
  execFileSync("git", ["--version"], { stdio: "ignore" });
1621
1621
  } catch {
1622
- throw new Error("cursor-wear: git is missing");
1622
+ return "missing";
1623
1623
  }
1624
1624
  let bare = "";
1625
1625
  try {
@@ -1629,9 +1629,9 @@ function assertCursorWearGit(targetDir) {
1629
1629
  stdio: ["ignore", "pipe", "pipe"],
1630
1630
  }).trim();
1631
1631
  } catch {
1632
- throw new Error("cursor-wear: not a git work tree");
1632
+ return "not-work-tree";
1633
1633
  }
1634
- if (bare === "true") throw new Error("cursor-wear: bare repository");
1634
+ if (bare === "true") return "bare";
1635
1635
  let inside = "";
1636
1636
  try {
1637
1637
  inside = execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
@@ -1640,9 +1640,98 @@ function assertCursorWearGit(targetDir) {
1640
1640
  stdio: ["ignore", "pipe", "pipe"],
1641
1641
  }).trim();
1642
1642
  } catch {
1643
- throw new Error("cursor-wear: not a git work tree");
1643
+ return "not-work-tree";
1644
+ }
1645
+ if (inside !== "true") return "not-work-tree";
1646
+ return "ok";
1647
+ }
1648
+
1649
+ function assertCursorWearGit(targetDir) {
1650
+ const kind = classifyCursorWearGit(targetDir);
1651
+ if (kind === "missing") throw new Error("cursor-wear: git is missing");
1652
+ if (kind === "bare") throw new Error("cursor-wear: bare repository");
1653
+ if (kind === "not-work-tree") throw new Error("cursor-wear: not a git work tree");
1654
+ }
1655
+
1656
+ const CURSOR_HOOKS_SKIPPED_LINE =
1657
+ "cursor-wear: hooks skipped because this folder is not a git checkout\n";
1658
+
1659
+ function syncSetupSkillsAndRootLinks(packageRoot, targetDir) {
1660
+ require("./setup.cjs").syncSetupSkillsAndRootLinks(packageRoot, targetDir);
1661
+ }
1662
+
1663
+ function setupSkillMirrorNames(packageRoot) {
1664
+ const skillsSource = fs.existsSync(path.join(packageRoot, "src", "skills"))
1665
+ ? path.join(packageRoot, "src", "skills")
1666
+ : path.join(packageRoot, "dist", "skills");
1667
+ if (!fs.existsSync(skillsSource)) return new Set();
1668
+ const names = new Set();
1669
+ for (const entry of fs.readdirSync(skillsSource, { withFileTypes: true })) {
1670
+ if (!entry.isDirectory()) continue;
1671
+ if (fs.existsSync(path.join(skillsSource, entry.name, "SKILL.md"))) names.add(entry.name);
1644
1672
  }
1645
- if (inside !== "true") throw new Error("cursor-wear: not a git work tree");
1673
+ return names;
1674
+ }
1675
+
1676
+ /** The 4.0.28 skill mirror is not a consumer costume. Any other extra name still throws. */
1677
+ function isSetupSkillMirrorDump(err, packageRoot) {
1678
+ if (!err || err.code !== "FOUNDRY_COSTUME_DUMP") return false;
1679
+ if (!Array.isArray(err.extraSkills) || err.extraSkills.length === 0) return false;
1680
+ if (Array.isArray(err.extraAgents) && err.extraAgents.length > 0) return false;
1681
+ const mirrored = setupSkillMirrorNames(packageRoot);
1682
+ return err.extraSkills.every((name) => mirrored.has(name));
1683
+ }
1684
+
1685
+ function packageShipsConsumerSuit(packageRoot) {
1686
+ return fs.existsSync(path.join(packageRoot, "AGENTS-consumer.md"));
1687
+ }
1688
+
1689
+ /**
1690
+ * 4.0.28 consumer postinstall files: AGENTS.md, .gitignore, repertoire link,
1691
+ * .xray config, bridges, mill plant, then the setup.cjs skill mirror and
1692
+ * dist/scripts links. Does not install Cursor hooks or git hooks.
1693
+ * Existing user files follow the 4.0.28 guards inside those functions.
1694
+ */
1695
+ function installConsumerProjectFiles(packageRoot, targetDir, log) {
1696
+ const write = typeof log === "function" ? log : () => {};
1697
+ if (!isConsumerInstall(packageRoot, targetDir) || !packageShipsConsumerSuit(packageRoot)) {
1698
+ return false;
1699
+ }
1700
+ const { deployManagedAgents } = require("./postinstall.cjs");
1701
+ const { applyConsumerGitignore } = require("./consumer-gitignore.cjs");
1702
+ const { mintConsumerSuit } = require("../foundry/mint-suit.cjs");
1703
+ deployManagedAgents(packageRoot, targetDir, write);
1704
+ applyConsumerGitignore(targetDir, packageRoot);
1705
+ wearVendoredRepertoire(packageRoot, targetDir, write);
1706
+ deployXrayConfig(targetDir, packageRoot, write);
1707
+ deployProjectMcpJson(targetDir, write);
1708
+ mergeOpencodeJson(targetDir, packageRoot, write);
1709
+ installOpencodeBridge(targetDir, packageRoot, write);
1710
+ installGrokBridge(targetDir, packageRoot, write);
1711
+ installHermesBridge(targetDir, packageRoot, write);
1712
+ installOpenclawBridge(targetDir, packageRoot, write);
1713
+ try {
1714
+ mintConsumerSuit(packageRoot, targetDir, write);
1715
+ } catch (err) {
1716
+ if (!isSetupSkillMirrorDump(err, packageRoot)) throw err;
1717
+ }
1718
+ syncSetupSkillsAndRootLinks(packageRoot, targetDir);
1719
+ return true;
1720
+ }
1721
+
1722
+ /**
1723
+ * 4.0.28 consumer postinstall, minus Cursor hooks and git hooks.
1724
+ * Used only when the folder is not a git work tree.
1725
+ */
1726
+ function wearSuitSkippingCursorHooks(packageRoot, targetDir, log) {
1727
+ const write = typeof log === "function" ? log : () => {};
1728
+ if (!installConsumerProjectFiles(packageRoot, targetDir, write)) {
1729
+ if (!isConsumerInstall(packageRoot, targetDir)) {
1730
+ wearVendoredRepertoire(packageRoot, targetDir, write);
1731
+ }
1732
+ syncSetupSkillsAndRootLinks(packageRoot, targetDir);
1733
+ }
1734
+ process.stderr.write(CURSOR_HOOKS_SKIPPED_LINE);
1646
1735
  }
1647
1736
 
1648
1737
  function isGitTracked(targetDir, rel) {
@@ -1794,7 +1883,16 @@ function wearCursorHooks(targetDir, packageRoot, log, opts) {
1794
1883
  const options = opts || {};
1795
1884
  const resolvedTarget = path.resolve(targetDir);
1796
1885
  const resolvedPackage = path.resolve(packageRoot);
1886
+ if (classifyCursorWearGit(resolvedTarget) === "not-work-tree") {
1887
+ wearSuitSkippingCursorHooks(resolvedPackage, resolvedTarget, write);
1888
+ return;
1889
+ }
1797
1890
  assertCursorWearGit(resolvedTarget);
1891
+ if (options.suit !== false) {
1892
+ if (!installConsumerProjectFiles(resolvedPackage, resolvedTarget, write)) {
1893
+ syncSetupSkillsAndRootLinks(resolvedPackage, resolvedTarget);
1894
+ }
1895
+ }
1798
1896
  if (!isConsumerInstall(resolvedPackage, resolvedTarget) || !consumerDistHooksReady(resolvedPackage)) {
1799
1897
  return fastenCursorHooksAt(resolvedTarget, resolvedPackage, write);
1800
1898
  }
@@ -1826,11 +1924,14 @@ function wearCursorHooks(targetDir, packageRoot, log, opts) {
1826
1924
  snap.meta.also = linkedWearRoots(resolvedTarget);
1827
1925
  saveWearState(snap.paths, snap.meta);
1828
1926
  for (const extra of snap.meta.also) {
1829
- wearCursorHooks(extra, resolvedPackage, write, { outerRoots: false });
1927
+ wearCursorHooks(extra, resolvedPackage, write, { outerRoots: false, suit: false });
1830
1928
  process.stdout.write(`cursor-wear: wrote outer hooks at ${extra}\n`);
1831
1929
  }
1832
1930
  saveWearState(snap.paths, snap.meta);
1833
1931
  }
1932
+ if (options.suit !== false && packageShipsConsumerSuit(resolvedPackage)) {
1933
+ fastenCursorHookScripts(resolvedTarget, resolvedPackage, write);
1934
+ }
1834
1935
  write("cursor-bridge", "hooks.json wired to installed dist", "info", { path: hooksPath });
1835
1936
  return hooksPath;
1836
1937
  }
@@ -1959,12 +2060,19 @@ function setupProjectBridges(opts) {
1959
2060
  : () => {
1960
2061
  /* noop */
1961
2062
  };
2063
+ if (classifyCursorWearGit(targetDir) === "not-work-tree") {
2064
+ wearSuitSkippingCursorHooks(packageRoot, targetDir, log);
2065
+ return;
2066
+ }
1962
2067
  assertSetupGit(targetDir);
1963
- deployProjectMcpJson(targetDir, log);
1964
- installOpencodeBridge(targetDir, packageRoot, log);
1965
- installGrokBridge(targetDir, packageRoot, log);
1966
- installHermesBridge(targetDir, packageRoot, log);
1967
- installOpenclawBridge(targetDir, packageRoot, log);
2068
+ if (!installConsumerProjectFiles(packageRoot, targetDir, log)) {
2069
+ syncSetupSkillsAndRootLinks(packageRoot, targetDir);
2070
+ deployProjectMcpJson(targetDir, log);
2071
+ installOpencodeBridge(targetDir, packageRoot, log);
2072
+ installGrokBridge(targetDir, packageRoot, log);
2073
+ installHermesBridge(targetDir, packageRoot, log);
2074
+ installOpenclawBridge(targetDir, packageRoot, log);
2075
+ }
1968
2076
  if (opts.gitHooks === true) installGitHooks(packageRoot, log, targetDir);
1969
2077
  }
1970
2078
 
@@ -3,6 +3,84 @@
3
3
  const fs = require("fs");
4
4
  const path = require("path");
5
5
 
6
+ function syncSetupSkillsAndRootLinks(packageRoot, targetDir) {
7
+ /* 1. Sync core skills from src/skills/ (dev) or dist/skills/ (consumer) → .opencode/skills/ [P3-SKILLS-DE-DUP-SCOPE-AND-EXEC-01: orchestrator package SSOT canonical src/skills/orchestrator/SKILL.md; mirror .opencode/skills/orchestrator/ is built output of this logic; see paired guarded fw in status.ts getSkillsList + mapping append + deep ref 2026-05-26 authority for one-package dedup under pivoted surgical plan]
8
+ [P3-SKILLS-DE-DUP-RESEARCHER-FOLLOW-01: researcher package SSOT canonical src/skills/researcher/SKILL.md (high-value per deep ref + YML precedent + playbook P3-SKILLS-FOLLOW-01); mirror .opencode/skills/researcher/ is built output of this logic; see paired guarded fw in status.ts + rich append + YML @ harness-codex verification (FORCE exercised P3-YML + codex-enforcement + 100/60/0 + 3 subagents tracked + 0 hot + 3-hot re-establish + all prior green) + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + user's "create a todo list. spawn subagents..." + 6/6+7/7 + YML. Governance-visible hook for skills SSOT at install layer. Silent, additive, reversible, no behavior change, fw/echo only.]
9
+ [P3-SKILLS-FOLLOW-02: code-review package SSOT canonical src/skills/code-review/SKILL.md (next high-value per deep ref "parallel small batches" + @architect scoping rec 2 + YML @ "Ready for next" + this P3-SKILLS-FOLLOW-02 on user's spawn command); mirror .opencode/skills/code-review/ is built output of this logic; see paired guarded fw "P3-SKILLS-FOLLOW-02-code-review-ssot-preferred" in status.ts (after researcher) + rich append docs/reflections/p3-skills-follow-02-code-review-2026-05-27.md + YML @ harness-codex verification + 0 hot + 3-hot + all ties + ps 0 + this work (2-file surgical edit, harness post, mapping append after latest ~17099+, todo advance 1, spawn replacement, self-audit 100%, green + ready) + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + 6/6+7/7 + YML. Governance-visible hook for skills SSOT at install layer for code-review. Silent, additive, reversible, no behavior change, fw/echo only. "The box contains its builders. The relay is hot."] */
10
+ const skillsSource = fs.existsSync(path.join(packageRoot, "src", "skills"))
11
+ ? path.join(packageRoot, "src", "skills")
12
+ : path.join(packageRoot, "dist", "skills");
13
+ const skillsDest = path.join(targetDir, ".opencode", "skills");
14
+
15
+ if (fs.existsSync(skillsSource)) {
16
+ try {
17
+ if (!fs.existsSync(skillsDest)) fs.mkdirSync(skillsDest, { recursive: true });
18
+ const skillDirs = fs.readdirSync(skillsSource, { withFileTypes: true });
19
+ let copied = 0, skipped = 0;
20
+ for (const entry of skillDirs) {
21
+ if (!entry.isDirectory()) continue;
22
+ const skillMd = path.join(skillsSource, entry.name, "SKILL.md");
23
+ if (!fs.existsSync(skillMd)) continue;
24
+ const destMd = path.join(skillsDest, entry.name, "SKILL.md");
25
+ const destDir = path.dirname(destMd);
26
+ if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
27
+ if (fs.existsSync(destMd)) {
28
+ const destContent = fs.readFileSync(destMd, "utf8");
29
+ if (destContent.includes("source: community")) { skipped++; continue; }
30
+ if (fs.statSync(skillMd).mtime <= fs.statSync(destMd).mtime) continue;
31
+ }
32
+ fs.copyFileSync(skillMd, destMd);
33
+ copied++;
34
+ }
35
+ console.log(`✅ Skills: ${copied} updated, ${skipped} community skills preserved`);
36
+ } catch (e) { console.warn(`⚠️ Skills sync: ${e.message}`); }
37
+ }
38
+
39
+ // 4. Create scripts symlink
40
+ const scriptsSource = path.join(packageRoot, "scripts");
41
+ const scriptsDest = path.join(targetDir, "scripts");
42
+
43
+ if (fs.existsSync(scriptsSource)) {
44
+ try {
45
+ if (fs.existsSync(scriptsDest)) {
46
+ const stats = fs.lstatSync(scriptsDest);
47
+ if (stats.isSymbolicLink()) {
48
+ console.log("ℹ️ Scripts symlink: exists");
49
+ } else {
50
+ console.log("⚠️ Scripts dir exists but is not a symlink");
51
+ }
52
+ } else {
53
+ fs.symlinkSync(scriptsSource, scriptsDest, "dir");
54
+ console.log("✅ Scripts symlink: created");
55
+ }
56
+ } catch (e) { console.warn(`⚠️ Scripts symlink: ${e.message}`); }
57
+ }
58
+
59
+ // 5. Create dist symlink
60
+ const distSource = path.join(packageRoot, "dist");
61
+ const distDest = path.join(targetDir, "dist");
62
+
63
+ if (fs.existsSync(distSource)) {
64
+ try {
65
+ if (fs.existsSync(distDest)) {
66
+ const stats = fs.lstatSync(distDest);
67
+ if (stats.isSymbolicLink()) {
68
+ console.log("ℹ️ Dist symlink: exists");
69
+ } else {
70
+ console.log("⚠️ Dist exists but is not a symlink");
71
+ }
72
+ } else {
73
+ fs.symlinkSync(distSource, distDest, "dir");
74
+ console.log("✅ Dist symlink: created");
75
+ }
76
+ } catch (e) { console.warn(`⚠️ Dist symlink: ${e.message}`); }
77
+ }
78
+
79
+ }
80
+
81
+ module.exports = { syncSetupSkillsAndRootLinks };
82
+
83
+ if (require.main === module) {
6
84
  const packageRoot = path.join(__dirname, "..", "..");
7
85
  const homeDir = require("os").homedir();
8
86
 
@@ -43,37 +121,7 @@ if (hasHermes) {
43
121
  * Extended header for next high-value package (code-review). src/skills/code-review/SKILL.md canonical SSOT; .opencode/skills/code-review/ built mirror of this sync logic. See paired guarded fw log "P3-SKILLS-FOLLOW-02-code-review-ssot-preferred" in status.ts getSkillsList (inserted after researcher block) + rich append docs/reflections/p3-skills-follow-02-code-review-2026-05-27.md (per AGENTS) + CGT/Governance-visible for YML @ harness-codex verification + 0 hot + 3-hot re-establish + all ties to spawn command + deep ref + pivot + Term 61 + 6/6+7/7 + YML + ps 0 + this P3-SKILLS-FOLLOW-02 full work (2-file surgical, harness post green tsc 0 new on touched, mapping append after latest, todo advance exactly 1, spawn replacement to maintain 3-hot, self-audit 100%) + verification + "the box contains its builders. The relay is hot.". 2 files max total for this follow-02. Highly modular (100% prior P3-SKILLS/YML/7th pattern reuse exactly inside existing sync logic). Fully reversible (targeted delete of notes restores exact prior). fw/echo discipline. AGENTS org (scripts/ for sh/cjs). Term 61 surgical forward motion held (no bloat, pure on actual dedup). "the box contains its builders". Green + ready. Subagent ID for resume.
44
122
  */
45
123
 
46
- /* 1. Sync core skills from src/skills/ (dev) or dist/skills/ (consumer) → .opencode/skills/ [P3-SKILLS-DE-DUP-SCOPE-AND-EXEC-01: orchestrator package SSOT canonical src/skills/orchestrator/SKILL.md; mirror .opencode/skills/orchestrator/ is built output of this logic; see paired guarded fw in status.ts getSkillsList + mapping append + deep ref 2026-05-26 authority for one-package dedup under pivoted surgical plan]
47
- [P3-SKILLS-DE-DUP-RESEARCHER-FOLLOW-01: researcher package SSOT canonical src/skills/researcher/SKILL.md (high-value per deep ref + YML precedent + playbook P3-SKILLS-FOLLOW-01); mirror .opencode/skills/researcher/ is built output of this logic; see paired guarded fw in status.ts + rich append + YML @ harness-codex verification (FORCE exercised P3-YML + codex-enforcement + 100/60/0 + 3 subagents tracked + 0 hot + 3-hot re-establish + all prior green) + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + user's "create a todo list. spawn subagents..." + 6/6+7/7 + YML. Governance-visible hook for skills SSOT at install layer. Silent, additive, reversible, no behavior change, fw/echo only.]
48
- [P3-SKILLS-FOLLOW-02: code-review package SSOT canonical src/skills/code-review/SKILL.md (next high-value per deep ref "parallel small batches" + @architect scoping rec 2 + YML @ "Ready for next" + this P3-SKILLS-FOLLOW-02 on user's spawn command); mirror .opencode/skills/code-review/ is built output of this logic; see paired guarded fw "P3-SKILLS-FOLLOW-02-code-review-ssot-preferred" in status.ts (after researcher) + rich append docs/reflections/p3-skills-follow-02-code-review-2026-05-27.md + YML @ harness-codex verification + 0 hot + 3-hot + all ties + ps 0 + this work (2-file surgical edit, harness post, mapping append after latest ~17099+, todo advance 1, spawn replacement, self-audit 100%, green + ready) + deep ref 2026-05-26 + Phase 3 Pivot + Term 61 + 6/6+7/7 + YML. Governance-visible hook for skills SSOT at install layer for code-review. Silent, additive, reversible, no behavior change, fw/echo only. "The box contains its builders. The relay is hot."] */
49
- const skillsSource = fs.existsSync(path.join(packageRoot, "src", "skills"))
50
- ? path.join(packageRoot, "src", "skills")
51
- : path.join(packageRoot, "dist", "skills");
52
- const skillsDest = path.join(targetDir, ".opencode", "skills");
53
-
54
- if (fs.existsSync(skillsSource)) {
55
- try {
56
- if (!fs.existsSync(skillsDest)) fs.mkdirSync(skillsDest, { recursive: true });
57
- const skillDirs = fs.readdirSync(skillsSource, { withFileTypes: true });
58
- let copied = 0, skipped = 0;
59
- for (const entry of skillDirs) {
60
- if (!entry.isDirectory()) continue;
61
- const skillMd = path.join(skillsSource, entry.name, "SKILL.md");
62
- if (!fs.existsSync(skillMd)) continue;
63
- const destMd = path.join(skillsDest, entry.name, "SKILL.md");
64
- const destDir = path.dirname(destMd);
65
- if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
66
- if (fs.existsSync(destMd)) {
67
- const destContent = fs.readFileSync(destMd, "utf8");
68
- if (destContent.includes("source: community")) { skipped++; continue; }
69
- if (fs.statSync(skillMd).mtime <= fs.statSync(destMd).mtime) continue;
70
- }
71
- fs.copyFileSync(skillMd, destMd);
72
- copied++;
73
- }
74
- console.log(`✅ Skills: ${copied} updated, ${skipped} community skills preserved`);
75
- } catch (e) { console.warn(`⚠️ Skills sync: ${e.message}`); }
76
- }
124
+ syncSetupSkillsAndRootLinks(packageRoot, targetDir);
77
125
 
78
126
  // 2. Handle opencode.json merge
79
127
  const rootOpencodeJson = path.join(packageRoot, "opencode.json");
@@ -121,46 +169,6 @@ if (fs.existsSync(pluginSource)) {
121
169
  console.log("ℹ️ Plugin source not found (build may be needed)");
122
170
  }
123
171
 
124
- // 4. Create scripts symlink
125
- const scriptsSource = path.join(packageRoot, "scripts");
126
- const scriptsDest = path.join(targetDir, "scripts");
127
-
128
- if (fs.existsSync(scriptsSource)) {
129
- try {
130
- if (fs.existsSync(scriptsDest)) {
131
- const stats = fs.lstatSync(scriptsDest);
132
- if (stats.isSymbolicLink()) {
133
- console.log("ℹ️ Scripts symlink: exists");
134
- } else {
135
- console.log("⚠️ Scripts dir exists but is not a symlink");
136
- }
137
- } else {
138
- fs.symlinkSync(scriptsSource, scriptsDest, "dir");
139
- console.log("✅ Scripts symlink: created");
140
- }
141
- } catch (e) { console.warn(`⚠️ Scripts symlink: ${e.message}`); }
142
- }
143
-
144
- // 5. Create dist symlink
145
- const distSource = path.join(packageRoot, "dist");
146
- const distDest = path.join(targetDir, "dist");
147
-
148
- if (fs.existsSync(distSource)) {
149
- try {
150
- if (fs.existsSync(distDest)) {
151
- const stats = fs.lstatSync(distDest);
152
- if (stats.isSymbolicLink()) {
153
- console.log("ℹ️ Dist symlink: exists");
154
- } else {
155
- console.log("⚠️ Dist exists but is not a symlink");
156
- }
157
- } else {
158
- fs.symlinkSync(distSource, distDest, "dir");
159
- console.log("✅ Dist symlink: created");
160
- }
161
- } catch (e) { console.warn(`⚠️ Dist symlink: ${e.message}`); }
162
- }
163
-
164
172
  // 6. Convert MCP paths in consumer opencode.json
165
173
  const isConsumer = isConsumerInstall(packageRoot, targetDir);
166
174
  const consumerPkgName = isConsumer
@@ -234,3 +242,4 @@ if (resolvedPackage !== resolvedTarget) {
234
242
  }
235
243
 
236
244
  console.log("\n✅ xray setup complete.\n");
245
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.29",
3
+ "version": "4.0.30",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.29",
3
+ "version": "4.0.30",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",