0xray 4.0.29 → 4.0.31

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 (44) hide show
  1. package/.grok-plugin/plugin.json +1 -1
  2. package/.opencode/skills/orchestrator/SKILL.md +12 -0
  3. package/.xray/features.json +1 -1
  4. package/README.md +1 -0
  5. package/dist/CHANGELOG.md +17 -0
  6. package/dist/README.md +1 -0
  7. package/dist/cli/commands/validate.js +5 -0
  8. package/dist/cli/index.js +16 -1
  9. package/dist/integrations/grok/hooks/grok-hook-utils.js +24 -4
  10. package/dist/integrations/grok/hooks/post-tool-use.js +2 -1
  11. package/dist/integrations/grok/hooks/pre-tool-use.js +90 -5
  12. package/dist/integrations/grok/hooks/session-start.js +7 -2
  13. package/dist/integrations/hooks/goggles-pipeline.mjs +568 -0
  14. package/dist/integrations/hooks/goggles-planes.json +28 -0
  15. package/dist/integrations/hooks/plates.cjs +23 -0
  16. package/dist/integrations/hooks/station-hook-runtime.cjs +40 -11
  17. package/dist/integrations/hooks/station-memory-ingest.mjs +3 -0
  18. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  19. package/dist/mcps/orchestrator/config/agent-capabilities.js +7 -0
  20. package/dist/memory-routing/plates.d.ts +1 -1
  21. package/dist/memory-routing/plates.js +5 -0
  22. package/dist/memory-routing/provider-loader.js +2 -0
  23. package/dist/nucleus/thin-dispatch.d.ts +1 -0
  24. package/dist/nucleus/thin-dispatch.js +4 -2
  25. package/dist/skills/orchestrator/SKILL.md +12 -0
  26. package/docs-site/docs/plates/glossary.md +27 -0
  27. package/docs-site/docs/plates/goggles.md +18 -0
  28. package/docs-site/docs/plates/grokbot.md +41 -0
  29. package/docs-site/docs/plates/host-pack.md +32 -0
  30. package/docs-site/docs/plates/house.md +42 -39
  31. package/docs-site/docs/plates/index.md +13 -1
  32. package/docs-site/docs/plates/kits.md +28 -0
  33. package/docs-site/docs/plates/suit.md +40 -0
  34. package/llms.txt +1 -0
  35. package/package.json +2 -2
  36. package/scripts/foundry/assert-packed-dist-cli.mjs +5 -0
  37. package/scripts/node/consumer-install-smoke.mjs +5 -0
  38. package/scripts/node/install-bridges.cjs +120 -12
  39. package/scripts/node/setup.cjs +80 -71
  40. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  41. package/src/mcps/orchestrator/config/agent-capabilities.ts +8 -0
  42. package/src/skills/orchestrator/SKILL.md +12 -0
  43. package/vendor/@0xray/repertoire/dist/paths.js +4 -0
  44. package/xray/features.json +1 -1
@@ -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.31",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -14,6 +14,7 @@ import {
14
14
  fromMemoryCapabilityMap,
15
15
  } from './memory-routing-bridge.js';
16
16
  import { routeSubagent } from '../../../nucleus/autonomy-kernel.js';
17
+ import { scoreAndRoute } from '../../../nucleus/thin-dispatch.js';
17
18
 
18
19
  /** routeSubagent names → AGENT_REGISTRY keys */
19
20
  const ROUTE_AGENT_ALIASES: Record<string, string> = {
@@ -102,6 +103,13 @@ export class AgentCapabilitiesManager {
102
103
  operationDescription = '',
103
104
  taskType = '',
104
105
  ): string | null {
106
+ if (operationDescription.trim()) {
107
+ const routed = scoreAndRoute(operationDescription, {});
108
+ if (routed.memoryRouting?.overridden && this.capabilities.has(routed.agent)) {
109
+ return routed.agent;
110
+ }
111
+ }
112
+
105
113
  if (taskType.trim()) {
106
114
  const routed = routeSubagent(taskType);
107
115
  const resolved = resolveRoutedAgent(routed, this.capabilities);
@@ -53,6 +53,18 @@ When `multi_agent_orchestration.lead_dev_mode` is true in `features.json` (defau
53
53
  | Test failures | bug-triage |
54
54
  | Review | code-review |
55
55
 
56
+ ## Goggles
57
+
58
+ Pushed on `feat/goggles-look`. Not merged. Not published. Grok CLI has not shipped this. Wear the local build. From the worn checkout run `node dist/integrations/hooks/goggles-pipeline.mjs`. Do not run `npx 0xray goggles`. If `dist` is older than `src/integrations/hooks/goggles-pipeline.mjs`, build that tree and wear that `dist`. A subagent wears this same local build.
59
+
60
+ Kind 0 is actuality. It compares the list in the file to the same six names in the code. It speaks only when those lists differ. A match is quiet. It does not read the suit that is running. It is not a plate type.
61
+
62
+ Kind 1 names one plane: dichotomy, syncopate, synthesis, or loop. The lens holds that plane. An action on that plane is quiet. An action on another plane, or on a pipeline drawing, is stopped. A pipeline drawing is not a scope stop. Ground is not a scope stop. Scope, when named, is ecosystem, part, one flow, or one artifact, and an action wider than that scope is stopped. One kind and one scope level at a time. Two planes, calling, ground, and a pipeline name do not arm the lens. `outer` without one plane is `Name one plane.` After 1 is empty. Nothing is picked. Calling stays off.
63
+
64
+ `digest` and `triage` return the card already built by `assemblePlane`. The fields are from, digest, plate, entry, exit, files, skills, setup, teardown, and worn. Empty stays empty. The rows are ground, routing, house, boot, governance, memory-recall, orchestration, processor, and reporting. Those nine are not Kind 0. `digest` fills the card. Entry and exit are the plate's input and output box titles when that plate has them. Setup and teardown stay empty unless the row names them. The mill path is `scripts/foundry`. `triage` adds the empty fields and whether the row holds. Zoom after the card is the same ladder: ecosystem, part, one flow, one artifact. One file is one artifact. Several files are not narrowed to a guessed file.
65
+
66
+ The hold lasts for the work that named the plane. It does not stop one tool and then forget. Work that says goggles clears the hold and stays quiet. The suit does not invent the plane.
67
+
56
68
  ## Hooks (rewired, not new MCPs)
57
69
 
58
70
  - **SessionStart** → `session-start.js` boots lead_dev_mode
@@ -421,6 +421,10 @@ export function reloadOpProc(cwd = process.cwd()) {
421
421
  }
422
422
  function mergeProjectOverlays(destPath) {
423
423
  mergeStackOverlay(destPath);
424
+ // Suit heat keeps repo-* off the project file. A wake that merges them
425
+ // and then prunes them records a fake 59 → 45 drop on every compact.
426
+ if (process.env.REPERTOIRE_SUBJECT_OVERLAY === '0')
427
+ return;
424
428
  mergeSubjectOverlay(destPath);
425
429
  }
426
430
  export function hydrateWritableSignals(seedPath, cwd = process.cwd()) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.29",
3
+ "version": "4.0.31",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",