0xray 4.0.10 → 4.0.12
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/.grok-plugin/plugin.json +20 -0
- package/.xray/features.json +1 -1
- package/AGENTS-consumer.md +1 -1
- package/AGENTS.md +1 -1
- package/README.md +2 -2
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +1 -1
- package/dist/CHANGELOG.md +19 -0
- package/dist/README.md +2 -2
- package/dist/SKILLS.md +1 -1
- package/dist/governance/llm-governance-provider.js +20 -4
- package/dist/integrations/grok/grok-cli.d.ts +3 -0
- package/dist/integrations/grok/grok-cli.js +79 -73
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/llms.txt +1 -1
- package/package.json +3 -2
- package/scripts/foundry/CHANGELOG.md +1 -1
- package/scripts/foundry/README.md +2 -2
- package/scripts/foundry/inspect.mjs +22 -6
- package/scripts/foundry/mint-suit.cjs +24 -0
- package/scripts/foundry/plant/skills/inspect/SKILL.md +1 -1
- package/scripts/node/install-bridges.cjs +39 -24
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/xray/features.json +1 -1
- package/.opencode/agents/api-design.yml +0 -31
- package/.opencode/agents/architect.yml +0 -15
- package/.opencode/agents/architecture-patterns.yml +0 -14
- package/.opencode/agents/auto-format.yml +0 -14
- package/.opencode/agents/backend-engineer.yml +0 -12
- package/.opencode/agents/boot-orchestrator.yml +0 -14
- package/.opencode/agents/bug-triage-specialist.yml +0 -15
- package/.opencode/agents/code-analyzer.yml +0 -12
- package/.opencode/agents/code-reviewer.yml +0 -14
- package/.opencode/agents/content-creator.yml +0 -12
- package/.opencode/agents/database-engineer.yml +0 -12
- package/.opencode/agents/devops-engineer.yml +0 -12
- package/.opencode/agents/framework-compliance-audit.yml +0 -14
- package/.opencode/agents/frontend-engineer.yml +0 -12
- package/.opencode/agents/frontend-ui-ux-engineer.yml +0 -12
- package/.opencode/agents/git-workflow.yml +0 -15
- package/.opencode/agents/growth-strategist.yml +0 -12
- package/.opencode/agents/hermes-agent.yml +0 -12
- package/.opencode/agents/inference-improve.yml +0 -12
- package/.opencode/agents/lint.yml +0 -14
- package/.opencode/agents/log-monitor.yml +0 -12
- package/.opencode/agents/mobile-developer.yml +0 -12
- package/.opencode/agents/model-health-check.yml +0 -12
- package/.opencode/agents/multimodal-looker.yml +0 -12
- package/.opencode/agents/performance-analysis.yml +0 -12
- package/.opencode/agents/performance-engineer.yml +0 -12
- package/.opencode/agents/performance-optimization.yml +0 -12
- package/.opencode/agents/processor-pipeline.yml +0 -14
- package/.opencode/agents/project-analysis.yml +0 -12
- package/.opencode/agents/refactorer.yml +0 -12
- package/.opencode/agents/researcher.yml +0 -12
- package/.opencode/agents/security-auditor.yml +0 -12
- package/.opencode/agents/security-scan.yml +0 -12
- package/.opencode/agents/seo-consultant.yml +0 -12
- package/.opencode/agents/session-management.yml +0 -12
- package/.opencode/agents/state-manager.yml +0 -12
- package/.opencode/agents/storyteller.yml +0 -12
- package/.opencode/agents/strategist.yml +0 -12
- package/.opencode/agents/tech-writer.yml +0 -12
- package/.opencode/agents/testing-best-practices.yml +0 -12
- package/.opencode/agents/testing-lead.yml +0 -12
- package/.opencode/agents/ui-ux-design.yml +0 -12
- package/.opencode/codex.codex +0 -8
- package/.opencode/commands/auto-format.md +0 -99
- package/.opencode/commands/auto-summary-capture.md +0 -90
- package/.opencode/commands/dependency-audit.md +0 -184
- package/.opencode/commands/enforcer-daily-scan.md +0 -137
- package/.opencode/commands/framework-compliance-audit.md +0 -205
- package/.opencode/commands/interactive-validator.md +0 -75
- package/.opencode/commands/job-summary-logger.md +0 -68
- package/.opencode/commands/lint.md +0 -11
- package/.opencode/commands/mode-switch.md +0 -95
- package/.opencode/commands/model-health-check.md +0 -186
- package/.opencode/commands/performance-analysis.md +0 -144
- package/.opencode/commands/pre-commit-introspection.md +0 -185
- package/.opencode/commands/pre-commit-introspection.sh +0 -133
- package/.opencode/commands/security-scan.md +0 -157
- package/.opencode/commands/sisyphus-validation.md +0 -128
- package/.opencode/commands/summary-logger.md +0 -83
- package/.opencode/enforcer-config.json +0 -282
- package/.opencode/workflows/post-deployment-audit.yml +0 -123
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "0xray",
|
|
3
|
+
"version": "4.0.12",
|
|
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
|
+
"author": {
|
|
6
|
+
"name": "0xRay AI",
|
|
7
|
+
"url": "https://0xray.ai"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/0xRayAI/xray",
|
|
10
|
+
"repository": "https://github.com/0xRayAI/xray",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"0xray",
|
|
13
|
+
"mill",
|
|
14
|
+
"inspect",
|
|
15
|
+
"codex",
|
|
16
|
+
"mcp",
|
|
17
|
+
"suit"
|
|
18
|
+
],
|
|
19
|
+
"mcpServers": ".mcp.json"
|
|
20
|
+
}
|
package/.xray/features.json
CHANGED
package/AGENTS-consumer.md
CHANGED
|
@@ -51,7 +51,7 @@ Governance deliberation uses **code-review**, **security-audit** (via enforcer/s
|
|
|
51
51
|
| `npx 0xray setup` | Symlinks, hook extras, Hermes skill sync |
|
|
52
52
|
| `npx 0xray status` | Verify installation |
|
|
53
53
|
| `npx 0xray opencode install` | OpenCode bridge (also runs on postinstall) |
|
|
54
|
-
| `npx 0xray grok install` |
|
|
54
|
+
| `npx 0xray grok install` | Project `.grok/plugins/0xray` + 7 MCPs servers (machine plugin not last-wins) |
|
|
55
55
|
| `npx 0xray hermes install` | Hermes plugin bridge |
|
|
56
56
|
| `npx 0xray openclaw install` | OpenClaw config + skills |
|
|
57
57
|
| `npx 0xray skill:install` | Install starter skills |
|
package/AGENTS.md
CHANGED
|
@@ -47,7 +47,7 @@ Governance deliberation: **code-review**, **security-audit**, **researcher** wit
|
|
|
47
47
|
3. `.gitignore.default` → `.gitignore` (if absent)
|
|
48
48
|
4. `.xray/` config (`codex.json`, `features.json`, `config.json`) then overlay their plant
|
|
49
49
|
5. `.mcp.json` (7 servers)
|
|
50
|
-
6. Four bridges: OpenCode, Grok, Hermes, OpenClaw
|
|
50
|
+
6. Four bridges: OpenCode, Grok, Hermes, OpenClaw. Grok last-mile dest is project `.grok/plugins/0xray` (shared HOME does not last-wins clobber machine `~/.grok/plugins/0xray`)
|
|
51
51
|
7. Optional git hooks
|
|
52
52
|
|
|
53
53
|
**Shop plant:** `shop-extract`, `shop-witness`, `shop-pin` (groover-hangar) are first-class with mill plant. Extra shops: `foundry.json` `shopPlant`. Not `"costume": true`. `npx @0xray/foundry inspect --skip-live` is the receipt.
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Manual per-platform install (idempotent, same result as postinstall):
|
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
npx 0xray opencode install
|
|
38
|
-
npx 0xray grok install # 7 MCPs servers +
|
|
38
|
+
npx 0xray grok install # 7 MCPs servers + project .grok/plugins/0xray (not machine last-wins)
|
|
39
39
|
npx 0xray hermes install
|
|
40
40
|
npx 0xray openclaw install
|
|
41
41
|
npx 0xray skill:install # starter skills
|
|
@@ -185,7 +185,7 @@ Docs: [memory routing](docs-site/docs/guides/memory-routing.md) · [Repertoire](
|
|
|
185
185
|
| Platform | Install | Postinstall behavior |
|
|
186
186
|
|----------|---------|----------------------|
|
|
187
187
|
| **OpenCode** | `npx 0xray opencode install` | Merges `opencode.json`, copies agent YML surfaces |
|
|
188
|
-
| **Grok CLI / Build** | `npx 0xray grok install` |
|
|
188
|
+
| **Grok CLI / Build** | `npx 0xray grok install` | Project `.grok/plugins/0xray` (shared HOME does not clobber machine plugin), 7 MCPs servers |
|
|
189
189
|
| **Hermes Agent** | `npx 0xray hermes install` | `~/.hermes/plugins/xray-hermes`, consumer root marker |
|
|
190
190
|
| **OpenClaw** | `npx 0xray openclaw install` | `.xray/config/openclaw.json`, skill sync |
|
|
191
191
|
|
package/SKILLS.md
CHANGED
|
@@ -148,7 +148,7 @@ npx 0xray skill:install <source>
|
|
|
148
148
|
| Source (framework) | `src/skills/<name>/SKILL.md` |
|
|
149
149
|
| Published package | `node_modules/0xray/dist/skills/<name>/SKILL.md` |
|
|
150
150
|
| OpenCode (after setup) | `.opencode/skills/<name>/SKILL.md` |
|
|
151
|
-
| Grok |
|
|
151
|
+
| Grok | project `.grok/plugins/0xray/skills/<name>/SKILL.md` (machine `~/.grok/plugins/0xray` is not last-wins) |
|
|
152
152
|
| Hermes / OpenClaw | Platform skill dirs (postinstall sync) |
|
|
153
153
|
|
|
154
154
|
## Related features (since 3.1)
|
package/dist/AGENTS.md
CHANGED
|
@@ -47,7 +47,7 @@ Governance deliberation: **code-review**, **security-audit**, **researcher** wit
|
|
|
47
47
|
3. `.gitignore.default` → `.gitignore` (if absent)
|
|
48
48
|
4. `.xray/` config (`codex.json`, `features.json`, `config.json`) then overlay their plant
|
|
49
49
|
5. `.mcp.json` (7 servers)
|
|
50
|
-
6. Four bridges: OpenCode, Grok, Hermes, OpenClaw
|
|
50
|
+
6. Four bridges: OpenCode, Grok, Hermes, OpenClaw. Grok last-mile dest is project `.grok/plugins/0xray` (shared HOME does not last-wins clobber machine `~/.grok/plugins/0xray`)
|
|
51
51
|
7. Optional git hooks
|
|
52
52
|
|
|
53
53
|
**Shop plant:** `shop-extract`, `shop-witness`, `shop-pin` (groover-hangar) are first-class with mill plant. Extra shops: `foundry.json` `shopPlant`. Not `"costume": true`. `npx @0xray/foundry inspect --skip-live` is the receipt.
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,9 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
|
|
|
12
12
|
- Pack → tmp suit proof: `npm run pack:tmp-proof` (and consumer smoke) installs the packed tgz, runs `foundry mint --skip-live`, plants factory hangar shops, and inspects without costume dump. Playwright n/a (mill CLI).
|
|
13
13
|
|
|
14
14
|
### 🐛 Bug Fixes
|
|
15
|
+
- **Grok multi-seat wear** — last-mile dest is project `.grok/plugins/0xray`. Shared HOME (passwd `$HOME`) no longer writes machine `~/.grok/plugins/0xray`, so two seats (forge/critic/herald/blinky) cannot last-wins clobber each other's `XRAY_ROOT`. Isolated HOME may wear `$HOME/.grok/plugins/0xray` and still must not write the passwd machine plugin. Inspect reports project dest. Not a 45-skill dump.
|
|
16
|
+
- **Grok marketplace pack** — `package.json` `files` includes `.grok-plugin/` so `npm pack` ships the mill-default Grok manifest (`package/.grok-plugin/plugin.json`). Consumers no longer receive only stale `.plugin/plugin.json`.
|
|
17
|
+
- **Grok marketplace manifest** — `.grok-plugin/plugin.json` matches `4.0.10`: `author` is an object, `mcpServers` is a flat path (not `components.mcpServers`), description is mill+inspect default wear (not a 45 knowledge-skills claim). Fixes `grok plugin validate`.
|
|
15
18
|
- **Consumer install of packed `0xray`** — stop shipping `@0xray/repertoire` as `file:./vendor/@0xray/repertoire`. npm `--install-links`, pnpm, and yarn resolve that path from the **consumer** root (`ENOENT .../vendor/@0xray/repertoire/package.json`), not from `node_modules/0xray`. The organ stays in the tarball at `vendor/@0xray/repertoire/`; postinstall wears it into `node_modules/@0xray/repertoire`. Fresh `npm install 0xray` / `npm install 0xray-*.tgz` no longer needs a consumer-root `vendor/` tree. Mill plant (`mill`+`inspect`) unchanged.
|
|
16
19
|
|
|
17
20
|
### 🔧 Maintenance
|
|
@@ -42,6 +45,22 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
|
|
|
42
45
|
|
|
43
46
|
---
|
|
44
47
|
|
|
48
|
+
## [4.0.12] - 2026-09-12
|
|
49
|
+
|
|
50
|
+
Public npm is still `0xray@4.0.11`, which predates #29. Isolation cannot be proven from `main` alone — bots dogfood the registry. This patch PUT wears project-scoped Grok plugin dest so multi-seat wear does not last-wins clobber machine `~/.grok/plugins/0xray`. Shared HOME writes project `.grok/plugins/0xray` only. Isolated HOME may wear `$HOME/.grok/plugins/0xray` and still must not write the passwd machine plugin. Mill+inspect default. Nested mill stays **0.1.9**. Not 5.0.0. This PR does not publish.
|
|
51
|
+
|
|
52
|
+
- fix(grok): project-scoped plugin dest so multi-seat wear does not last-wins clobber machine ~/.grok (747816635)
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## [4.0.11] - 2026-09-12
|
|
57
|
+
|
|
58
|
+
npm pack now includes `.grok-plugin/` so the mill-default Grok marketplace manifest ships in the tarball (`package/.grok-plugin/plugin.json`). Published `0xray@4.0.10` omitted it — the `files` whitelist landed in #27 after that PUT. Not 5.0.0. This PR does not publish.
|
|
59
|
+
|
|
60
|
+
- fix(pack): ship .grok-plugin in npm files whitelist (5a65851cb)
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
45
64
|
## [4.0.10] - 2026-09-12
|
|
46
65
|
|
|
47
66
|
### 🔄 Changes
|
package/dist/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Manual per-platform install (idempotent, same result as postinstall):
|
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
npx 0xray opencode install
|
|
38
|
-
npx 0xray grok install # 7 MCPs servers +
|
|
38
|
+
npx 0xray grok install # 7 MCPs servers + project .grok/plugins/0xray (not machine last-wins)
|
|
39
39
|
npx 0xray hermes install
|
|
40
40
|
npx 0xray openclaw install
|
|
41
41
|
npx 0xray skill:install # starter skills
|
|
@@ -185,7 +185,7 @@ Docs: [memory routing](docs-site/docs/guides/memory-routing.md) · [Repertoire](
|
|
|
185
185
|
| Platform | Install | Postinstall behavior |
|
|
186
186
|
|----------|---------|----------------------|
|
|
187
187
|
| **OpenCode** | `npx 0xray opencode install` | Merges `opencode.json`, copies agent YML surfaces |
|
|
188
|
-
| **Grok CLI / Build** | `npx 0xray grok install` |
|
|
188
|
+
| **Grok CLI / Build** | `npx 0xray grok install` | Project `.grok/plugins/0xray` (shared HOME does not clobber machine plugin), 7 MCPs servers |
|
|
189
189
|
| **Hermes Agent** | `npx 0xray hermes install` | `~/.hermes/plugins/xray-hermes`, consumer root marker |
|
|
190
190
|
| **OpenClaw** | `npx 0xray openclaw install` | `.xray/config/openclaw.json`, skill sync |
|
|
191
191
|
|
package/dist/SKILLS.md
CHANGED
|
@@ -148,7 +148,7 @@ npx 0xray skill:install <source>
|
|
|
148
148
|
| Source (framework) | `src/skills/<name>/SKILL.md` |
|
|
149
149
|
| Published package | `node_modules/0xray/dist/skills/<name>/SKILL.md` |
|
|
150
150
|
| OpenCode (after setup) | `.opencode/skills/<name>/SKILL.md` |
|
|
151
|
-
| Grok |
|
|
151
|
+
| Grok | project `.grok/plugins/0xray/skills/<name>/SKILL.md` (machine `~/.grok/plugins/0xray` is not last-wins) |
|
|
152
152
|
| Hermes / OpenClaw | Platform skill dirs (postinstall sync) |
|
|
153
153
|
|
|
154
154
|
## Related features (since 3.1)
|
|
@@ -3,6 +3,7 @@ import { frameworkLogger } from "../core/framework-logger.js";
|
|
|
3
3
|
const DEFAULT_HERMES_PROVIDER = "xai-oauth";
|
|
4
4
|
const DEFAULT_HERMES_MODEL = "grok-4.3";
|
|
5
5
|
const DEFAULT_HERMES_TIMEOUT_MS = 120_000;
|
|
6
|
+
const UNIT_TEST_HERMES_TIMEOUT_MS = 2_000;
|
|
6
7
|
const ROLE_PROMPTS = {
|
|
7
8
|
"code-review": `You are a senior code reviewer on a governance committee for a software project. Analyze the following proposal from a code quality, maintainability, readability, and engineering best practices perspective.
|
|
8
9
|
|
|
@@ -47,12 +48,25 @@ function resolveHermesProvider() {
|
|
|
47
48
|
function resolveHermesModel() {
|
|
48
49
|
return process.env.HERMES_MODEL?.trim() || DEFAULT_HERMES_MODEL;
|
|
49
50
|
}
|
|
51
|
+
function inUnitTestContext() {
|
|
52
|
+
return process.env.NODE_ENV === "test" || Boolean(process.env.VITEST);
|
|
53
|
+
}
|
|
54
|
+
/** Dead xai-oauth (invalid_grant) hangs hermes -z until DEFAULT_HERMES_TIMEOUT_MS. Unit/Vitest must not wait. */
|
|
55
|
+
function unitTestBlocksLiveHermes() {
|
|
56
|
+
if (process.env.XRAY_GOVERNANCE_ALLOW_HERMES === "true")
|
|
57
|
+
return false;
|
|
58
|
+
return inUnitTestContext();
|
|
59
|
+
}
|
|
50
60
|
function resolveHermesTimeoutMs() {
|
|
51
61
|
const raw = process.env.HERMES_TIMEOUT_MS?.trim();
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
if (raw) {
|
|
63
|
+
const parsed = Number(raw);
|
|
64
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
65
|
+
return parsed;
|
|
66
|
+
}
|
|
67
|
+
if (inUnitTestContext())
|
|
68
|
+
return UNIT_TEST_HERMES_TIMEOUT_MS;
|
|
69
|
+
return DEFAULT_HERMES_TIMEOUT_MS;
|
|
56
70
|
}
|
|
57
71
|
export function resolveHermesBin() {
|
|
58
72
|
const explicit = process.env.HERMES_BIN?.trim();
|
|
@@ -84,6 +98,8 @@ function getConfig() {
|
|
|
84
98
|
const direct = getDirectLlmConfig();
|
|
85
99
|
if (direct)
|
|
86
100
|
return direct;
|
|
101
|
+
if (unitTestBlocksLiveHermes())
|
|
102
|
+
return null;
|
|
87
103
|
if (hermesCliAvailable()) {
|
|
88
104
|
return {
|
|
89
105
|
mode: "hermes",
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
export interface GrokInstallOptions {
|
|
18
18
|
force?: boolean;
|
|
19
19
|
dryRun?: boolean;
|
|
20
|
+
env?: NodeJS.ProcessEnv;
|
|
21
|
+
machineHome?: string;
|
|
22
|
+
targetDir?: string;
|
|
20
23
|
}
|
|
21
24
|
export declare function installForGrokCLI(options?: GrokInstallOptions): Promise<void>;
|
|
22
25
|
/** Grok TUI reads <project>/.grok/config.toml, not the package copy. */
|
|
@@ -49,18 +49,23 @@ function registerGrokMcpServers(targetDir) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
export async function installForGrokCLI(options = {}) {
|
|
52
|
-
frameworkLogger.log('grok-integration', 'install-start', 'info', {
|
|
52
|
+
frameworkLogger.log('grok-integration', 'install-start', 'info', {
|
|
53
|
+
options: { force: options.force, dryRun: options.dryRun },
|
|
54
|
+
});
|
|
53
55
|
const millSuit = requireCjs(path.join(packageRoot, 'scripts/foundry/mint-suit.cjs'));
|
|
54
|
-
const
|
|
55
|
-
const machine = millSuit.machineHome();
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
const env = options.env || process.env;
|
|
57
|
+
const machine = options.machineHome || millSuit.machineHome();
|
|
58
|
+
const targetDir = options.targetDir || resolveConsumerTargetDir(packageRoot, process.cwd());
|
|
59
|
+
const dests = millSuit.resolveGrokPluginDests(targetDir, env, machine);
|
|
60
|
+
for (const dest of dests) {
|
|
61
|
+
if (millSuit.wouldClobberMachineGrok(dest, env, machine)) {
|
|
62
|
+
frameworkLogger.log('grok-integration', 'refuse-machine-grok-clobber', 'error', {
|
|
63
|
+
home: millSuit.processHome(env),
|
|
64
|
+
machineHome: machine,
|
|
65
|
+
dest,
|
|
66
|
+
});
|
|
67
|
+
throw new Error('foundry-inspect: isolated HOME must not clobber ~/.grok/plugins/0xray');
|
|
68
|
+
}
|
|
64
69
|
}
|
|
65
70
|
// Try to find the plugin source from the installed package
|
|
66
71
|
const possibleSources = [
|
|
@@ -73,58 +78,57 @@ export async function installForGrokCLI(options = {}) {
|
|
|
73
78
|
return;
|
|
74
79
|
}
|
|
75
80
|
if (options.dryRun) {
|
|
76
|
-
console.log(`[Grok] Dry run: Would copy plugin from ${sourceDir} → ${
|
|
81
|
+
console.log(`[Grok] Dry run: Would copy plugin from ${sourceDir} → ${dests.join(' , ')}`);
|
|
77
82
|
return;
|
|
78
83
|
}
|
|
79
|
-
const
|
|
84
|
+
const isolated = millSuit.isIsolatedHome(env, machine);
|
|
80
85
|
try {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if (globalCopied > 0) {
|
|
102
|
-
console.log(`\x1b[32m✓ Synced ${globalCopied} builtin skills to ~/.grok/skills/\x1b[0m`);
|
|
86
|
+
for (const dest of dests) {
|
|
87
|
+
const pluginExists = fs.existsSync(dest);
|
|
88
|
+
if (pluginExists && !options.force) {
|
|
89
|
+
console.log(`[Grok] 0xray Grok plugin is already installed at ${dest}.`);
|
|
90
|
+
console.log('Use --force to reinstall plugin files.');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
fs.cpSync(sourceDir, dest, { recursive: true, force: true });
|
|
94
|
+
frameworkLogger.log('grok-integration', 'plugin-copied', 'info', { destination: dest });
|
|
95
|
+
console.log(`\x1b[32m✓ Copied Grok plugin to ${dest}\x1b[0m`);
|
|
96
|
+
}
|
|
97
|
+
if (millSuit.wantsCostume(targetDir)) {
|
|
98
|
+
const skillsCopied = syncBuiltinSkills(path.join(dest, 'skills'));
|
|
99
|
+
if (skillsCopied > 0) {
|
|
100
|
+
console.log(`\x1b[32m✓ Synced ${skillsCopied} builtin skills to Grok plugin\x1b[0m`);
|
|
101
|
+
}
|
|
102
|
+
frameworkLogger.log('grok-integration', 'skills-synced', 'info', { count: skillsCopied });
|
|
103
|
+
}
|
|
104
|
+
pinGrokPluginToInstalledDist(dest, packageRoot, targetDir);
|
|
105
|
+
wearGrokHookCommands(dest, packageRoot, targetDir);
|
|
103
106
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
fs.cpSync(sourceDir, projectPluginDir, { recursive: true, force: true });
|
|
107
|
+
if (isolated && millSuit.wantsCostume(targetDir)) {
|
|
108
|
+
const home = millSuit.processHome(env);
|
|
109
|
+
const globalCopied = syncBuiltinSkills(path.join(home, '.grok', 'skills'));
|
|
110
|
+
if (globalCopied > 0) {
|
|
111
|
+
console.log(`\x1b[32m✓ Synced ${globalCopied} builtin skills to isolated ~/.grok/skills/\x1b[0m`);
|
|
110
112
|
}
|
|
111
|
-
pinGrokPluginToInstalledDist(projectPluginDir, packageRoot, targetDir);
|
|
112
|
-
wearGrokHookCommands(projectPluginDir, packageRoot, targetDir);
|
|
113
113
|
}
|
|
114
114
|
writeProjectRepertoireMcp(targetDir);
|
|
115
115
|
mintAfterWear(targetDir);
|
|
116
|
-
|
|
116
|
+
const primary = dests[0];
|
|
117
117
|
try {
|
|
118
|
-
execSync(`grok plugins trust "${
|
|
118
|
+
execSync(`grok plugins trust "${primary}"`, { stdio: 'ignore' });
|
|
119
119
|
console.log('\x1b[32m✓ Auto-trusted the 0xray plugin with Grok CLI\x1b[0m');
|
|
120
120
|
}
|
|
121
121
|
catch {
|
|
122
122
|
console.log('\nPlease run this command to fully trust the plugin:');
|
|
123
|
-
console.log(` grok plugins trust "${
|
|
123
|
+
console.log(` grok plugins trust "${primary}"`);
|
|
124
|
+
}
|
|
125
|
+
if (isolated) {
|
|
126
|
+
registerGrokMcpServers(targetDir);
|
|
127
|
+
console.log('\x1b[32m✓ Registered 7 xray MCP servers with Grok CLI (npx)\x1b[0m');
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
console.log('\x1b[32m✓ Project-scoped Grok plugin worn (machine ~/.grok/plugins/0xray not written)\x1b[0m');
|
|
124
131
|
}
|
|
125
|
-
// Register MCP servers via grok mcp add (npx -y 0xray mcp — matches install-bridges)
|
|
126
|
-
registerGrokMcpServers(targetDir);
|
|
127
|
-
console.log('\x1b[32m✓ Registered 7 xray MCP servers with Grok CLI (npx)\x1b[0m');
|
|
128
132
|
console.log('\n✅ 0xRay is now installed as a first-class Grok CLI plugin!');
|
|
129
133
|
console.log('Restart Grok or run `grok` to load the new hooks and MCP servers.');
|
|
130
134
|
}
|
|
@@ -150,38 +154,40 @@ function wearGrokHookCommands(pluginDir, xrayRoot, targetDir) {
|
|
|
150
154
|
function pinGrokPluginToInstalledDist(pluginDir, xrayRoot, targetDir) {
|
|
151
155
|
const hookJs = path.join(xrayRoot, 'dist/integrations/grok/hooks/pre-tool-use.js');
|
|
152
156
|
const cliJs = path.join(xrayRoot, 'dist/cli/index.js');
|
|
153
|
-
if (!fs.existsSync(hookJs))
|
|
154
|
-
return;
|
|
155
157
|
const hooksPath = path.join(pluginDir, 'hooks', 'hooks.json');
|
|
156
|
-
if (fs.existsSync(hooksPath)) {
|
|
158
|
+
if (fs.existsSync(hookJs) && fs.existsSync(hooksPath)) {
|
|
157
159
|
const text = fs.readFileSync(hooksPath, 'utf8');
|
|
158
160
|
fs.writeFileSync(hooksPath, text.split('${XRAY_AI_PATH:-node_modules/0xray}').join(xrayRoot));
|
|
159
161
|
}
|
|
160
162
|
const mcpPath = path.join(pluginDir, '.mcp.json');
|
|
161
|
-
if (fs.existsSync(mcpPath)
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
163
|
+
if (!fs.existsSync(mcpPath))
|
|
164
|
+
return;
|
|
165
|
+
const mcp = JSON.parse(fs.readFileSync(mcpPath, 'utf8'));
|
|
166
|
+
for (const server of Object.values(mcp.mcpServers ?? {})) {
|
|
167
|
+
server.env = { ...server.env, XRAY_ROOT: targetDir };
|
|
168
|
+
if (fs.existsSync(cliJs) &&
|
|
169
|
+
server.command === 'npx' &&
|
|
170
|
+
Array.isArray(server.args) &&
|
|
171
|
+
server.args.includes('mcp')) {
|
|
172
|
+
const mcpIdx = server.args.indexOf('mcp');
|
|
173
|
+
const mcpCmd = server.args[mcpIdx + 1] ?? 'governance';
|
|
174
|
+
server.command = 'node';
|
|
175
|
+
server.args = [cliJs, 'mcp', mcpCmd];
|
|
170
176
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
}
|
|
178
|
+
const repertoireMcp = resolveRepertoireMcp(targetDir);
|
|
179
|
+
if (mcp.mcpServers) {
|
|
180
|
+
if (repertoireMcp) {
|
|
181
|
+
mcp.mcpServers.repertoire = {
|
|
182
|
+
command: 'node',
|
|
183
|
+
args: [repertoireMcp],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
delete mcp.mcpServers.repertoire;
|
|
182
188
|
}
|
|
183
|
-
fs.writeFileSync(mcpPath, `${JSON.stringify(mcp, null, 2)}\n`);
|
|
184
189
|
}
|
|
190
|
+
fs.writeFileSync(mcpPath, `${JSON.stringify(mcp, null, 2)}\n`);
|
|
185
191
|
}
|
|
186
192
|
/** Grok TUI reads <project>/.grok/config.toml, not the package copy. */
|
|
187
193
|
export function writeProjectRepertoireMcp(projectRoot) {
|
package/llms.txt
CHANGED
|
@@ -8,7 +8,7 @@ Default consumer wear is **mill plant** (`mill` + `inspect`), not a 45-skill / 4
|
|
|
8
8
|
|
|
9
9
|
## Wear (what a stranger gets)
|
|
10
10
|
|
|
11
|
-
- `npm install 0xray` — postinstall fastens mill+inspect, writes 7 MCP `.mcp.json`, four host bridges (OpenCode, Grok, Hermes, OpenClaw), overlays their plant. Does **not** write consumer-root `SKILLS.md`.
|
|
11
|
+
- `npm install 0xray` — postinstall fastens mill+inspect, writes 7 MCP `.mcp.json`, four host bridges (OpenCode, Grok, Hermes, OpenClaw), overlays their plant. Grok last-mile dest is project `.grok/plugins/0xray`. Shared HOME does not last-wins clobber machine `~/.grok/plugins/0xray`. Isolated HOME must not write the machine plugin. Does **not** write consumer-root `SKILLS.md`.
|
|
12
12
|
- `npx @0xray/foundry mint --skip-live` — re-fasten mill plant, then inspect.
|
|
13
13
|
- `npx @0xray/foundry inspect --skip-live` — plant-vs-worn, receipt, CI. Chat is not a receipt.
|
|
14
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "0xray",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.12",
|
|
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",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"test:processors": "npm test -- src/__tests__/unit/processor-activation.test.ts src/__tests__/unit/typescript-compilation-processor.test.ts",
|
|
80
80
|
"test:miscellaneous": "npm test -- src/__tests__/unit/blocked-test.test.ts",
|
|
81
81
|
"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",
|
|
82
|
-
"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",
|
|
82
|
+
"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",
|
|
83
83
|
"test:integration-all": "npm test -- src/__tests__/integration/",
|
|
84
84
|
"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",
|
|
85
85
|
"test:agents-all": "echo 'Legacy agents test entry retired'",
|
|
@@ -180,6 +180,7 @@
|
|
|
180
180
|
"src/skills/",
|
|
181
181
|
"src/mcps/",
|
|
182
182
|
".plugin/",
|
|
183
|
+
".grok-plugin/",
|
|
183
184
|
".opencode/agents/",
|
|
184
185
|
".opencode/commands/",
|
|
185
186
|
".opencode/hooks/",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
Shop plant is first-class with mill plant. `shop-extract`, `shop-witness`, `shop-pin` (and `foundry.json` `shopPlant`) are not a costume dump. `"costume": true` still required for 45/42. No mill version bump.
|
|
5
|
+
Shop plant is first-class with mill plant. `shop-extract`, `shop-witness`, `shop-pin` (and `foundry.json` `shopPlant`) are not a costume dump. `"costume": true` still required for 45/42. Inspect isolated-home dest is project `.grok/plugins/0xray`. Shared HOME last-mile does not write machine `~/.grok/plugins/0xray`. Isolated HOME must not write the passwd machine plugin. No mill version bump.
|
|
6
6
|
|
|
7
7
|
## [0.1.9] - 2026-09-09
|
|
8
8
|
|
|
@@ -32,7 +32,7 @@ npx @0xray/foundry hooks
|
|
|
32
32
|
|
|
33
33
|
`FOUNDRY_ROOT` overrides cwd (the repo being milled).
|
|
34
34
|
|
|
35
|
-
`gate` is build + test + docs-check. `docs-build` runs Docusaurus on the 0xray exo (`docs-site/`); stranger mills skip. `inspect` runs the six mill checks (diff, plant vs worn, receipt, CI, live tarball GET, isolated HOME). Mint fails on a costume dump. Isolated HOME skips machine `~/.grok`. `ci` reports GitHub Actions (no auto-push). `hooks` installs git pre/post hooks. GitHub `0xRay CI/CD` is the mill gate on `main`. `Deploy Docs` is the mill Pages put.
|
|
35
|
+
`gate` is build + test + docs-check. `docs-build` runs Docusaurus on the 0xray exo (`docs-site/`); stranger mills skip. `inspect` runs the six mill checks (diff, plant vs worn, receipt, CI, live tarball GET, isolated HOME). Mint fails on a costume dump. Isolated HOME skips machine `~/.grok`. Shared HOME last-mile dest is project `.grok/plugins/0xray` (no last-wins machine plugin). `ci` reports GitHub Actions (no auto-push). `hooks` installs git pre/post hooks. GitHub `0xRay CI/CD` is the mill gate on `main`. `Deploy Docs` is the mill Pages put.
|
|
36
36
|
|
|
37
37
|
`docs-check` and `gate` run **full** 0xRay corpus only when the milled `package.json` name is `0xray` and `docs-site/` exists. Otherwise **light**: `package.json` + CHANGELOG.
|
|
38
38
|
|
|
@@ -57,7 +57,7 @@ After mill plant is fastened, overlay their plant (defaults; remap in `foundry.j
|
|
|
57
57
|
|
|
58
58
|
**Shop plant:** `shop-extract`, `shop-witness`, `shop-pin` are first-class with mill plant. Inspect does not treat those worn names as a costume dump. `foundry.json` `"shopPlant"` names more shops (array), a plant dir (string), or `{ "skills": [...], "dir": "..." }`. This is not `"costume": true` and does not copy 45/42.
|
|
59
59
|
|
|
60
|
-
**4.0.9 mill target (0xray postinstall, not this mill package):** `install-bridges.cjs` does not mill npm global prefix or npx `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. Nested mill stays **0.1.9**.
|
|
60
|
+
**4.0.9 mill target (0xray postinstall, not this mill package):** `install-bridges.cjs` does not mill npm global prefix or npx `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. Shared HOME Grok last-mile is project `.grok/plugins/0xray` (two seats do not clobber machine plugin). Nested mill stays **0.1.9**.
|
|
61
61
|
|
|
62
62
|
## Publish this mill
|
|
63
63
|
|
|
@@ -42,6 +42,18 @@ export function wouldClobberMachineGrok(
|
|
|
42
42
|
return mint.wouldClobberMachineGrok(dest, env, machine);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export function projectGrokPluginDir(targetDir) {
|
|
46
|
+
return mint.projectGrokPluginDir(targetDir);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function resolveGrokPluginDests(
|
|
50
|
+
targetDir,
|
|
51
|
+
env = process.env,
|
|
52
|
+
machine = mint.machineHome(),
|
|
53
|
+
) {
|
|
54
|
+
return mint.resolveGrokPluginDests(targetDir, env, machine);
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
function readJson(file) {
|
|
46
58
|
try {
|
|
47
59
|
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
@@ -218,17 +230,20 @@ export function packagesToProbe(root) {
|
|
|
218
230
|
});
|
|
219
231
|
}
|
|
220
232
|
|
|
221
|
-
function checkIsolatedHome(env = process.env, machine = mint.machineHome()) {
|
|
233
|
+
function checkIsolatedHome(root, env = process.env, machine = mint.machineHome()) {
|
|
222
234
|
const isolated = isIsolatedHome(env, machine);
|
|
223
235
|
const machinePlugin = machineGrokPluginDir(machine);
|
|
224
|
-
const
|
|
225
|
-
const dest =
|
|
226
|
-
const clobber = wouldClobberMachineGrok(
|
|
236
|
+
const dests = mint.resolveGrokPluginDests(root, env, machine);
|
|
237
|
+
const dest = dests[0] || null;
|
|
238
|
+
const clobber = dests.some((d) => wouldClobberMachineGrok(d, env, machine));
|
|
227
239
|
if (clobber) {
|
|
228
240
|
return {
|
|
229
241
|
id: "isolated-home",
|
|
230
242
|
ok: false,
|
|
231
243
|
isolated,
|
|
244
|
+
dest,
|
|
245
|
+
dests,
|
|
246
|
+
machinePlugin,
|
|
232
247
|
detail: `isolated HOME must not write ${machinePlugin}`,
|
|
233
248
|
};
|
|
234
249
|
}
|
|
@@ -237,7 +252,8 @@ function checkIsolatedHome(env = process.env, machine = mint.machineHome()) {
|
|
|
237
252
|
ok: true,
|
|
238
253
|
isolated,
|
|
239
254
|
machinePlugin,
|
|
240
|
-
dest
|
|
255
|
+
dest,
|
|
256
|
+
dests,
|
|
241
257
|
};
|
|
242
258
|
}
|
|
243
259
|
|
|
@@ -275,7 +291,7 @@ export async function inspectSuit(root, opts = {}) {
|
|
|
275
291
|
}
|
|
276
292
|
}
|
|
277
293
|
|
|
278
|
-
checks.push(checkIsolatedHome(env, machineHome));
|
|
294
|
+
checks.push(checkIsolatedHome(root, env, machineHome));
|
|
279
295
|
|
|
280
296
|
const failed = checks.filter((c) => c.ok === false);
|
|
281
297
|
const receipt = checks.find((c) => c.id === "receipt") || {};
|
|
@@ -217,6 +217,10 @@ function machineGrokPluginDir(machine) {
|
|
|
217
217
|
return path.join(machine || machineHome(), ".grok", "plugins", "0xray");
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
function projectGrokPluginDir(targetDir) {
|
|
221
|
+
return path.join(targetDir, ".grok", "plugins", "0xray");
|
|
222
|
+
}
|
|
223
|
+
|
|
220
224
|
function wouldClobberMachineGrok(dest, env, machine) {
|
|
221
225
|
if (!dest) return false;
|
|
222
226
|
const realMachine = machine || machineHome();
|
|
@@ -226,6 +230,24 @@ function wouldClobberMachineGrok(dest, env, machine) {
|
|
|
226
230
|
return target === real || target.startsWith(`${real}${path.sep}`);
|
|
227
231
|
}
|
|
228
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Last-mile Grok plugin dests. Project floor always.
|
|
235
|
+
* Isolated HOME may also wear $HOME/.grok/plugins/0xray (not passwd machine).
|
|
236
|
+
* Shared HOME never writes machine ~/.grok/plugins/0xray (multi-seat last-wins).
|
|
237
|
+
*/
|
|
238
|
+
function resolveGrokPluginDests(targetDir, env, machine) {
|
|
239
|
+
const realMachine = machine || machineHome();
|
|
240
|
+
const dests = [projectGrokPluginDir(targetDir)];
|
|
241
|
+
if (!isIsolatedHome(env, realMachine)) return dests;
|
|
242
|
+
const home = processHome(env);
|
|
243
|
+
if (!home) return dests;
|
|
244
|
+
const isolatedDest = path.join(home, ".grok", "plugins", "0xray");
|
|
245
|
+
if (wouldClobberMachineGrok(isolatedDest, env, realMachine)) return dests;
|
|
246
|
+
if (path.resolve(isolatedDest) === path.resolve(dests[0])) return dests;
|
|
247
|
+
dests.push(isolatedDest);
|
|
248
|
+
return dests;
|
|
249
|
+
}
|
|
250
|
+
|
|
229
251
|
/**
|
|
230
252
|
* Project skill dirs on every TUI floor. Create on fasten. Never machine home.
|
|
231
253
|
* YML agents stay OpenCode (`.opencode/agents`).
|
|
@@ -578,5 +600,7 @@ module.exports = {
|
|
|
578
600
|
processHome,
|
|
579
601
|
isIsolatedHome,
|
|
580
602
|
machineGrokPluginDir,
|
|
603
|
+
projectGrokPluginDir,
|
|
604
|
+
resolveGrokPluginDests,
|
|
581
605
|
wouldClobberMachineGrok,
|
|
582
606
|
};
|
|
@@ -16,7 +16,7 @@ Mill **does** these checks (`npx @0xray/foundry inspect`). Mint fails on a costu
|
|
|
16
16
|
3. **Mill receipt.** `.xray/foundry-inventory.json` — mill name/version, `suit` (`fastened` / `overlay` / `costume`), `millPlant.skills` must include `mill` and `inspect`.
|
|
17
17
|
4. **CI.** GitHub mill CI report (`.opencode/logs/ci-cd-monitor-report.json`), not a green check in chat. No token is a skip, not a pass invented.
|
|
18
18
|
5. **Live PUT.** HTTP 200 on the npm `.tgz`. Metadata without a tarball is not shipped.
|
|
19
|
-
6. **Isolated HOME.** Last-mile must not
|
|
19
|
+
6. **Isolated HOME.** Last-mile dest is project `.grok/plugins/0xray`. Isolated HOME may wear `$HOME/.grok/plugins/0xray` and must not write machine `~/.grok/plugins/0xray`. Shared HOME (passwd `$HOME`) does not last-wins clobber the machine plugin. Mill compares `$HOME` to the passwd home (`os.userInfo().homedir`), not `os.homedir()` (which follows `$HOME`).
|
|
20
20
|
|
|
21
21
|
## How to work
|
|
22
22
|
|