0xray 4.0.27 → 4.0.29
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/.gitignore.default +1 -0
- package/.grok-plugin/plugin.json +1 -1
- package/.xray/features.json +1 -1
- package/README.md +4 -2
- package/dist/.gitignore.default +1 -0
- package/dist/CHANGELOG.md +16 -0
- package/dist/README.md +4 -2
- package/dist/cli/index.js +52 -44
- package/dist/integrations/cursor/README.md +21 -2
- package/dist/integrations/cursor/hooks/xray-cloud-hook.sh +62 -5
- package/dist/integrations/hooks/plates.cjs +7 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/memory-routing/plates.d.ts +1 -1
- package/dist/memory-routing/plates.js +1 -0
- package/docs-site/docs/plates/house.md +50 -0
- package/docs-site/docs/plates/index.md +1 -1
- package/llms.txt +2 -0
- package/package.json +1 -1
- package/scripts/foundry/inspect.mjs +47 -2
- package/scripts/node/bridge-mcp-wiring.cjs +321 -29
- package/scripts/node/consumer-gitignore.cjs +1 -0
- package/scripts/node/consumer-install-smoke.mjs +9 -38
- package/scripts/node/install-bridges.cjs +1049 -33
- package/scripts/node/mcp-launch.cjs +70 -0
- package/scripts/node/postinstall.cjs +46 -70
- package/scripts/node/unwear-cursor-hooks.cjs +21 -0
- package/scripts/node/wear-cursor-hooks.cjs +17 -0
- package/scripts/node/wear-vendored-repertoire.cjs +35 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/xray/features.json +1 -1
package/.gitignore.default
CHANGED
package/.grok-plugin/plugin.json
CHANGED
package/.xray/features.json
CHANGED
package/README.md
CHANGED
|
@@ -52,7 +52,9 @@ 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.
|
|
55
|
+
| **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
|
+
| **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
|
+
| **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. |
|
|
56
58
|
| **4.0.9** | Mill target: postinstall does not mill npm global prefix or `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. |
|
|
57
59
|
| **4.0.0** | Exo + temperament. Constitution always on; ceremony by host. Repertoire organ on (vendored 0.2). Station card survives compact/host-swap. **On npm.** [vision](docs-site/docs/architecture/v4-vision.md) · [now](docs-site/docs/architecture/v4-now.md) |
|
|
58
60
|
| **3.4.1** | Unified `install-bridges.cjs` on postinstall — OpenCode, Grok, Hermes, OpenClaw in one pass. All 7 MCPs servers via `npx -y 0xray mcp <cmd>` (no `dist/` paths). Canonical `release.mjs` pipeline. |
|
|
@@ -64,7 +66,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
|
|
|
64
66
|
|
|
65
67
|
### Consolidations
|
|
66
68
|
|
|
67
|
-
- **
|
|
69
|
+
- **Install, then wear, then setup where needed** — `npm install` runs `postinstall.cjs`, which writes nothing and prints one line: `npx 0xray wear`. `wear` and `unwear` set up or remove the Cursor suit. `npx 0xray setup` writes `.mcp.json` and the OpenCode, Grok, Hermes, and OpenClaw bridges (`install-bridges.cjs`); git hooks only with `--git-hooks`. Mill target is the consumer project, not npm global prefix or `_npx`.
|
|
68
70
|
- **7-server MCP surface** — `.mcp.json` SSOT; Grok plugin and all bridges share `XRAY_MCP_SERVERS`.
|
|
69
71
|
- **Dev vs consumer AGENTS** — `AGENTS.md` (framework) vs `AGENTS-consumer.md` (copied to consumer projects on install).
|
|
70
72
|
- **Release pipeline** — `npm run release:patch|minor|major` → reconcile → gate → artifacts → tag → publish.
|
package/dist/.gitignore.default
CHANGED
package/dist/CHANGELOG.md
CHANGED
|
@@ -41,6 +41,22 @@ 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.29] - 2026-09-28
|
|
45
|
+
|
|
46
|
+
Next patch after npm `4.0.28`. Released 2026-09-28.
|
|
47
|
+
|
|
48
|
+
`npm install` now only creates the relative `node_modules/@0xray/repertoire` link to the vendored repertoire and prints one line: `npx 0xray wear`. It no longer writes the suit. Run `npx 0xray wear` after install. Wear writes only the consumer project's `.cursor/hooks.json`, pointing at the installed package's dist hooks, and adds them beside existing user entries. It snapshots the pre-wear file under `.xray/state/cursor-hook-wear/`, and `npx 0xray unwear` restores it. `npx 0xray setup` writes `.mcp.json` and the OpenCode, Grok, Hermes, and OpenClaw bridges. Companion package `@0xray/grok-bot` is unchanged at 0.1.8.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## [4.0.28] - 2026-09-26
|
|
53
|
+
|
|
54
|
+
Next patch after npm `4.0.27`. Released 2026-09-27.
|
|
55
|
+
|
|
56
|
+
MCP servers start through `scripts/node/mcp-launch.cjs` and only see PATH, HOME, and XRAY_ROOT, plus the names on their keep list. Tokens such as NPM_TOKEN are no longer inherited. User env values stay out of argv. Postinstall keeps user edits to AGENTS.md, .mcp.json, and opencode.json. `house init` no longer copies EXAMPLE.md, and doctor FAILs while `house/EXAMPLE.md` exists. Inspect has a new machinePlugin check. The Cursor hook defaults XRAY_ROOT to the suit directory. Companion package `@0xray/grok-bot@0.1.7`.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
44
60
|
## [4.0.27] - 2026-09-25
|
|
45
61
|
|
|
46
62
|
Next patch after npm `4.0.26`. Released 2026-09-26.
|
package/dist/README.md
CHANGED
|
@@ -52,7 +52,9 @@ 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.
|
|
55
|
+
| **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
|
+
| **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
|
+
| **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. |
|
|
56
58
|
| **4.0.9** | Mill target: postinstall does not mill npm global prefix or `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. |
|
|
57
59
|
| **4.0.0** | Exo + temperament. Constitution always on; ceremony by host. Repertoire organ on (vendored 0.2). Station card survives compact/host-swap. **On npm.** [vision](docs-site/docs/architecture/v4-vision.md) · [now](docs-site/docs/architecture/v4-now.md) |
|
|
58
60
|
| **3.4.1** | Unified `install-bridges.cjs` on postinstall — OpenCode, Grok, Hermes, OpenClaw in one pass. All 7 MCPs servers via `npx -y 0xray mcp <cmd>` (no `dist/` paths). Canonical `release.mjs` pipeline. |
|
|
@@ -64,7 +66,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
|
|
|
64
66
|
|
|
65
67
|
### Consolidations
|
|
66
68
|
|
|
67
|
-
- **
|
|
69
|
+
- **Install, then wear, then setup where needed** — `npm install` runs `postinstall.cjs`, which writes nothing and prints one line: `npx 0xray wear`. `wear` and `unwear` set up or remove the Cursor suit. `npx 0xray setup` writes `.mcp.json` and the OpenCode, Grok, Hermes, and OpenClaw bridges (`install-bridges.cjs`); git hooks only with `--git-hooks`. Mill target is the consumer project, not npm global prefix or `_npx`.
|
|
68
70
|
- **7-server MCP surface** — `.mcp.json` SSOT; Grok plugin and all bridges share `XRAY_MCP_SERVERS`.
|
|
69
71
|
- **Dev vs consumer AGENTS** — `AGENTS.md` (framework) vs `AGENTS-consumer.md` (copied to consumer projects on install).
|
|
70
72
|
- **Release pipeline** — `npm run release:patch|minor|major` → reconcile → gate → artifacts → tag → publish.
|
package/dist/cli/index.js
CHANGED
|
@@ -45,52 +45,71 @@ program
|
|
|
45
45
|
.name("0xray")
|
|
46
46
|
.description("xray: Bulletproof AI orchestration with systematic error prevention")
|
|
47
47
|
.version(version);
|
|
48
|
-
function
|
|
49
|
-
const
|
|
50
|
-
validateScriptPath(
|
|
51
|
-
|
|
48
|
+
function runNodeScript(scriptName, args = []) {
|
|
49
|
+
const script = join(packageRoot, "scripts", "node", scriptName);
|
|
50
|
+
validateScriptPath(script, scriptName);
|
|
51
|
+
const quoted = [script, ...args].map((part) => `"${part}"`).join(" ");
|
|
52
|
+
execSync(`node ${quoted}`, { stdio: "inherit", cwd: process.cwd() });
|
|
52
53
|
}
|
|
53
54
|
program
|
|
54
55
|
.command("install")
|
|
55
56
|
.description("Install xray framework in the current project")
|
|
56
|
-
.action(
|
|
57
|
-
frameworkLogger.log('cli', 'install
|
|
57
|
+
.action(() => {
|
|
58
|
+
frameworkLogger.log('cli', 'install', 'info', { message: 'nothing written' });
|
|
59
|
+
process.stdout.write("nothing written\n");
|
|
60
|
+
});
|
|
61
|
+
program
|
|
62
|
+
.command("setup")
|
|
63
|
+
.description("Set up .mcp.json and the OpenCode, Grok, Hermes, and OpenClaw bridges")
|
|
64
|
+
.option("--git-hooks", "also install git hooks")
|
|
65
|
+
.action((opts) => {
|
|
66
|
+
const args = ["setup"];
|
|
67
|
+
if (opts.gitHooks)
|
|
68
|
+
args.push("--git-hooks");
|
|
58
69
|
try {
|
|
59
|
-
|
|
60
|
-
validateScriptPath(postinstallScript, "postinstall script");
|
|
61
|
-
execSync(`node "${postinstallScript}"`, { stdio: "inherit", cwd: process.cwd() });
|
|
62
|
-
frameworkLogger.log('cli', 'install-success', 'info', { message: 'xray framework installed' });
|
|
63
|
-
// UX banner kept for user visibility post-install (non-removable per exception)
|
|
64
|
-
console.log("✅ xray framework installed!");
|
|
65
|
-
console.log("💡 Run 'npx xray setup' for full configuration (hooks, Hermes, symlinks)");
|
|
70
|
+
runNodeScript("install-bridges.cjs", args);
|
|
66
71
|
}
|
|
67
72
|
catch (error) {
|
|
68
|
-
frameworkLogger.log(
|
|
69
|
-
|
|
73
|
+
frameworkLogger.log("cli", "setup-error", "error", {
|
|
74
|
+
error: error instanceof Error ? error.message : String(error),
|
|
75
|
+
});
|
|
70
76
|
process.exit(1);
|
|
71
77
|
}
|
|
72
78
|
});
|
|
73
79
|
program
|
|
74
|
-
.command("
|
|
75
|
-
.description("
|
|
76
|
-
.action(
|
|
80
|
+
.command("wear")
|
|
81
|
+
.description("Wear the 0xray suit in this git checkout")
|
|
82
|
+
.action(() => {
|
|
83
|
+
try {
|
|
84
|
+
runNodeScript("wear-cursor-hooks.cjs");
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
frameworkLogger.log('cli', 'wear-error', 'error', {
|
|
88
|
+
error: error instanceof Error ? error.message : String(error),
|
|
89
|
+
});
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
77
93
|
program
|
|
78
|
-
.command("
|
|
79
|
-
.description("
|
|
80
|
-
.action(
|
|
81
|
-
console.log("🚀 xray CLI: Initializing configuration...");
|
|
94
|
+
.command("unwear")
|
|
95
|
+
.description("Remove the 0xray suit and restore the pre-wear hooks file")
|
|
96
|
+
.action(() => {
|
|
82
97
|
try {
|
|
83
|
-
|
|
84
|
-
validateScriptPath(postinstallScript, "postinstall script");
|
|
85
|
-
execSync(`node "${postinstallScript}"`, { stdio: "inherit", cwd: process.cwd() });
|
|
86
|
-
runSetup();
|
|
87
|
-
console.log("✅ xray configuration initialized!");
|
|
98
|
+
runNodeScript("unwear-cursor-hooks.cjs");
|
|
88
99
|
}
|
|
89
100
|
catch (error) {
|
|
90
|
-
|
|
101
|
+
frameworkLogger.log('cli', 'unwear-error', 'error', {
|
|
102
|
+
error: error instanceof Error ? error.message : String(error),
|
|
103
|
+
});
|
|
91
104
|
process.exit(1);
|
|
92
105
|
}
|
|
93
106
|
});
|
|
107
|
+
program
|
|
108
|
+
.command("init")
|
|
109
|
+
.description("Initialize xray configuration in the current project")
|
|
110
|
+
.action(() => {
|
|
111
|
+
process.stdout.write("nothing written\n");
|
|
112
|
+
});
|
|
94
113
|
program
|
|
95
114
|
.command("status")
|
|
96
115
|
.description("Show comprehensive xray framework status")
|
|
@@ -341,22 +360,7 @@ program
|
|
|
341
360
|
console.log("===========================");
|
|
342
361
|
console.log("");
|
|
343
362
|
try {
|
|
344
|
-
|
|
345
|
-
// Run the postinstaller script (same as install command)
|
|
346
|
-
const postinstallScript = join(packageRoot, "scripts", "node", "postinstall.cjs");
|
|
347
|
-
// SECURITY: Validate script path before execution
|
|
348
|
-
validateScriptPath(postinstallScript, "postinstall script");
|
|
349
|
-
execSync(`node "${postinstallScript}"`, {
|
|
350
|
-
stdio: "inherit",
|
|
351
|
-
cwd: process.cwd(),
|
|
352
|
-
});
|
|
353
|
-
console.log("");
|
|
354
|
-
console.log("🎉 Framework configuration restored successfully!");
|
|
355
|
-
console.log("");
|
|
356
|
-
console.log("💡 Next steps:");
|
|
357
|
-
console.log(" • Restart OpenCode to load the restored configuration");
|
|
358
|
-
console.log(" • Run: npx xray health (to verify everything works)");
|
|
359
|
-
console.log(" • Try: @security-auditor scan this project");
|
|
363
|
+
process.stdout.write("nothing written\n");
|
|
360
364
|
}
|
|
361
365
|
catch (error) {
|
|
362
366
|
console.error("❌ Fix command failed:", error instanceof Error ? error.message : String(error));
|
|
@@ -451,6 +455,10 @@ program
|
|
|
451
455
|
}
|
|
452
456
|
// Check configuration - check for opencode.json or .xray/ (min compat .xray/ fallback for prior 0xRay consumer runtime per Scope Rule; plain xray primary)
|
|
453
457
|
const cwd = process.cwd();
|
|
458
|
+
const wearMeta = path.join(cwd, ".xray", "state", "cursor-hook-wear", "meta.json");
|
|
459
|
+
if (!fs.existsSync(wearMeta)) {
|
|
460
|
+
process.stdout.write("not worn\n");
|
|
461
|
+
}
|
|
454
462
|
const opencodeConfigPath = path.join(cwd, "opencode.json");
|
|
455
463
|
const xrayDir = getConfigDir(cwd);
|
|
456
464
|
const opencodeExists = fs.existsSync(opencodeConfigPath);
|
|
@@ -10,10 +10,25 @@ Repertoire is preferred (vendored, dest = named laws). Station + Codex gates sti
|
|
|
10
10
|
2. Cursor Cloud Agent clones the repo and loads **project** hooks. Desktop Agent Chat does the same when the folder is the workspace.
|
|
11
11
|
3. Hook names are camelCase: `preToolUse`, `preCompact`, `afterFileEdit`, plus Cloud `beforeShellExecution` / `beforeReadFile`. Command is a **relative** `.cursor/hooks/*.sh` — Cloud execs argv[0] without a shell. Do not put `XRAY_AI_PATH=` in `hooks.json`. Stdin is JSON; stdout is JSON.
|
|
12
12
|
4. First `preToolUse` or `afterFileEdit` writes `.xray/state/session-boot.json` + `.xray/state/STATION.md`. After a compact, **Read STATION.md**. The host does not inject it. A multi-repo Cloud wrapper (`/agent` with `repos/xray`) is not a dest heat root, even if a leftover wrapper card exists. Heat the mill under `repos/` and the Read path. Dest `EACCES` fail-opens — a wired hook must not deny every tool.
|
|
13
|
-
5. `install-bridges`
|
|
13
|
+
5. When the package has no dist hook scripts yet, `install-bridges` fastens the daemon workspace root if it can see `repos/xray` above the checkout. A consumer install that already has dist scripts writes only that consumer project directory. `ReloadAgentSkills` still runs so a mid-session wear can bind this daemon. Dogfood commands stay a relative `.cursor/hooks/*.sh`.
|
|
14
14
|
6. `preCompact` is observational (cannot block). Cloud **does** fire it ([hooks.md](https://cursor.com/docs/hooks.md) support matrix: Yes) once hooks are bound and the host actually compacts. Stdout is only `{ "user_message": "…" }` — that is a notice, not a spawn. The spawn id is stdin `conversation_id` (same `bc-`) plus Task's returned agent id. Resume that id. Do not cold-start a twin. Station merge keeps ticket / seed / Durable / unfinished keys.
|
|
15
15
|
|
|
16
|
-
Copy the consumer template from `src/integrations/cursor/hooks/hooks.json` and the sibling `.sh` runners.
|
|
16
|
+
Copy the consumer template from `src/integrations/cursor/hooks/hooks.json` and the sibling `.sh` runners. This exo repo's own `.cursor/hooks.json` stays on `.cursor/hooks/*.sh` so dogfood can run `src/integrations/cursor/hooks/*.js` before `npm run build`.
|
|
17
|
+
|
|
18
|
+
Consumer wear (`installCursorBridge` / `wearCursorHooks`, including `npm run wear` in a suited bench) writes only that consumer project's `.cursor/hooks.json`. It does not rewrite a parent checkout's committed hooks, `CURSOR_PROJECT_DIR`, or a `repos/xray` directory above the project. Those outer paths are written only when `wearCursorHooks` is called with `{ outerRoots: true }`, and each one is printed as `cursor-wear: wrote outer hooks at <path>`. The five shipped events (`preToolUse`, `preCompact`, `afterFileEdit`, `beforeShellExecution`, `beforeReadFile`) are added beside existing user entries, unless that event already runs `xray-cloud-hook.sh` (the committed `.cursor/hooks/*.sh` runners). A suited bench that already commits those runners is left byte for byte. The new command, when one is added, is a relative path to the installed package:
|
|
19
|
+
|
|
20
|
+
`node_modules/0xray/dist/integrations/cursor/hooks/<event>.sh`
|
|
21
|
+
|
|
22
|
+
Wear does not copy scripts into `.cursor/hooks/`. A user's `.cursor/hooks/<name>.sh` stays as it is, including when the name matches a shipped script, and wear adds the dist command beside it. A `hooks.json` that contains `//` comments is merged in place. A duplicate `hooks` key, or any other file that cannot be parsed safely, makes wear stop and write nothing.
|
|
23
|
+
|
|
24
|
+
Install the package first (`npm install`), then `npx 0xray wear`. Postinstall writes nothing. Wearing again writes the same bytes and takes a fresh snapshot every time. The pre-wear copy is `<project>/.xray/state/cursor-hook-wear/` (gitignored, and left out of the npm package), so removing `node_modules` does not delete it. When wear creates that folder and the path is not already ignored, it appends the path to `$GIT_DIR/info/exclude`. Wear stores the user bytes, never an already-worn `hooks.json`. Restore with `npx 0xray unwear` (or `node node_modules/0xray/scripts/node/unwear-cursor-hooks.cjs`). Unwear prints `restored` only when the file bytes match that snapshot exactly. If the file changed or cannot be parsed, unwear exits non-zero, says what differs, and leaves the snapshot in place. Wear refuses, and writes nothing, when git is missing, the directory is not a work tree, `GIT_DIR` is bare, or `hooks.json` cannot be parsed.
|
|
25
|
+
|
|
26
|
+
`xray-cloud-hook.sh` resolution order (first file that exists wins). Each run appends one `cursor-hook-invoke.log` line with `js=` set to the absolute path it executes:
|
|
27
|
+
|
|
28
|
+
1. Consumer `node_modules/0xray/dist/integrations/cursor/hooks/${JS}`, walking upward from the script directory, then from cwd. A directory whose `package.json` name is `0xray` is skipped, so a factory checkout does not prefer its own `node_modules` or a nested example over `src/`.
|
|
29
|
+
2. Sibling `${JS}` when the runner itself lives under `node_modules/0xray`.
|
|
30
|
+
3. `$XRAY_AI_PATH` `src/` then `dist/` (explicit mill).
|
|
31
|
+
4. Dogfood `src/` at cwd, `../xray`, `repos/xray`, and `$CURSOR_PROJECT_DIR/repos/xray`, then dist at cwd, then `cwd/node_modules/0xray`.
|
|
17
32
|
|
|
18
33
|
## Contracts
|
|
19
34
|
|
|
@@ -64,3 +79,7 @@ echo '{"hook_event_name":"preCompact","trigger":"auto","context_tokens":1}' \
|
|
|
64
79
|
```
|
|
65
80
|
|
|
66
81
|
Path C seed + receipt: `examples/cursor-cloud-compact/`. Suited Arm S (real usage, no FILL): `examples/killer-dual/`.
|
|
82
|
+
|
|
83
|
+
## Known limits
|
|
84
|
+
|
|
85
|
+
`findLocalExecDaemon` reads the local exec-daemon auth token from `/proc/<pid>/cmdline` (`scripts/node/install-bridges.cjs:927`–`:935`). That read needs a separate security review. Wear does not change it.
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
# Cloud-safe Cursor hook runner. Command in hooks.json must be a relative path.
|
|
3
3
|
# Do not put env-assignment in hooks.json — Cloud execs argv[0] without a shell.
|
|
4
|
+
#
|
|
5
|
+
# Resolution order (first existing file wins):
|
|
6
|
+
# 1. Consumer install. Walk upward from this script's directory, then from cwd.
|
|
7
|
+
# Use node_modules/0xray/dist/integrations/cursor/hooks/${JS}.
|
|
8
|
+
# Skip a directory whose package.json "name" is "0xray" (the factory repo).
|
|
9
|
+
# That keeps dogfood on src/ and prefers a consumer install over a parent src/.
|
|
10
|
+
# 2. Sibling ${JS} when this runner lives under node_modules/0xray (installed dist).
|
|
11
|
+
# 3. XRAY_AI_PATH, if set: src then dist (explicit mill, dogfood path shape).
|
|
12
|
+
# 4. Dogfood repo source: cwd/src, cwd/../xray/src, cwd/repos/xray/src,
|
|
13
|
+
# ${CURSOR_PROJECT_DIR}/repos/xray/src, then those roots' dist/, then
|
|
14
|
+
# cwd/node_modules/0xray (dist then src).
|
|
15
|
+
# Consumer wear points hooks.json at the installed dist *.sh so step 1/2 run
|
|
16
|
+
# even when Cursor's cwd is a parent factory checkout.
|
|
4
17
|
set -eu
|
|
5
18
|
|
|
6
19
|
EVENT="${1:-preToolUse}"
|
|
@@ -11,7 +24,7 @@ REL=""
|
|
|
11
24
|
pick_mill() {
|
|
12
25
|
mill="$1"
|
|
13
26
|
rel="$2"
|
|
14
|
-
if [ -f "${mill}/${rel}" ]; then
|
|
27
|
+
if [ -n "$mill" ] && [ -f "${mill}/${rel}" ]; then
|
|
15
28
|
MILL="$mill"
|
|
16
29
|
REL="$rel"
|
|
17
30
|
return 0
|
|
@@ -19,15 +32,54 @@ pick_mill() {
|
|
|
19
32
|
return 1
|
|
20
33
|
}
|
|
21
34
|
|
|
22
|
-
|
|
35
|
+
is_xray_package() {
|
|
36
|
+
pkg="$1/package.json"
|
|
37
|
+
[ -f "$pkg" ] || return 1
|
|
38
|
+
grep -q '"name"[[:space:]]*:[[:space:]]*"0xray"' "$pkg" 2>/dev/null || return 1
|
|
39
|
+
return 0
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
pick_consumer_from() {
|
|
43
|
+
dir="$1"
|
|
44
|
+
[ -n "$dir" ] || return 1
|
|
45
|
+
while [ -n "$dir" ]; do
|
|
46
|
+
if ! is_xray_package "$dir"; then
|
|
47
|
+
if pick_mill "$dir/node_modules/0xray" "dist/integrations/cursor/hooks/${JS}"; then
|
|
48
|
+
return 0
|
|
49
|
+
fi
|
|
50
|
+
fi
|
|
51
|
+
parent="$(dirname -- "$dir")"
|
|
52
|
+
if [ "$parent" = "$dir" ]; then
|
|
53
|
+
break
|
|
54
|
+
fi
|
|
55
|
+
dir="$parent"
|
|
56
|
+
done
|
|
57
|
+
return 1
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
HERE="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
61
|
+
|
|
62
|
+
pick_consumer_from "$HERE" || pick_consumer_from "$(pwd)" || true
|
|
63
|
+
|
|
64
|
+
if [ -z "$MILL" ]; then
|
|
65
|
+
case "$HERE" in
|
|
66
|
+
*/node_modules/0xray/*)
|
|
67
|
+
pick_mill "$HERE" "${JS}" || true
|
|
68
|
+
;;
|
|
69
|
+
esac
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
if [ -z "$MILL" ] && [ -n "${XRAY_AI_PATH:-}" ]; then
|
|
23
73
|
pick_mill "${XRAY_AI_PATH}" "src/integrations/cursor/hooks/${JS}" || \
|
|
24
74
|
pick_mill "${XRAY_AI_PATH}" "dist/integrations/cursor/hooks/${JS}" || true
|
|
25
75
|
fi
|
|
76
|
+
|
|
26
77
|
if [ -z "$MILL" ]; then
|
|
27
78
|
pick_mill "$(pwd)" "src/integrations/cursor/hooks/${JS}" || \
|
|
28
79
|
pick_mill "$(pwd)/../xray" "src/integrations/cursor/hooks/${JS}" || \
|
|
29
80
|
pick_mill "$(pwd)/repos/xray" "src/integrations/cursor/hooks/${JS}" || \
|
|
30
81
|
pick_mill "${CURSOR_PROJECT_DIR:-}/repos/xray" "src/integrations/cursor/hooks/${JS}" || \
|
|
82
|
+
pick_mill "$(pwd)" "dist/integrations/cursor/hooks/${JS}" || \
|
|
31
83
|
pick_mill "$(pwd)/node_modules/0xray" "dist/integrations/cursor/hooks/${JS}" || \
|
|
32
84
|
pick_mill "$(pwd)/node_modules/0xray" "src/integrations/cursor/hooks/${JS}" || true
|
|
33
85
|
fi
|
|
@@ -36,14 +88,19 @@ if [ -n "$MILL" ] && [ -d "$MILL" ]; then
|
|
|
36
88
|
MILL="$(cd "$MILL" && pwd)"
|
|
37
89
|
fi
|
|
38
90
|
|
|
91
|
+
JS_ABS=""
|
|
92
|
+
if [ -n "$MILL" ] && [ -n "$REL" ] && [ -f "${MILL}/${REL}" ]; then
|
|
93
|
+
JS_ABS="$(CDPATH= cd -- "$(dirname -- "${MILL}/${REL}")" && pwd)/$(basename -- "${REL}")"
|
|
94
|
+
fi
|
|
95
|
+
|
|
39
96
|
NODE_BIN="$(command -v node 2>/dev/null || true)"
|
|
40
97
|
|
|
41
98
|
log_invoke() {
|
|
42
99
|
dest="$1"
|
|
43
100
|
mkdir -p "${dest}/.xray/state" 2>/dev/null || true
|
|
44
101
|
{
|
|
45
|
-
printf 'ts=%s event=%s cwd=%s mill=%s node=%s\n' \
|
|
46
|
-
"$(date -Iseconds)" "$EVENT" "$(pwd)" "${MILL:-MISSING}" "${NODE_BIN:-MISSING}"
|
|
102
|
+
printf 'ts=%s event=%s cwd=%s mill=%s node=%s js=%s\n' \
|
|
103
|
+
"$(date -Iseconds)" "$EVENT" "$(pwd)" "${MILL:-MISSING}" "${NODE_BIN:-MISSING}" "${JS_ABS:-MISSING}"
|
|
47
104
|
} >> "${dest}/.xray/state/cursor-hook-invoke.log" 2>/dev/null || true
|
|
48
105
|
}
|
|
49
106
|
|
|
@@ -59,5 +116,5 @@ fi
|
|
|
59
116
|
|
|
60
117
|
export XRAY_HOOK_EVENT="$EVENT"
|
|
61
118
|
export XRAY_AI_PATH="$MILL"
|
|
62
|
-
export XRAY_ROOT="$
|
|
119
|
+
export XRAY_ROOT="${XRAY_ROOT:-$(pwd)}"
|
|
63
120
|
exec "$NODE_BIN" "${MILL}/${REL}"
|
|
@@ -14,6 +14,7 @@ const PLATE_IDS = Object.freeze([
|
|
|
14
14
|
"processor",
|
|
15
15
|
"reporting",
|
|
16
16
|
"memory-recall",
|
|
17
|
+
"house",
|
|
17
18
|
]);
|
|
18
19
|
|
|
19
20
|
/** Id token, then extra phrases. Equal top scores recall nothing. */
|
|
@@ -61,6 +62,12 @@ const CUES = {
|
|
|
61
62
|
[/recall(?:s|ed|ing)?\s+(?:a\s+|one\s+|the\s+)?plate/i, 5],
|
|
62
63
|
[/stamp(?:ed|ing)?\s+plates?/i, 4],
|
|
63
64
|
],
|
|
65
|
+
house: [
|
|
66
|
+
[/house init/i, 4],
|
|
67
|
+
[/HOUSE\.md/i, 4],
|
|
68
|
+
[/GROK_BOT_HOUSE/i, 4],
|
|
69
|
+
[/setup-house/i, 4],
|
|
70
|
+
],
|
|
64
71
|
};
|
|
65
72
|
|
|
66
73
|
function platesDir() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const PLATE_IDS: readonly ["routing", "governance", "boot", "orchestration", "processor", "reporting", "memory-recall"];
|
|
1
|
+
export declare const PLATE_IDS: readonly ["routing", "governance", "boot", "orchestration", "processor", "reporting", "memory-recall", "house"];
|
|
2
2
|
export type PlateId = (typeof PLATE_IDS)[number];
|
|
3
3
|
export interface PlateStamp {
|
|
4
4
|
id: PlateId;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: House
|
|
3
|
+
sidebar_label: House
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# House
|
|
7
|
+
|
|
8
|
+
One team, one folder. `grok-bot house init` copies `HOUSE.md`, `WAVEBOARD.md`, and `ATTENTION_STATE.md` into `./house`. It does not copy `EXAMPLE.md`. It refuses when a target file is already there. Doctor reads `HOUSE.md` through `GROK_BOT_HOUSE`, or by walking up when that variable is unset, and FAILs with `house/EXAMPLE.md exists — delete it` when that file is present. A wake reads the station, then the board files in `house/`.
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
12
|
+
│ INPUT LAYER │
|
|
13
|
+
│ │
|
|
14
|
+
│ npx @0xray/grok-bot house init │
|
|
15
|
+
│ copies HOUSE.md, WAVEBOARD.md, ATTENTION_STATE.md only │
|
|
16
|
+
│ refuses if a target file is already there │
|
|
17
|
+
└──────────────────────────────┬───────────────────────────────┘
|
|
18
|
+
v
|
|
19
|
+
┌──────────────────────────────┼───────────────────────────────┐
|
|
20
|
+
│ PROCESSING LAYER v │
|
|
21
|
+
│ │
|
|
22
|
+
│ ┌──────────────────────────────────────────────────────┐ │
|
|
23
|
+
│ │ HOUSE.md — six headings │ │
|
|
24
|
+
│ │ owner · seats · public voice · allowed · ask first │ │
|
|
25
|
+
│ │ board: WAVEBOARD.md + ATTENTION_STATE.md │ │
|
|
26
|
+
│ │ the owner approves Allowed before it counts │ │
|
|
27
|
+
│ └───────────────────────────┬──────────────────────────┘ │
|
|
28
|
+
│ v │
|
|
29
|
+
│ ┌──────────────────────────────────────────────────────┐ │
|
|
30
|
+
│ │ grok-bot doctor │ │
|
|
31
|
+
│ │ GROK_BOT_HOUSE, or walk up for house/HOUSE.md │ │
|
|
32
|
+
│ │ a set path that is missing warns and does not walk │ │
|
|
33
|
+
│ │ a line that starts with (example) fails │ │
|
|
34
|
+
│ │ house/EXAMPLE.md exists — delete it │ │
|
|
35
|
+
│ └───────────────────────────┬──────────────────────────┘ │
|
|
36
|
+
└──────────────────────────────┼───────────────────────────────┘
|
|
37
|
+
v
|
|
38
|
+
┌──────────────────────────────┼───────────────────────────────┐
|
|
39
|
+
│ OUTPUT LAYER v │
|
|
40
|
+
│ │
|
|
41
|
+
│ read the station, then house/WAVEBOARD.md │
|
|
42
|
+
│ and house/ATTENTION_STATE.md │
|
|
43
|
+
│ a missing board file uses templates/house/ │
|
|
44
|
+
│ one card, one owner │
|
|
45
|
+
│ change the house when the owner says a rule twice │
|
|
46
|
+
└──────────────────────────────────────────────────────────────┘
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
stamped · 0xray · @0xray/grok-bot 0.1.7
|
|
@@ -13,4 +13,4 @@ The station card stays the short subsystem table. That table is the index still
|
|
|
13
13
|
|
|
14
14
|
The markdown file is the source of truth for that stamp. When the pipeline changes, edit the plate. A worn project may hold a copy at `.xray/state/plates/<id>.md`. The copy is written only when that file is missing, so a local edit stays.
|
|
15
15
|
|
|
16
|
-
[Routing](./routing.md) · [Governance](./governance.md) · [Boot](./boot.md) · [Orchestration](./orchestration.md) · [Processor](./processor.md) · [Reporting](./reporting.md) · [Memory recall](./memory-recall.md)
|
|
16
|
+
[Routing](./routing.md) · [Governance](./governance.md) · [Boot](./boot.md) · [Orchestration](./orchestration.md) · [Processor](./processor.md) · [Reporting](./reporting.md) · [Memory recall](./memory-recall.md) · [House](./house.md)
|
package/llms.txt
CHANGED
|
@@ -12,6 +12,8 @@ Default consumer wear is **mill plant** (`mill` + `inspect`), not a 45-skill / 4
|
|
|
12
12
|
- Memory scoring rules: [docs/memory-scoring.md](docs/memory-scoring.md). The orchestrator links that file. It does not copy the rules.
|
|
13
13
|
- Host `preCompact` writes the hook line and per-session receipt on the suit mill and on nested consumer wear roots (a bench with local `node_modules/0xray`). A counted cut needs a non-empty generation id and a numeric usage percent.
|
|
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
|
+
- 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
|
+
- `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.
|
|
15
17
|
|
|
16
18
|
- `npx @0xray/foundry mint --skip-live` — re-fasten mill plant, then inspect.
|
|
17
19
|
- `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
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Mill inspect organ. Runs the
|
|
3
|
+
* Mill inspect organ. Runs the plant checks, a machinePlugin check, and observational harness.
|
|
4
4
|
* Not an 8th MCP. Not PPE. Does not fasten hooks or Repertoire.
|
|
5
5
|
*
|
|
6
6
|
* npx @0xray/foundry inspect [--skip-live] [--go] [--go-out PATH]
|
|
@@ -515,7 +515,7 @@ export function packagesToProbe(root) {
|
|
|
515
515
|
});
|
|
516
516
|
}
|
|
517
517
|
|
|
518
|
-
function checkIsolatedHome(root, env = process.env, machine = mint.machineHome()) {
|
|
518
|
+
export function checkIsolatedHome(root, env = process.env, machine = mint.machineHome()) {
|
|
519
519
|
const isolated = isIsolatedHome(env, machine);
|
|
520
520
|
const machinePlugin = machineGrokPluginDir(machine);
|
|
521
521
|
const dests = mint.resolveGrokPluginDests(root, env, machine);
|
|
@@ -542,6 +542,50 @@ function checkIsolatedHome(root, env = process.env, machine = mint.machineHome()
|
|
|
542
542
|
};
|
|
543
543
|
}
|
|
544
544
|
|
|
545
|
+
function isXrayPluginName(name) {
|
|
546
|
+
return name === "0xray" || name.startsWith("0xray");
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/** 0xray plugin dirs under the machine HOME's grok plugin folder. */
|
|
550
|
+
export function machineXrayPluginPaths(machine = mint.machineHome()) {
|
|
551
|
+
const pluginsDir = path.join(machine, ".grok", "plugins");
|
|
552
|
+
if (!fs.existsSync(pluginsDir)) return [];
|
|
553
|
+
let names;
|
|
554
|
+
try {
|
|
555
|
+
names = fs.readdirSync(pluginsDir);
|
|
556
|
+
} catch {
|
|
557
|
+
return [];
|
|
558
|
+
}
|
|
559
|
+
return names
|
|
560
|
+
.filter((name) => isXrayPluginName(name))
|
|
561
|
+
.sort()
|
|
562
|
+
.map((name) => path.join(pluginsDir, name));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* `isolated` stays HOME != machine home. This check is whether a machine-level
|
|
567
|
+
* 0xray Grok plugin exists. Overall inspect ok is false when this check fails.
|
|
568
|
+
*/
|
|
569
|
+
export function checkMachinePlugin(machine = mint.machineHome()) {
|
|
570
|
+
const machinePlugin = machineGrokPluginDir(machine);
|
|
571
|
+
const hits = machineXrayPluginPaths(machine);
|
|
572
|
+
if (hits.length > 0) {
|
|
573
|
+
return {
|
|
574
|
+
id: "machinePlugin",
|
|
575
|
+
ok: false,
|
|
576
|
+
machinePlugin,
|
|
577
|
+
hits,
|
|
578
|
+
detail: `machine-level ${hits.join(", ")} exists — delete it`,
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
return {
|
|
582
|
+
id: "machinePlugin",
|
|
583
|
+
ok: true,
|
|
584
|
+
machinePlugin,
|
|
585
|
+
hits: [],
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
|
|
545
589
|
export async function inspectSuit(root, opts = {}) {
|
|
546
590
|
const millRoot = opts.millRoot || millPackageDir();
|
|
547
591
|
const fetchFn = opts.fetch || fetch;
|
|
@@ -584,6 +628,7 @@ export async function inspectSuit(root, opts = {}) {
|
|
|
584
628
|
}
|
|
585
629
|
|
|
586
630
|
checks.push(checkIsolatedHome(root, env, machineHome));
|
|
631
|
+
checks.push(checkMachinePlugin(machineHome));
|
|
587
632
|
checks.push(checkHarness(root, requireHarness));
|
|
588
633
|
|
|
589
634
|
const failed = checks.filter((c) => c.ok === false);
|