0xray 4.1.0 → 4.1.1
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 +4 -1
- package/.grok-plugin/plugin.json +1 -1
- package/.opencode/skills/orchestrator/SKILL.md +1 -7
- package/.xray/features.json +4 -1
- package/.xray/features.schema.json +8 -0
- package/AGENTS-consumer.md +1 -1
- package/AGENTS.md +2 -2
- package/README.md +2 -2
- package/dist/.gitignore.default +4 -1
- package/dist/AGENTS.md +2 -2
- package/dist/CHANGELOG.md +27 -1
- package/dist/README.md +2 -2
- package/dist/cli/commands/opencode-install.js +3 -9
- package/dist/cli/commands/skill-install.js +10 -5
- package/dist/cli/goggles-status.d.ts +2 -5
- package/dist/cli/goggles-status.js +5 -53
- package/dist/cli/index.js +2 -2
- package/dist/enforcement/enforcer-tools.d.ts +1 -1
- package/dist/enforcement/enforcer-tools.js +1 -1
- package/dist/integrations/cursor/README.md +1 -1
- package/dist/integrations/cursor/hooks/pre-tool-use.js +4 -0
- package/dist/integrations/grok/grok-cli.js +5 -7
- package/dist/integrations/grok/hooks/grok-hook-utils.js +4 -1
- package/dist/integrations/grok/hooks/pre-tool-use.js +4 -18
- package/dist/integrations/grok/hooks/session-start.js +4 -2
- package/dist/integrations/hermes-agent/bridge.mjs +4 -1
- package/dist/integrations/hooks/goggles-mcp.mjs +20 -196
- package/dist/integrations/hooks/goggles-pipeline.mjs +606 -616
- package/dist/integrations/hooks/goggles-planes.json +88 -40
- package/dist/integrations/hooks/plates.cjs +84 -0
- package/dist/integrations/hooks/pre-tool-speak.mjs +2 -4
- package/dist/integrations/hooks/skill-seek.mjs +115 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +4 -1
- package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +4 -4
- package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +10 -1
- 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 +14 -0
- package/dist/nucleus/thin-dispatch.d.ts +1 -1
- package/dist/nucleus/thin-dispatch.js +1 -1
- package/dist/nucleus/work-freshness.mjs +10 -0
- package/dist/plugin/xray-codex-injection.js +3 -1
- package/dist/skills/orchestrator/SKILL.md +1 -7
- package/docs-site/docs/plates/asides.md +35 -0
- package/docs-site/docs/plates/confer.md +35 -0
- package/docs-site/docs/plates/consumer-mcp.md +35 -0
- package/docs-site/docs/plates/delegation-gate.md +35 -0
- package/docs-site/docs/plates/dynamo.md +35 -0
- package/docs-site/docs/plates/foundry.md +35 -0
- package/docs-site/docs/plates/goggles.md +8 -8
- package/docs-site/docs/plates/ground.md +35 -0
- package/docs-site/docs/plates/hermes.md +35 -0
- package/docs-site/docs/plates/index.md +12 -5
- package/docs-site/docs/plates/inference-cycle.md +35 -0
- package/docs-site/docs/plates/lens-gate.md +6 -6
- package/docs-site/docs/plates/openclaw.md +35 -0
- package/docs-site/docs/plates/opencode.md +35 -0
- package/docs-site/docs/plates/repertoire.md +35 -0
- package/docs-site/docs/plates/synthesis.md +35 -0
- package/docs-site/docs/plates/temperament.md +35 -0
- package/docs-site/docs/plates/trail-state.md +1 -1
- package/package.json +1 -1
- package/scripts/foundry/README.md +3 -1
- package/scripts/foundry/mint-suit.cjs +120 -2
- package/scripts/foundry/plant/skills/mill/SKILL.md +1 -1
- package/scripts/foundry/reconcile-version.mjs +10 -3
- package/scripts/foundry/release.mjs +1 -1
- package/scripts/foundry/validate-release-docs.mjs +2 -2
- package/scripts/foundry/version-manager.mjs +12 -4
- package/scripts/node/install-bridges.cjs +63 -34
- package/scripts/node/pack-tmp-suit-proof.mjs +23 -4
- package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +10 -1
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/skills/orchestrator/SKILL.md +1 -7
- package/xray/features.json +4 -1
- package/xray/features.schema.json +8 -0
package/.gitignore.default
CHANGED
package/.grok-plugin/plugin.json
CHANGED
|
@@ -57,13 +57,7 @@ When `multi_agent_orchestration.lead_dev_mode` is true in `features.json` (defau
|
|
|
57
57
|
|
|
58
58
|
The command is `0xray look`. `0xray goggles` is the same organ. A pipe keeps the line card. A terminal shows that card as a pane. Chat seats without hooks use the `goggles` MCP tools `look` and `status_lens`. Same organ.
|
|
59
59
|
|
|
60
|
-
|
|
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.
|
|
63
|
-
|
|
64
|
-
Naming a plane, `digest`, or `triage` returns that plane's view. The fields are from, digest, plate, entry, exit, files, skills, setup, teardown, and worn. Each field has a pipe. The pipe writes what it can see from the plate or the tree, and the view keeps that field. A field the pipe cannot see yet stays on the view for the next look. The rows are ground, routing, house, boot, governance, memory-recall, orchestration, processor, and reporting. Those nine are not Kind 0. The mill path is `scripts/foundry`. `triage` names the fields still open and whether the row holds. Zoom after the card is the same ladder: ecosystem, part, one flow, one artifact.
|
|
65
|
-
|
|
66
|
-
The hold lasts for the work that named the plane. A sentence that does not say look or name does not arm it and does not drop it. Work that says goggles clears the hold and stays quiet. When a tool names one card plane, the suit adds that plane's file as a hint.
|
|
60
|
+
A session starts on dev. The boot payload includes that card from `.xray/state/LENS.md`. The planes are dev, integration, domain, and ecosystem. A search inside the current card runs. Any other search returns the current card and does not run. Opening a file on the current card adds nothing. Opening a file on another plane switches to that card and the open proceeds. A file on no card stays on the current plane and returns that card. Compact writes that same card back. A thing on that plane has its own card. One card has its own plate and can name more. A missing plate names the stamp-plate skill. Stamp one plate for that card. The cards and plates that stay are what the next agent reads. Saying goggles clears a stale card line on the station.
|
|
67
61
|
|
|
68
62
|
## Hooks (rewired, not new MCPs)
|
|
69
63
|
|
package/.xray/features.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./features.schema.json",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"description": "0xRay Framework - Unified Feature Configuration",
|
|
5
5
|
"suit_temperament": {
|
|
6
6
|
"profile": "auto",
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"generic": "guided"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
+
"goggles": {
|
|
16
|
+
"enabled": true
|
|
17
|
+
},
|
|
15
18
|
"token_optimization": {
|
|
16
19
|
"enabled": true,
|
|
17
20
|
"max_context_tokens": 20000,
|
|
@@ -132,6 +132,14 @@
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
},
|
|
135
|
+
"goggles": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"description": "The suit keeps goggles on. enabled false fails wear and doctor.",
|
|
138
|
+
"properties": {
|
|
139
|
+
"enabled": { "type": "boolean" }
|
|
140
|
+
},
|
|
141
|
+
"required": ["enabled"]
|
|
142
|
+
},
|
|
135
143
|
"synthesis": {
|
|
136
144
|
"type": "object",
|
|
137
145
|
"properties": {
|
package/AGENTS-consumer.md
CHANGED
|
@@ -25,7 +25,7 @@ A peer lead continues from this card + Repertoire + the `orchestrator` skill. Du
|
|
|
25
25
|
`npx 0xray wear` writes the consumer suit:
|
|
26
26
|
|
|
27
27
|
- Copies this file → **`AGENTS.md`** in your project root
|
|
28
|
-
- Fastens mill plant (`mill` + `inspect`) then overlays **your** `src/skills` (same name wins). 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 package declares (blip-inspect, blip-vibe, blip-looker, sound-inspect, sound-mixer live in the mill). `npx @0xray/foundry sound mix` / `sound render` / `blip render` are CLI shims (0.1.11+). `npx @0xray/foundry inspect` runs mill-exported inspect; on a sound seat the last bed receipt; on a blip seat the last 4.44s receipt. Chat is not a receipt.
|
|
28
|
+
- Fastens mill plant (`mill` + `inspect`) then overlays **your** `src/skills` (same name wins). 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 package declares (blip-inspect, blip-vibe, blip-looker, sound-inspect, sound-mixer live in the mill). `npx @0xray/foundry sound mix` / `sound render` / `blip render` are CLI shims (0.1.11+). `npx @0xray/foundry inspect` runs mill-exported inspect; on a sound seat the last bed receipt; on a blip seat the last 4.44s receipt. Chat is not a receipt. The mill suit also wears every catalog skill and every role file. A blip or sound seat fastens that plant only. A name outside the fastened set still fails inspect. Does **not** write root **`SKILLS.md`**
|
|
29
29
|
- Factory shop plant (`shop-extract`, `shop-witness`, `shop-pin` from groover-hangar) is first-class with mill plant. Extra shops: `foundry.json` `"shopPlant"`. Not costume.
|
|
30
30
|
- Seeds **`.gitignore`** (from template, if absent)
|
|
31
31
|
- Deploys **`.xray/`** (`codex.json`, `features.json`, `config.json`) then overlays **your** mill SSOT (`xray/codex.json`, `xray/features.json`, `src/skills`, `src/opencode/agents`; remap with `foundry.json`)
|
package/AGENTS.md
CHANGED
|
@@ -24,7 +24,7 @@ Before other work, Read `.xray/state/STATION.md`. Compaction and host change are
|
|
|
24
24
|
- **External Governance** — Dynamo Solar SSOT, 69-term Codex. Judgement stays on.
|
|
25
25
|
- **Autonomous Engine** — thinDispatch 7-flow, AsideContext, confidence gate
|
|
26
26
|
|
|
27
|
-
Agents are declared in `src/opencode/agents/*.yml` — the YML SSOT. Skills live in `src/skills/*/SKILL.md` — see [SKILLS.md](SKILLS.md) for the exo catalog. Consumer default plant is **mill + inspect
|
|
27
|
+
Agents are declared in `src/opencode/agents/*.yml` — the YML SSOT. Skills live in `src/skills/*/SKILL.md` — see [SKILLS.md](SKILLS.md) for the exo catalog. Consumer default plant is **mill + inspect**. The mill suit also wears every catalog skill and every role file (`AGENTS-consumer.md` → `AGENTS.md`). Factory hangar shops coexist via shop plant. See [llms.txt](llms.txt).
|
|
28
28
|
|
|
29
29
|
## Consumer MCP surface (7 servers)
|
|
30
30
|
|
|
@@ -49,7 +49,7 @@ Governance deliberation: **code-review**, **security-audit**, **researcher** wit
|
|
|
49
49
|
`npx 0xray wear` runs `installAllBridges()` from `install-bridges.cjs`:
|
|
50
50
|
|
|
51
51
|
1. `AGENTS-consumer.md` → `AGENTS.md` (does **not** write consumer-root `SKILLS.md`)
|
|
52
|
-
2. Fasten mill plant (`mill` + `inspect`). 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 package declares (looker, vibe, mixer, blip-inspect, blip-vibe, blip-looker, sound-inspect, sound-mixer live in the mill).
|
|
52
|
+
2. Fasten mill plant (`mill` + `inspect`). 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 package declares (looker, vibe, mixer, blip-inspect, blip-vibe, blip-looker, sound-inspect, sound-mixer live in the mill). The mill suit also wears every catalog skill and every OpenCode role file. A blip or sound seat fastens that plant only. A name outside the fastened set still fails inspect.
|
|
53
53
|
3. `.gitignore.default` → `.gitignore` (if absent)
|
|
54
54
|
4. `.xray/` config (`codex.json`, `features.json`, `config.json`) then overlay their plant
|
|
55
55
|
5. `.mcp.json` (7 servers)
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**4.1** — a suit that survives the context window
|
|
6
6
|
|
|
7
|
-
Bifrost is the live board. Goggles
|
|
7
|
+
Bifrost is the live board. Goggles views one plane. A search runs inside that card.
|
|
8
8
|
|
|
9
9
|
0xRay is a three-subsystem autonomous engine. The suit is the wear. Inference remembers. External Governance judges. The Autonomous Engine runs the work. The host you already run wears it: Grok, OpenCode, Hermes, OpenClaw, or Cursor. Memory, judgement, and payments come on with the suit. When the window closes, the next session wakes with the job, the page, and the laws.
|
|
10
10
|
|
|
@@ -59,7 +59,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
|
|
|
59
59
|
|
|
60
60
|
| Version | Highlights |
|
|
61
61
|
|---------|------------|
|
|
62
|
-
| **4.1.0** | Bifrost is the collector board. A cloud agent is a board row. A stuck card's L2 nudge goes to the CoS role. `live-inbox` requires `LIVE_URL`, `SEAT_KEYS_DIR`, and `LIVE_CURSORS`. Goggles
|
|
62
|
+
| **4.1.0** | Bifrost is the collector board. A cloud agent is a board row. A stuck card's L2 nudge goes to the CoS role. `live-inbox` requires `LIVE_URL`, `SEAT_KEYS_DIR`, and `LIVE_CURSORS`. Goggles views one plane. The card is in LENS.md. A search runs inside that card. |
|
|
63
63
|
| **4.0.43** | Confer completes only on a real PASS. Cursor gate events fail closed, except EACCES when a cloud wrapper cannot write dest. Gate C cannot be skipped. |
|
|
64
64
|
| **4.0.42** | Confer votes. Burst runs the swarm. |
|
|
65
65
|
| **4.0.41** | Wake cascade stays on the station module. A fresh wear fastens mill and inspect. Goggles records the worn package path. The live page plays the mesh in the browser. |
|
package/dist/.gitignore.default
CHANGED
package/dist/AGENTS.md
CHANGED
|
@@ -24,7 +24,7 @@ Before other work, Read `.xray/state/STATION.md`. Compaction and host change are
|
|
|
24
24
|
- **External Governance** — Dynamo Solar SSOT, 69-term Codex. Judgement stays on.
|
|
25
25
|
- **Autonomous Engine** — thinDispatch 7-flow, AsideContext, confidence gate
|
|
26
26
|
|
|
27
|
-
Agents are declared in `src/opencode/agents/*.yml` — the YML SSOT. Skills live in `src/skills/*/SKILL.md` — see [SKILLS.md](SKILLS.md) for the exo catalog. Consumer default plant is **mill + inspect
|
|
27
|
+
Agents are declared in `src/opencode/agents/*.yml` — the YML SSOT. Skills live in `src/skills/*/SKILL.md` — see [SKILLS.md](SKILLS.md) for the exo catalog. Consumer default plant is **mill + inspect**. The mill suit also wears every catalog skill and every role file (`AGENTS-consumer.md` → `AGENTS.md`). Factory hangar shops coexist via shop plant. See [llms.txt](llms.txt).
|
|
28
28
|
|
|
29
29
|
## Consumer MCP surface (7 servers)
|
|
30
30
|
|
|
@@ -49,7 +49,7 @@ Governance deliberation: **code-review**, **security-audit**, **researcher** wit
|
|
|
49
49
|
`npx 0xray wear` runs `installAllBridges()` from `install-bridges.cjs`:
|
|
50
50
|
|
|
51
51
|
1. `AGENTS-consumer.md` → `AGENTS.md` (does **not** write consumer-root `SKILLS.md`)
|
|
52
|
-
2. Fasten mill plant (`mill` + `inspect`). 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 package declares (looker, vibe, mixer, blip-inspect, blip-vibe, blip-looker, sound-inspect, sound-mixer live in the mill).
|
|
52
|
+
2. Fasten mill plant (`mill` + `inspect`). 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 package declares (looker, vibe, mixer, blip-inspect, blip-vibe, blip-looker, sound-inspect, sound-mixer live in the mill). The mill suit also wears every catalog skill and every OpenCode role file. A blip or sound seat fastens that plant only. A name outside the fastened set still fails inspect.
|
|
53
53
|
3. `.gitignore.default` → `.gitignore` (if absent)
|
|
54
54
|
4. `.xray/` config (`codex.json`, `features.json`, `config.json`) then overlay their plant
|
|
55
55
|
5. `.mcp.json` (7 servers)
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,33 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## [4.1.1] - 2026-10-18
|
|
10
|
+
|
|
11
|
+
Work on main after 4.1.0.
|
|
12
|
+
|
|
13
|
+
### Wear
|
|
14
|
+
|
|
15
|
+
The mill suit wears every catalog skill and every role file when costume is off. The mill plant stays `mill` and `inspect`. A blip or sound seat fastens that plant only. A name outside the fastened set still fails inspect. (#379)
|
|
16
|
+
|
|
17
|
+
### Goggles
|
|
18
|
+
|
|
19
|
+
The lens file is `.xray/state/LENS.md`. The planes are dev, integration, domain, and ecosystem. A search runs only inside the current card. Any other search returns that card and does not run. A path switches the card. (#371)
|
|
20
|
+
|
|
21
|
+
Each card lists three to five skills in hand order. That list is the skills seek. The first skill that fits wins. If none fit, plate recall returns a skill name or declines. The seek does not call a model. A stored lens that still points at the catalog is rewritten to that list before the seek. Wear and doctor fail when a fastened suit turns goggles off. (#390)
|
|
22
|
+
|
|
23
|
+
### Live inbox
|
|
24
|
+
|
|
25
|
+
A seat can ack an inbox line after the pull has merged or the line was dropped. (#375)
|
|
26
|
+
|
|
27
|
+
### Docs
|
|
28
|
+
|
|
29
|
+
Four broken repository links on the docs site are fixed. (#383)
|
|
30
|
+
|
|
31
|
+
The grok-bot notes cover the memory packet, the duplicate-agent guard, and no local builds. (#378)
|
|
32
|
+
|
|
33
|
+
### Skills
|
|
34
|
+
|
|
35
|
+
`draw-stamped-card` and the bifrost-storyboard recipe are in the catalog. (#370)
|
|
10
36
|
|
|
11
37
|
## [4.1.0] - 2026-10-15
|
|
12
38
|
|
package/dist/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
**4.1** — a suit that survives the context window
|
|
6
6
|
|
|
7
|
-
Bifrost is the live board. Goggles
|
|
7
|
+
Bifrost is the live board. Goggles views one plane. A search runs inside that card.
|
|
8
8
|
|
|
9
9
|
0xRay is a three-subsystem autonomous engine. The suit is the wear. Inference remembers. External Governance judges. The Autonomous Engine runs the work. The host you already run wears it: Grok, OpenCode, Hermes, OpenClaw, or Cursor. Memory, judgement, and payments come on with the suit. When the window closes, the next session wakes with the job, the page, and the laws.
|
|
10
10
|
|
|
@@ -59,7 +59,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
|
|
|
59
59
|
|
|
60
60
|
| Version | Highlights |
|
|
61
61
|
|---------|------------|
|
|
62
|
-
| **4.1.0** | Bifrost is the collector board. A cloud agent is a board row. A stuck card's L2 nudge goes to the CoS role. `live-inbox` requires `LIVE_URL`, `SEAT_KEYS_DIR`, and `LIVE_CURSORS`. Goggles
|
|
62
|
+
| **4.1.0** | Bifrost is the collector board. A cloud agent is a board row. A stuck card's L2 nudge goes to the CoS role. `live-inbox` requires `LIVE_URL`, `SEAT_KEYS_DIR`, and `LIVE_CURSORS`. Goggles views one plane. The card is in LENS.md. A search runs inside that card. |
|
|
63
63
|
| **4.0.43** | Confer completes only on a real PASS. Cursor gate events fail closed, except EACCES when a cloud wrapper cannot write dest. Gate C cannot be skipped. |
|
|
64
64
|
| **4.0.42** | Confer votes. Burst runs the swarm. |
|
|
65
65
|
| **4.0.41** | Wake cascade stays on the station module. A fresh wear fastens mill and inspect. Goggles records the worn package path. The live page plays the mesh in the browser. |
|
|
@@ -75,7 +75,7 @@ function copyDir(src, dest, relPath = "") {
|
|
|
75
75
|
async function installForOpencode(options = {}) {
|
|
76
76
|
const { frameworkLogger } = await import('../../core/framework-logger.js');
|
|
77
77
|
const { syncBuiltinSkills } = await import('./skill-install.js');
|
|
78
|
-
const { mintAfterWear
|
|
78
|
+
const { mintAfterWear } = await import('./foundry-mint-wear.js');
|
|
79
79
|
const wiring = loadWiring();
|
|
80
80
|
frameworkLogger.log('opencode-integration', 'install-start', 'info', { options });
|
|
81
81
|
const opencodeSource = path.join(__dirname, '..', '..', '..', '.opencode');
|
|
@@ -109,14 +109,8 @@ async function installForOpencode(options = {}) {
|
|
|
109
109
|
console.log('Use --force to reinstall.');
|
|
110
110
|
}
|
|
111
111
|
else {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
frameworkLogger.log('opencode-integration', 'opencode-copied', 'info', { destination: opencodeDest });
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
fs.mkdirSync(opencodeDest, { recursive: true });
|
|
118
|
-
frameworkLogger.log('opencode-integration', 'mill-plant-plugin', 'info', { destination: opencodeDest });
|
|
119
|
-
}
|
|
112
|
+
copyDir(opencodeSource, opencodeDest);
|
|
113
|
+
frameworkLogger.log('opencode-integration', 'opencode-copied', 'info', { destination: opencodeDest });
|
|
120
114
|
const pluginSource = path.join(__dirname, '..', '..', '..', 'dist', 'plugin', 'xray-codex-injection.js');
|
|
121
115
|
const pluginDest = path.join(opencodeDest, 'plugin', 'xray-codex-injection.js');
|
|
122
116
|
if (fs.existsSync(pluginSource)) {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync, cpSync, rmSync, statSync, unlinkSync, copyFileSync } from "fs";
|
|
2
2
|
import { join, basename, dirname } from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
|
-
import { createRequire } from "module";
|
|
5
4
|
import { execSync } from "child_process";
|
|
6
5
|
function getLocalRegistryPath() {
|
|
7
6
|
return join(process.cwd(), ".xray", "skill-registry.json");
|
|
@@ -485,9 +484,6 @@ export async function skillRegistryCommand(action, args) {
|
|
|
485
484
|
// Each platform's install command calls this to copy framework skills.
|
|
486
485
|
export function syncBuiltinSkills(targetSkillsDir, packageRoot) {
|
|
487
486
|
const root = packageRoot ?? join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
488
|
-
const millSuit = createRequire(import.meta.url)(join(root, "scripts/foundry/mint-suit.cjs"));
|
|
489
|
-
if (!millSuit.wantsCostume(process.cwd()))
|
|
490
|
-
return 0;
|
|
491
487
|
const candidateDirs = [
|
|
492
488
|
join(root, "dist", "skills"),
|
|
493
489
|
join(root, "src", "skills"),
|
|
@@ -500,7 +496,16 @@ export function syncBuiltinSkills(targetSkillsDir, packageRoot) {
|
|
|
500
496
|
if (!existsSync(targetSkillsDir))
|
|
501
497
|
mkdirSync(targetSkillsDir, { recursive: true });
|
|
502
498
|
for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
|
|
503
|
-
|
|
499
|
+
let linkedDir = false;
|
|
500
|
+
if (entry.isSymbolicLink()) {
|
|
501
|
+
try {
|
|
502
|
+
linkedDir = statSync(join(sourceDir, entry.name)).isDirectory();
|
|
503
|
+
}
|
|
504
|
+
catch {
|
|
505
|
+
linkedDir = false;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (!entry.isDirectory() && !linkedDir)
|
|
504
509
|
continue;
|
|
505
510
|
const skillMd = join(sourceDir, entry.name, "SKILL.md");
|
|
506
511
|
if (!existsSync(skillMd))
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Goggles on status and health.
|
|
3
|
-
*
|
|
3
|
+
* The line is whether the organ is worn.
|
|
4
4
|
*/
|
|
5
5
|
export type GogglesStatus = {
|
|
6
6
|
organPresent: boolean;
|
|
7
|
-
kind0Text: string;
|
|
8
|
-
kind0Quiet: boolean;
|
|
9
|
-
kind0Label: string;
|
|
10
7
|
organLine: string;
|
|
11
8
|
};
|
|
12
|
-
export declare function probeGoggles(packageRoot: string,
|
|
9
|
+
export declare function probeGoggles(packageRoot: string, _cwd: string): GogglesStatus;
|
|
13
10
|
export declare function formatGogglesStatus(probe: GogglesStatus): string[];
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Goggles on status and health.
|
|
3
|
-
*
|
|
3
|
+
* The line is whether the organ is worn.
|
|
4
4
|
*/
|
|
5
|
-
import { existsSync
|
|
5
|
+
import { existsSync } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
-
const WORN_PLANES = ["dichotomy", "syncopate", "synthesis", "digest", "triage", "loop"];
|
|
8
7
|
const ORGAN_PAIRS = [
|
|
9
8
|
["dist/integrations/hooks/goggles-pipeline.mjs", "dist/integrations/hooks/goggles-planes.json"],
|
|
10
9
|
["src/integrations/hooks/goggles-pipeline.mjs", "src/integrations/hooks/goggles-planes.json"],
|
|
@@ -17,60 +16,13 @@ function organPair(packageRoot) {
|
|
|
17
16
|
}
|
|
18
17
|
return null;
|
|
19
18
|
}
|
|
20
|
-
function
|
|
21
|
-
const
|
|
22
|
-
if (!existsSync(file))
|
|
23
|
-
return { found: false, text: "" };
|
|
24
|
-
try {
|
|
25
|
-
return { found: true, text: readFileSync(file, "utf8").trim() };
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
return { found: false, text: "" };
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function mapDrift(packageRoot, planesRel) {
|
|
32
|
-
try {
|
|
33
|
-
const data = JSON.parse(readFileSync(join(packageRoot, planesRel), "utf8"));
|
|
34
|
-
const map = Array.isArray(data.planes) ? data.planes.map((name) => String(name)) : [];
|
|
35
|
-
const same = map.length === WORN_PLANES.length && map.every((name, index) => name === WORN_PLANES[index]);
|
|
36
|
-
return same ? "" : "Actuality. Drift: worn is not the map.";
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
return "";
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
export function probeGoggles(packageRoot, cwd) {
|
|
43
|
-
const pair = organPair(packageRoot);
|
|
44
|
-
const organPresent = pair !== null;
|
|
45
|
-
const lens = lensText(cwd);
|
|
46
|
-
let kind0Text = "";
|
|
47
|
-
let kind0Label = "(no LENS yet)";
|
|
48
|
-
let kind0Quiet = false;
|
|
49
|
-
if (lens.found) {
|
|
50
|
-
kind0Text = lens.text;
|
|
51
|
-
if (!lens.text || lens.text === "quiet (match)") {
|
|
52
|
-
kind0Quiet = true;
|
|
53
|
-
kind0Label = "quiet (match)";
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
kind0Label = lens.text;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
else if (pair) {
|
|
60
|
-
const drift = mapDrift(packageRoot, pair[1]);
|
|
61
|
-
if (drift) {
|
|
62
|
-
kind0Text = drift;
|
|
63
|
-
kind0Label = drift;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
19
|
+
export function probeGoggles(packageRoot, _cwd) {
|
|
20
|
+
const organPresent = organPair(packageRoot) !== null;
|
|
66
21
|
return {
|
|
67
22
|
organPresent,
|
|
68
|
-
kind0Text,
|
|
69
|
-
kind0Quiet,
|
|
70
|
-
kind0Label,
|
|
71
23
|
organLine: organPresent ? "Goggles: worn" : "Goggles: not found",
|
|
72
24
|
};
|
|
73
25
|
}
|
|
74
26
|
export function formatGogglesStatus(probe) {
|
|
75
|
-
return [probe.organLine
|
|
27
|
+
return [probe.organLine];
|
|
76
28
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -79,7 +79,7 @@ program
|
|
|
79
79
|
process.exit(1);
|
|
80
80
|
}
|
|
81
81
|
});
|
|
82
|
-
const LOOK_HELP = "
|
|
82
|
+
const LOOK_HELP = "dev, integration, domain, or ecosystem. The card is in LENS.md.";
|
|
83
83
|
function gogglesScript() {
|
|
84
84
|
const built = join(packageRoot, "dist", "integrations", "hooks", "goggles-pipeline.mjs");
|
|
85
85
|
const source = join(packageRoot, "src", "integrations", "hooks", "goggles-pipeline.mjs");
|
|
@@ -104,7 +104,7 @@ function runGoggles(args) {
|
|
|
104
104
|
}
|
|
105
105
|
program
|
|
106
106
|
.command("look")
|
|
107
|
-
.argument("[args...]", "
|
|
107
|
+
.argument("[args...]", "one card plane")
|
|
108
108
|
.description(LOOK_HELP)
|
|
109
109
|
.action((args) => {
|
|
110
110
|
runGoggles(args);
|
|
@@ -22,7 +22,7 @@ export declare function preProcessAndRoute(operation: string, context: RuleValid
|
|
|
22
22
|
export declare const FOUNDRY_EXO_CANNOT_SHIP = "Exo cannot ship. Use: node scripts/node/release.mjs [patch|minor|major]";
|
|
23
23
|
/**
|
|
24
24
|
* Release keyword used to run version-manager + git add -A + npm publish from the exo.
|
|
25
|
-
* That path is refused. Canonical mill:
|
|
25
|
+
* That path is refused. Canonical mill: scripts/foundry/release.mjs.
|
|
26
26
|
*/
|
|
27
27
|
export declare function executeReleaseWorkflow(operation: string, _context: RuleValidationContext, jobId: string, _routing: RoutingRecommendation): Promise<EnforcementResult>;
|
|
28
28
|
export interface EnforcementResult {
|
|
@@ -203,7 +203,7 @@ function buildTaskDescription(operation, context) {
|
|
|
203
203
|
export const FOUNDRY_EXO_CANNOT_SHIP = "Exo cannot ship. Use: node scripts/node/release.mjs [patch|minor|major]";
|
|
204
204
|
/**
|
|
205
205
|
* Release keyword used to run version-manager + git add -A + npm publish from the exo.
|
|
206
|
-
* That path is refused. Canonical mill:
|
|
206
|
+
* That path is refused. Canonical mill: scripts/foundry/release.mjs.
|
|
207
207
|
*/
|
|
208
208
|
export async function executeReleaseWorkflow(operation, _context, jobId, _routing) {
|
|
209
209
|
await frameworkLogger.log("enforcer-tools", "release-workflow-refused", "error", {
|
|
@@ -34,7 +34,7 @@ Install the package first (`npm install`), then `npx 0xray wear`. Postinstall wr
|
|
|
34
34
|
|
|
35
35
|
| Hook | Stdin | Stdout |
|
|
36
36
|
|------|--------|--------|
|
|
37
|
-
| `preToolUse` | Cursor tool event (`tool_name`, `tool_input`, `cwd`, `workspace_roots`, `conversation_id`) | `{ "permission": "allow" \| "deny" }` plus `user_message` / `agent_message`
|
|
37
|
+
| `preToolUse` | Cursor tool event (`tool_name`, `tool_input`, `cwd`, `workspace_roots`, `conversation_id`) | `{ "permission": "allow" \| "deny" }` plus `user_message` / `agent_message` when the hook has something to say |
|
|
38
38
|
| `preCompact` | `{ trigger, context_tokens, conversation_id, generation_id, … }` | `{ "user_message": "…" }` after Station write. Receipt keeps `conversation_id` + `generation_id`. That id is enough to resume. |
|
|
39
39
|
| `afterFileEdit` | file event | `{}` — boots Station only |
|
|
40
40
|
|
|
@@ -48,6 +48,7 @@ function finish(root, permission, reason, hint, toolName, extra = {}) {
|
|
|
48
48
|
}
|
|
49
49
|
if (hint && permission === 'allow') {
|
|
50
50
|
out.user_message = hint;
|
|
51
|
+
out.agent_message = hint;
|
|
51
52
|
}
|
|
52
53
|
if (extra.hookSpecificOutput) out.hookSpecificOutput = extra.hookSpecificOutput;
|
|
53
54
|
console.log(JSON.stringify(out));
|
|
@@ -115,6 +116,9 @@ async function main() {
|
|
|
115
116
|
if (lensStop?.decision === 'deny') {
|
|
116
117
|
finish(gateRoot, 'deny', lensStop.reason, null, toolName, { gate: lensStop.gate });
|
|
117
118
|
}
|
|
119
|
+
if (lensStop?.decision === 'allow' && lensStop.reason) {
|
|
120
|
+
finish(gateRoot, 'allow', lensStop.reason, lensStop.reason, toolName, { gate: lensStop.gate });
|
|
121
|
+
}
|
|
118
122
|
const route = repertoireRoute([toolName, cmd, content].filter(Boolean).join(' '));
|
|
119
123
|
|
|
120
124
|
if (isShellTool(toolName) && cmd) {
|
|
@@ -80,17 +80,15 @@ export async function installForGrokCLI(options = {}) {
|
|
|
80
80
|
frameworkLogger.log('grok-integration', 'plugin-copied', 'info', { destination: dest });
|
|
81
81
|
console.log(`\x1b[32m✓ Copied Grok plugin to ${dest}\x1b[0m`);
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
console.log(`\x1b[32m✓ Synced ${skillsCopied} builtin skills to Grok plugin\x1b[0m`);
|
|
87
|
-
}
|
|
88
|
-
frameworkLogger.log('grok-integration', 'skills-synced', 'info', { count: skillsCopied });
|
|
83
|
+
const skillsCopied = syncBuiltinSkills(path.join(dest, 'skills'));
|
|
84
|
+
if (skillsCopied > 0) {
|
|
85
|
+
console.log(`\x1b[32m✓ Synced ${skillsCopied} builtin skills to Grok plugin\x1b[0m`);
|
|
89
86
|
}
|
|
87
|
+
frameworkLogger.log('grok-integration', 'skills-synced', 'info', { count: skillsCopied });
|
|
90
88
|
pinGrokPluginToInstalledDist(dest, packageRoot, targetDir);
|
|
91
89
|
wearGrokHookCommands(dest, packageRoot, targetDir);
|
|
92
90
|
}
|
|
93
|
-
if (isolated
|
|
91
|
+
if (isolated) {
|
|
94
92
|
const home = millSuit.processHome(env);
|
|
95
93
|
const globalCopied = syncBuiltinSkills(path.join(home, '.grok', 'skills'));
|
|
96
94
|
if (globalCopied > 0) {
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
retainCompactFields,
|
|
29
29
|
writeStationMarkdown,
|
|
30
30
|
} from '../../hooks/station-hook-runtime.mjs';
|
|
31
|
-
import { handCard } from '../../hooks/goggles-pipeline.mjs';
|
|
31
|
+
import { handCard, planeCard } from '../../hooks/goggles-pipeline.mjs';
|
|
32
32
|
|
|
33
33
|
export {
|
|
34
34
|
checkPendingDelegationGate,
|
|
@@ -315,6 +315,7 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
315
315
|
const existing = readExistingBoot(root);
|
|
316
316
|
const heat = applyStationHeat(root, extra.host || 'grok', extra, existing);
|
|
317
317
|
const compactHold = retainCompactFields(existing, extra);
|
|
318
|
+
const shown = planeCard(root);
|
|
318
319
|
return {
|
|
319
320
|
lead_dev_mode: features.lead_dev_mode,
|
|
320
321
|
no_new_surface: features.no_new_surface,
|
|
@@ -348,6 +349,8 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
348
349
|
hook: source,
|
|
349
350
|
source,
|
|
350
351
|
timestamp: new Date().toISOString(),
|
|
352
|
+
plane: shown.plane,
|
|
353
|
+
card: shown.card,
|
|
351
354
|
};
|
|
352
355
|
}
|
|
353
356
|
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
workspaceRoot,
|
|
22
22
|
} from './grok-hook-utils.js';
|
|
23
23
|
import { appendHookActivity } from './grok-hook-activity.js';
|
|
24
|
-
import {
|
|
24
|
+
import { lensBeforeResearch } from '../../hooks/goggles-pipeline.mjs';
|
|
25
25
|
import { repertoireDecisionFields, repertoireRoute } from '../../hooks/pre-tool-speak.mjs';
|
|
26
26
|
|
|
27
27
|
export { repertoireDecisionFields };
|
|
@@ -81,28 +81,14 @@ async function main() {
|
|
|
81
81
|
if (extraBlock) finish(eventRoot, 'deny', extraBlock, null, toolName);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
const stop = cardStop(
|
|
85
|
-
eventRoot,
|
|
86
|
-
toolName,
|
|
87
|
-
[cmd, content, toolInput.pattern, toolInput.query, ...(ctx.paths || [])].filter(Boolean).join('\n'),
|
|
88
|
-
ctx.paths || [],
|
|
89
|
-
toolInput,
|
|
90
|
-
);
|
|
91
|
-
if (stop?.decision === 'deny') {
|
|
92
|
-
finish(eventRoot, 'deny', stop.reason, null, toolName, { gate: stop.gate });
|
|
93
|
-
}
|
|
94
|
-
if (stop?.decision === 'allow') {
|
|
95
|
-
finish(eventRoot, 'allow', null, null, toolName, {
|
|
96
|
-
gate: stop.gate,
|
|
97
|
-
hookSpecificOutput: stop.hookSpecificOutput,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
|
|
101
84
|
const spoken = [cmd, content, toolInput.pattern, toolInput.query, ...(ctx.paths || [])].filter(Boolean).join('\n');
|
|
102
85
|
const lensStop = lensBeforeResearch(eventRoot, toolName, spoken);
|
|
103
86
|
if (lensStop?.decision === 'deny') {
|
|
104
87
|
finish(eventRoot, 'deny', lensStop.reason, null, toolName, { gate: lensStop.gate });
|
|
105
88
|
}
|
|
89
|
+
if (lensStop?.decision === 'allow' && lensStop.reason) {
|
|
90
|
+
finish(eventRoot, 'allow', lensStop.reason, lensStop.reason, toolName, { gate: lensStop.gate });
|
|
91
|
+
}
|
|
106
92
|
|
|
107
93
|
const route = repertoireRoute([toolName, cmd, content].filter(Boolean).join(' '));
|
|
108
94
|
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
runInferenceImprovementLight,
|
|
25
25
|
} from '../../hooks/pipeline-hook-runtime.mjs';
|
|
26
26
|
import { maintainLens } from '../../hooks/goggles-pipeline.mjs';
|
|
27
|
-
import { readSavedFreshness, refreshFreshness } from '../../../nucleus/work-freshness.mjs';
|
|
27
|
+
import { freshnessNeedsRefresh, readSavedFreshness, refreshFreshness } from '../../../nucleus/work-freshness.mjs';
|
|
28
28
|
|
|
29
29
|
function extractIntent(event) {
|
|
30
30
|
return event.prompt || event.userMessage || event.user_prompt || event.compactContext || null;
|
|
@@ -137,7 +137,9 @@ async function main() {
|
|
|
137
137
|
let freshnessLine = null;
|
|
138
138
|
if (!compact) {
|
|
139
139
|
try {
|
|
140
|
-
|
|
140
|
+
const refresh = HOOK_EVENT === 'session_start'
|
|
141
|
+
|| (HOOK_EVENT === 'user_prompt_submit' && freshnessNeedsRefresh(eventRoot));
|
|
142
|
+
freshnessLine = refresh
|
|
141
143
|
? refreshFreshness(eventRoot).freshnessLine
|
|
142
144
|
: readSavedFreshness(eventRoot);
|
|
143
145
|
} catch {
|
|
@@ -920,7 +920,7 @@ async function handleDelegationGate(command, projectRoot, logDir) {
|
|
|
920
920
|
const spoken = `${tool} ${JSON.stringify(args)}`.slice(0, 500);
|
|
921
921
|
const { lensDecision, repertoireRoute } = await import("../hooks/pre-tool-speak.mjs");
|
|
922
922
|
const lens = lensDecision(projectRoot, tool, spoken);
|
|
923
|
-
if (lens) {
|
|
923
|
+
if (lens?.decision === "deny") {
|
|
924
924
|
return {
|
|
925
925
|
allow: false,
|
|
926
926
|
phase: "pre",
|
|
@@ -928,6 +928,9 @@ async function handleDelegationGate(command, projectRoot, logDir) {
|
|
|
928
928
|
reason: lens.reason,
|
|
929
929
|
};
|
|
930
930
|
}
|
|
931
|
+
if (lens?.decision === "allow" && lens.reason) {
|
|
932
|
+
return { phase: "pre", ...outcome, gate: "lens", reason: lens.reason };
|
|
933
|
+
}
|
|
931
934
|
const route = repertoireRoute(spoken);
|
|
932
935
|
return { phase: "pre", ...outcome, ...(route || {}) };
|
|
933
936
|
} catch (error) {
|