0xray 4.0.25 → 4.0.27
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 +1 -1
- package/.opencode/skills/orchestrator/SKILL.md +5 -5
- package/.opencode/skills/storyteller/SKILL.md +1 -1
- package/.xray/features.json +1 -1
- package/AGENTS.md +1 -1
- package/README.md +1 -0
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +1 -1
- package/dist/CHANGELOG.md +42 -0
- package/dist/README.md +1 -0
- package/dist/SKILLS.md +1 -1
- package/dist/cli/commands/mcp-install.d.ts +12 -0
- package/dist/cli/commands/mcp-install.js +38 -2
- package/dist/integrations/cursor/README.md +6 -2
- package/dist/integrations/cursor/hooks/cursor-hook-utils.js +82 -7
- package/dist/integrations/cursor/hooks/cursor-usage-receipt.js +94 -1
- package/dist/integrations/cursor/hooks/pre-compact.js +27 -3
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/memory-routing/record-lesson.d.ts +7 -2
- package/dist/memory-routing/record-lesson.js +37 -3
- package/dist/skills/orchestrator/SKILL.md +5 -5
- package/dist/skills/storyteller/SKILL.md +1 -1
- package/llms.txt +5 -1
- package/package.json +3 -2
- package/scripts/foundry/reconcile-version.mjs +24 -4
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/skills/orchestrator/SKILL.md +5 -5
- package/src/skills/storyteller/SKILL.md +1 -1
- package/xray/features.json +1 -1
package/.grok-plugin/plugin.json
CHANGED
|
@@ -62,7 +62,7 @@ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
|
|
|
62
62
|
|
|
63
63
|
## Lead cadence (syncopation)
|
|
64
64
|
|
|
65
|
-
The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/
|
|
65
|
+
The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`).
|
|
66
66
|
|
|
67
67
|
Jargon is not the job. Review and cadence ask whether the change works. Do not spend the loop reciting dest names, mill liturgy, or host mantras.
|
|
68
68
|
|
|
@@ -76,8 +76,8 @@ Jargon is not the job. Review and cadence ask whether the change works. Do not s
|
|
|
76
76
|
- **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
|
|
77
77
|
- **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
|
|
78
78
|
- **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
|
|
79
|
-
- **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `
|
|
80
|
-
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture.
|
|
79
|
+
- **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `grok-bot/OP-PROC.md` (team specifics live in `house/`). Do not paste a command novel. When a law is spoken twice, encode it this wake.
|
|
80
|
+
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Memory scoring rules: [docs/memory-scoring.md](https://github.com/0xRayAI/xray/blob/main/docs/memory-scoring.md).
|
|
81
81
|
- **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
|
|
82
82
|
- **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
|
|
83
83
|
|
|
@@ -96,7 +96,7 @@ This suite is the engine that builds the engine. When a seat sees OP-PROC, write
|
|
|
96
96
|
|
|
97
97
|
Operating planes: code, OP-PROC, model, suit, mill, host, and test/ship. Test/ship is the critical OP-PROC plane. Test then ship is the hero. Ship without that proof is the catastrophe. Long-term memory is the project law list. Each wake refreshes a changed stack definition and keeps observation stats. Heat writes the matched names onto Station, the short-term card that survives compaction. Reactive decisions move out of TypeScript into OP-PROC as the model improves. That move is why the mill and the suit exist. It is not fully proved. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish. Do not freeze the live cut.
|
|
98
98
|
- **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
|
|
99
|
-
- **Board:** critic Strict comments;
|
|
99
|
+
- **Board:** critic Strict comments; the implementer implements; lead stays main thread.
|
|
100
100
|
- **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
|
|
101
|
-
- **Ship matrix:** `
|
|
101
|
+
- **Ship matrix:** `grok-bot/OP-PROC.md` Decision matrix (team specifics live in `house/`) — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
|
|
102
102
|
- **Metamorphosis:** LLM → OP-PROC is in-context worn seats (same critic, same dummy, resume only). Not more bots.
|
|
@@ -96,7 +96,7 @@ codex_terms: [5, 7, 32] # Related Codex term numbers
|
|
|
96
96
|
```markdown
|
|
97
97
|
## What Next?
|
|
98
98
|
|
|
99
|
-
- Related Codex terms: [codex.json](
|
|
99
|
+
- Related Codex terms: [codex.json](../../../.xray/codex.json)
|
|
100
100
|
- Next story to write: [suggestion]
|
|
101
101
|
```
|
|
102
102
|
|
package/.xray/features.json
CHANGED
package/AGENTS.md
CHANGED
|
@@ -12,7 +12,7 @@ Quick reference for the xray AI orchestration framework (**4.0**).
|
|
|
12
12
|
|
|
13
13
|
Before other work, Read `.xray/state/STATION.md`. Compaction and host change are the same cut. Continue the card. Do not restart the job. Grok does not inject the card (OpenCode does) — this Read is the Grok contract. Do not thicken the Grok exo.
|
|
14
14
|
|
|
15
|
-
**Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`
|
|
15
|
+
**Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`grok-bot/OP-PROC.md` Decision matrix) — green CI is not ship. npm OTP in a browser, then poll the new version before moving on. Loop until Station is done. Live ticks and moving workstreams — not idle pacers. Same critic (resume only). Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`). Playbook: `orchestrator` skill.
|
|
16
16
|
|
|
17
17
|
## What is xray?
|
|
18
18
|
|
package/README.md
CHANGED
|
@@ -52,6 +52,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
|
|
|
52
52
|
| Version | Highlights |
|
|
53
53
|
|---------|------------|
|
|
54
54
|
| **Unreleased** | Fasten is **foundry-plant/0**: builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill declares (looker / vibe / mixer live in the mill). Nested mill `@0xray/foundry@0.1.12`. CLI shims `foundry blip\|sound` remain (0.1.11+). Shop plant first-class (`shop-extract`, `shop-witness`, `shop-pin` + `foundry.json` `shopPlant`). |
|
|
55
|
+
| **4.0.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. Not published. |
|
|
55
56
|
| **4.0.9** | Mill target: postinstall does not mill npm global prefix or `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. |
|
|
56
57
|
| **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) |
|
|
57
58
|
| **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. |
|
package/SKILLS.md
CHANGED
|
@@ -76,7 +76,7 @@ xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) as the **costume /
|
|
|
76
76
|
|
|
77
77
|
| Skill | Agent | Description |
|
|
78
78
|
|-------|-------|-------------|
|
|
79
|
-
| `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads
|
|
79
|
+
| `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads `grok-bot/OP-PROC.md`; ship matrix A–D in `grok-bot/OP-PROC.md`; team specifics live in `house/`) |
|
|
80
80
|
| `xray-orchestrator` | — | xray orchestration skill (MCP orchestrator surface) |
|
|
81
81
|
| `processor-pipeline` | — | Data processing pipeline management |
|
|
82
82
|
| `boot-orchestrator` | — | Framework boot orchestration |
|
package/dist/AGENTS.md
CHANGED
|
@@ -12,7 +12,7 @@ Quick reference for the xray AI orchestration framework (**4.0**).
|
|
|
12
12
|
|
|
13
13
|
Before other work, Read `.xray/state/STATION.md`. Compaction and host change are the same cut. Continue the card. Do not restart the job. Grok does not inject the card (OpenCode does) — this Read is the Grok contract. Do not thicken the Grok exo.
|
|
14
14
|
|
|
15
|
-
**Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`
|
|
15
|
+
**Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`grok-bot/OP-PROC.md` Decision matrix) — green CI is not ship. npm OTP in a browser, then poll the new version before moving on. Loop until Station is done. Live ticks and moving workstreams — not idle pacers. Same critic (resume only). Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`). Playbook: `orchestrator` skill.
|
|
16
16
|
|
|
17
17
|
## What is xray?
|
|
18
18
|
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -41,6 +41,48 @@ 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.27] - 2026-09-25
|
|
45
|
+
|
|
46
|
+
Next patch after npm `4.0.26`. Released 2026-09-26.
|
|
47
|
+
|
|
48
|
+
A counted host compact needs a non-empty generation id and a numeric `context_usage_percent`. That hook line and per-session receipt are written on the suit mill and mirrored onto nested consumer wear roots. Memory scoring rules live in `docs/memory-scoring.md`. The orchestrator links that file and does not copy the rules. Companion package `@0xray/grok-bot@0.1.6`: one general operating page, a `house/` overlay that is not in that npm pack, `templates/house/` in the pack, `grok-bot house init` (copy, refuse to overwrite), and doctor lookup via `GROK_BOT_HOUSE` or a walk-up for `house/HOUSE.md`.
|
|
49
|
+
|
|
50
|
+
### 🔄 Changes
|
|
51
|
+
|
|
52
|
+
### 🐛 Bug Fixes
|
|
53
|
+
- fix: a host compact proof requires a non-empty generation id and a numeric context_usage_percent (d869cbf79)
|
|
54
|
+
- fix: mirror preCompact proof to nested consumer wear roots (16b7481af)
|
|
55
|
+
|
|
56
|
+
### 📚 Documentation
|
|
57
|
+
- feat(grok-bot): house init and shared house lookup (#128) (0f93687f2)
|
|
58
|
+
- General operating page for grok-bot, with a fill-in house (#124) (17e02c5a7)
|
|
59
|
+
- docs: orchestrator links memory-scoring (#127) (bca04dba8)
|
|
60
|
+
- docs: add ben-proof suited compaction bench harness (13284b9d8)
|
|
61
|
+
- docs: core audit fixes and a readable memory-scoring doc (#126) (23b370d1e)
|
|
62
|
+
- docs: point 0xray at grok-bot/OP-PROC.md (#125) (53b1889dc)
|
|
63
|
+
|
|
64
|
+
### 🔎 Other Changes
|
|
65
|
+
- docs(grok-bot): OP-PROC amendment (Blaze 10:31) + moltbook push allow (#123) (a2abed78c)
|
|
66
|
+
- docs(grok-bot): OP-PROC one-page front door + WAVEBOARD/ATTENTION_STATE mirror (#122) (519b2dae0)
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## [4.0.26] - 2026-09-25
|
|
71
|
+
|
|
72
|
+
### 🔄 Changes
|
|
73
|
+
|
|
74
|
+
### 🐛 Bug Fixes
|
|
75
|
+
- fix: store a lesson when the task matches no signal (e3c75b43d)
|
|
76
|
+
- fix: prove a Cursor compact cut with a session log and per-session receipt (bb3a1c68f)
|
|
77
|
+
- fix: mill check accepts a published version; mcp:status runs (a8bd79e23)
|
|
78
|
+
|
|
79
|
+
### 🔎 Other Changes
|
|
80
|
+
- Merge pull request #116 from 0xRayAI/cursor/mill-ci-mcp-status-fbe0 (ba94508d2)
|
|
81
|
+
- Merge pull request #120 from 0xRayAI/cursor/lesson-recall-fbe0 (8f4a5a62a)
|
|
82
|
+
- Merge pull request #119 from 0xRayAI/cursor/compact-receipt-proof-fbe0 (a911fd17b)
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
44
86
|
## [4.0.25] - 2026-09-24
|
|
45
87
|
|
|
46
88
|
`0xray@4.0.25` ships the plate schematics in the package. `docs-site/docs/plates/` is on the npm `files` list. A worn suit resolves `memory-recall` and `processor` from `dist/integrations/hooks/plates.cjs`.
|
package/dist/README.md
CHANGED
|
@@ -52,6 +52,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
|
|
|
52
52
|
| Version | Highlights |
|
|
53
53
|
|---------|------------|
|
|
54
54
|
| **Unreleased** | Fasten is **foundry-plant/0**: builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill declares (looker / vibe / mixer live in the mill). Nested mill `@0xray/foundry@0.1.12`. CLI shims `foundry blip\|sound` remain (0.1.11+). Shop plant first-class (`shop-extract`, `shop-witness`, `shop-pin` + `foundry.json` `shopPlant`). |
|
|
55
|
+
| **4.0.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. Not published. |
|
|
55
56
|
| **4.0.9** | Mill target: postinstall does not mill npm global prefix or `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. |
|
|
56
57
|
| **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) |
|
|
57
58
|
| **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. |
|
package/dist/SKILLS.md
CHANGED
|
@@ -76,7 +76,7 @@ xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) as the **costume /
|
|
|
76
76
|
|
|
77
77
|
| Skill | Agent | Description |
|
|
78
78
|
|-------|-------|-------------|
|
|
79
|
-
| `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads
|
|
79
|
+
| `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads `grok-bot/OP-PROC.md`; ship matrix A–D in `grok-bot/OP-PROC.md`; team specifics live in `house/`) |
|
|
80
80
|
| `xray-orchestrator` | — | xray orchestration skill (MCP orchestrator surface) |
|
|
81
81
|
| `processor-pipeline` | — | Data processing pipeline management |
|
|
82
82
|
| `boot-orchestrator` | — | Framework boot orchestration |
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
export type McpInstallerAction = {
|
|
2
|
+
kind: "list" | "status" | "help";
|
|
3
|
+
} | {
|
|
4
|
+
kind: "install" | "remove";
|
|
5
|
+
name?: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "unknown";
|
|
8
|
+
command: string;
|
|
9
|
+
};
|
|
10
|
+
/** Colon and hyphen forms documented on `npx 0xray` map to the bare dispatcher verbs. */
|
|
11
|
+
export declare function normalizeMcpInstallerToken(command: string | undefined): string | undefined;
|
|
12
|
+
export declare function classifyMcpInstallerArgs(args: readonly string[]): McpInstallerAction;
|
|
1
13
|
export declare function listMCPsCommand(): void;
|
|
2
14
|
export declare function showMCPStatusCommand(): void;
|
|
3
15
|
export declare function installMCPCommand(name: string): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } from "fs";
|
|
2
|
-
import { join, dirname } from "path";
|
|
2
|
+
import { join, dirname, resolve } from "path";
|
|
3
3
|
import { execSync } from "child_process";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
4
5
|
import { getConfigDir } from "../../core/config-paths.js";
|
|
5
6
|
function getMCPConfigPath() {
|
|
6
7
|
return join(process.cwd(), ".xray", "mcp-registry.json");
|
|
@@ -186,9 +187,44 @@ function removeMCP(name) {
|
|
|
186
187
|
saveInstalledMCPs(installed);
|
|
187
188
|
console.log(`\n✅ Removed ${name}`);
|
|
188
189
|
}
|
|
190
|
+
const MCP_INSTALLER_ALIASES = {
|
|
191
|
+
"mcp:list": "list",
|
|
192
|
+
"mcp-list": "list",
|
|
193
|
+
"mcp:status": "status",
|
|
194
|
+
"mcp-status": "status",
|
|
195
|
+
"mcp:install": "install",
|
|
196
|
+
"mcp-install": "install",
|
|
197
|
+
"mcp:remove": "remove",
|
|
198
|
+
"mcp-remove": "remove",
|
|
199
|
+
};
|
|
200
|
+
/** Colon and hyphen forms documented on `npx 0xray` map to the bare dispatcher verbs. */
|
|
201
|
+
export function normalizeMcpInstallerToken(command) {
|
|
202
|
+
if (command === undefined)
|
|
203
|
+
return undefined;
|
|
204
|
+
return MCP_INSTALLER_ALIASES[command] ?? command;
|
|
205
|
+
}
|
|
206
|
+
export function classifyMcpInstallerArgs(args) {
|
|
207
|
+
const raw = args[0];
|
|
208
|
+
const command = normalizeMcpInstallerToken(raw);
|
|
209
|
+
if (command === undefined || command === "status")
|
|
210
|
+
return { kind: "status" };
|
|
211
|
+
if (command === "list")
|
|
212
|
+
return { kind: "list" };
|
|
213
|
+
if (command === "help" || command === "--help" || command === "-h")
|
|
214
|
+
return { kind: "help" };
|
|
215
|
+
if (command === "install" || command === "remove") {
|
|
216
|
+
const name = args[1];
|
|
217
|
+
return name === undefined ? { kind: command } : { kind: command, name };
|
|
218
|
+
}
|
|
219
|
+
return { kind: "unknown", command: raw ?? command };
|
|
220
|
+
}
|
|
221
|
+
const isDirectRun = process.argv[1] !== undefined &&
|
|
222
|
+
resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
189
223
|
async function main() {
|
|
224
|
+
if (!isDirectRun)
|
|
225
|
+
return;
|
|
190
226
|
const args = process.argv.slice(2);
|
|
191
|
-
const command = args[0];
|
|
227
|
+
const command = normalizeMcpInstallerToken(args[0]);
|
|
192
228
|
switch (command) {
|
|
193
229
|
case "list":
|
|
194
230
|
listMCPs();
|
|
@@ -25,7 +25,7 @@ Copy the consumer template from `src/integrations/cursor/hooks/hooks.json` and t
|
|
|
25
25
|
|
|
26
26
|
`preCompact` labels `event_class`:
|
|
27
27
|
|
|
28
|
-
- `cursor-host-precompact` — Cursor actually fired the hook
|
|
28
|
+
- `cursor-host-precompact` — Cursor actually fired the hook. The event must carry a non-empty `generation_id` and a numeric `context_usage_percent`, plus the hook name or trigger. A token count or `trigger: auto` alone stays synthetic and does not write `cursor-hook.log` or `cursor-receipts/<sessionId>.json`.
|
|
29
29
|
- `cursor-precompact-synthetic` — script invoked with `--event-class=cursor-precompact-synthetic` (Path C fallback)
|
|
30
30
|
- `cursor-host-precompact-FAIL` — HOST-FIRE fill ran; host did not spawn `preCompact` (see `RECEIPT-HOST-PRECOMPACT.md`, `-2.md`, `-3.md`)
|
|
31
31
|
- First live host fire (Arm S): `examples/killer-dual/RECEIPT-HOST-PRECOMPACT.md`
|
|
@@ -40,7 +40,11 @@ Do **not** prove window pressure with UTF-8 chars÷4. `src/integrations/cursor/h
|
|
|
40
40
|
| `cursor-cloud` `run-info` / `get-events` / dashboard (model, bc-id, window) | yes — token MISS is honest |
|
|
41
41
|
| chars÷4, fill-only, `fillBytes` | **forbidden** (`ok: false`) |
|
|
42
42
|
|
|
43
|
-
Host `preCompact` fire is counted from `.xray/state/cursor-hook-invoke.log` (`event=preCompact`). Do not hand-invoke `pre-compact.js` to mint that Y.
|
|
43
|
+
Host `preCompact` fire is counted from `.xray/state/cursor-hook-invoke.log` (`event=preCompact`). Do not hand-invoke `pre-compact.js` to mint that Y. That invoke log has no session id.
|
|
44
|
+
|
|
45
|
+
A cut counts only when `.xray/state/cursor-receipts/<sessionId>.json` exists **and** `.xray/state/cursor-hook.log` contains a line with that same session id (timestamp, `context_tokens`, `context_usage_percent`, `context_window_size`, `generation_id`). `probeLogExists` is true only when that append succeeded. `.xray/state/cursor-usage-receipt.json` and `cursor-precompact.json` keep only the newest event. That single latest json is not enough — the next arm overwrites it.
|
|
46
|
+
|
|
47
|
+
Nested consumer benches under `examples/` (e.g. `examples/ben-proof/suited` with local `node_modules/0xray`) receive the same hook log line and per-session receipt as the mill — `preCompact` has no Read paths, so those wear roots are discovered from the suit mill at compact time.
|
|
44
48
|
|
|
45
49
|
Arm S landscape + receipt: `examples/killer-dual/`.
|
|
46
50
|
|
|
@@ -53,6 +53,11 @@ export {
|
|
|
53
53
|
FORBIDDEN_USAGE_METHODS,
|
|
54
54
|
invokeProbeLogPath,
|
|
55
55
|
cursorUsageReceiptPath,
|
|
56
|
+
cursorHookLogPath,
|
|
57
|
+
sanitizeSessionReceiptId,
|
|
58
|
+
cursorSessionReceiptPath,
|
|
59
|
+
appendCursorCompactProofLog,
|
|
60
|
+
writeCursorSessionReceipt,
|
|
56
61
|
parseInvokeProbeLog,
|
|
57
62
|
hostUsageFromPreCompactEvent,
|
|
58
63
|
classifyUsageCite,
|
|
@@ -182,6 +187,73 @@ export function cursorHeatRoots(event = {}) {
|
|
|
182
187
|
return out;
|
|
183
188
|
}
|
|
184
189
|
|
|
190
|
+
function isNestedConsumerWearRoot(root, millRoot) {
|
|
191
|
+
if (!root || !millRoot) return false;
|
|
192
|
+
const resolved = path.resolve(String(root));
|
|
193
|
+
const millResolved = path.resolve(String(millRoot));
|
|
194
|
+
if (resolved === millResolved) return false;
|
|
195
|
+
if (!heatRootHasCard(resolved) || !isHeatRootWritable(resolved)) return false;
|
|
196
|
+
const wornRay = path.join(resolved, 'node_modules', '0xray', 'package.json');
|
|
197
|
+
if (!fs.existsSync(wornRay)) return false;
|
|
198
|
+
if (!resolved.startsWith(millResolved + path.sep)) return false;
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Nested consumer benches (e.g. examples/ben-proof/suited) wear 0xray locally.
|
|
204
|
+
* preCompact stdin has no Read paths, so cursorHeatRoots never visits those dirs.
|
|
205
|
+
*/
|
|
206
|
+
export function discoverNestedConsumerWearRoots(millRoot) {
|
|
207
|
+
const millResolved = path.resolve(String(millRoot));
|
|
208
|
+
if (packageNameAt(millResolved) !== '0xray') return [];
|
|
209
|
+
const out = [];
|
|
210
|
+
const seen = new Set();
|
|
211
|
+
const queue = [path.join(millResolved, 'examples')];
|
|
212
|
+
let steps = 0;
|
|
213
|
+
while (queue.length > 0 && steps < 500) {
|
|
214
|
+
steps += 1;
|
|
215
|
+
const dir = queue.shift();
|
|
216
|
+
if (!dir || !fs.existsSync(dir)) continue;
|
|
217
|
+
let entries;
|
|
218
|
+
try {
|
|
219
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
220
|
+
} catch {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
for (const ent of entries) {
|
|
224
|
+
if (!ent.isDirectory()) continue;
|
|
225
|
+
if (ent.name === 'node_modules' || ent.name === '.git' || ent.name === 'dist') continue;
|
|
226
|
+
const full = path.join(dir, ent.name);
|
|
227
|
+
if (isNestedConsumerWearRoot(full, millResolved) && !seen.has(full)) {
|
|
228
|
+
seen.add(full);
|
|
229
|
+
out.push(full);
|
|
230
|
+
}
|
|
231
|
+
queue.push(full);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return out;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/** Mill heat roots plus nested consumer wear sites that share the same compact proof. */
|
|
238
|
+
export function cursorCompactProofRoots(event = {}) {
|
|
239
|
+
const seen = new Set();
|
|
240
|
+
const out = [];
|
|
241
|
+
for (const root of cursorHeatRoots(event)) {
|
|
242
|
+
const resolved = path.resolve(String(root));
|
|
243
|
+
if (seen.has(resolved)) continue;
|
|
244
|
+
seen.add(resolved);
|
|
245
|
+
out.push(resolved);
|
|
246
|
+
if (packageNameAt(resolved) !== '0xray') continue;
|
|
247
|
+
for (const worn of discoverNestedConsumerWearRoots(resolved)) {
|
|
248
|
+
const wornResolved = path.resolve(String(worn));
|
|
249
|
+
if (seen.has(wornResolved)) continue;
|
|
250
|
+
seen.add(wornResolved);
|
|
251
|
+
out.push(wornResolved);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
|
|
185
257
|
function packageNameAt(root) {
|
|
186
258
|
try {
|
|
187
259
|
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
@@ -204,6 +276,7 @@ export function cursorGateRoot(heatRoots, eventRoot) {
|
|
|
204
276
|
export function cursorSessionId(event = {}) {
|
|
205
277
|
return (
|
|
206
278
|
event.conversation_id ||
|
|
279
|
+
event.conversationId ||
|
|
207
280
|
event.session_id ||
|
|
208
281
|
event.sessionId ||
|
|
209
282
|
process.env.CURSOR_CONVERSATION_ID ||
|
|
@@ -258,13 +331,15 @@ export function classifyPreCompactEvent(event = {}, argv = process.argv) {
|
|
|
258
331
|
if (fromEvent) return fromEvent;
|
|
259
332
|
|
|
260
333
|
const named = event.hook_event_name || event.hookEventName || event.hook;
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
334
|
+
const hookNamed = named === 'preCompact' || named === 'pre_compact';
|
|
335
|
+
const triggerNamed = event.trigger === 'auto' || event.trigger === 'manual';
|
|
336
|
+
const generation = event.generation_id || event.generationId;
|
|
337
|
+
const hasGeneration = typeof generation === 'string' && generation.trim().length > 0;
|
|
338
|
+
const hasPercent = typeof event.context_usage_percent === 'number';
|
|
339
|
+
// A token count or trigger alone is not a host fire. The 2026-09-25 20:28
|
|
340
|
+
// line had context_tokens 120000 and window 200000 with no generation id,
|
|
341
|
+
// no usage percent, and no preCompact invoke.
|
|
342
|
+
const looksHost = (hookNamed || triggerNamed) && hasGeneration && hasPercent;
|
|
268
343
|
return looksHost ? EVENT_CLASS_HOST : EVENT_CLASS_SYNTHETIC;
|
|
269
344
|
}
|
|
270
345
|
|
|
@@ -28,6 +28,70 @@ export function cursorUsageReceiptPath(root) {
|
|
|
28
28
|
return path.join(root, '.xray', 'state', 'cursor-usage-receipt.json');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/** Proof log. A cut is greppable here; cursor-hook-invoke.log has no session id. */
|
|
32
|
+
export function cursorHookLogPath(root) {
|
|
33
|
+
return path.join(root, '.xray', 'state', 'cursor-hook.log');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function logToken(value) {
|
|
37
|
+
if (value == null) return '';
|
|
38
|
+
return String(value).replace(/[\r\n]+/g, '');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Safe filename segment for `.xray/state/cursor-receipts/<id>.json`.
|
|
43
|
+
* Empty when the id cannot be kept inside that directory.
|
|
44
|
+
*/
|
|
45
|
+
export function sanitizeSessionReceiptId(sessionId) {
|
|
46
|
+
const raw = typeof sessionId === 'string' ? sessionId.trim() : '';
|
|
47
|
+
if (!raw) return '';
|
|
48
|
+
const safe = raw
|
|
49
|
+
.replace(/\0/g, '')
|
|
50
|
+
.replace(/[/\\]/g, '_')
|
|
51
|
+
.replace(/\.\./g, '_')
|
|
52
|
+
.replace(/[^A-Za-z0-9._-]+/g, '_')
|
|
53
|
+
.replace(/^[._]+/, '')
|
|
54
|
+
.replace(/[._]+$/g, '');
|
|
55
|
+
if (!safe || safe === '.' || safe === '..') return '';
|
|
56
|
+
return safe.slice(0, 180);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function cursorSessionReceiptPath(root, sessionId) {
|
|
60
|
+
const safe = sanitizeSessionReceiptId(sessionId);
|
|
61
|
+
if (!safe) return null;
|
|
62
|
+
return path.join(root, '.xray', 'state', 'cursor-receipts', `${safe}.json`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Append one preCompact proof line. True only when the append landed and
|
|
67
|
+
* the file contains that session id (grep of *.log can find the cut).
|
|
68
|
+
*/
|
|
69
|
+
export function appendCursorCompactProofLog(root, fields = {}) {
|
|
70
|
+
const sessionId = logToken(fields.sessionId);
|
|
71
|
+
const timestamp = logToken(fields.timestamp) || new Date().toISOString();
|
|
72
|
+
const line = [
|
|
73
|
+
`ts=${timestamp}`,
|
|
74
|
+
`session_id=${sessionId}`,
|
|
75
|
+
`context_tokens=${logToken(fields.context_tokens)}`,
|
|
76
|
+
`context_usage_percent=${logToken(fields.context_usage_percent)}`,
|
|
77
|
+
`context_window_size=${logToken(fields.context_window_size)}`,
|
|
78
|
+
`generation_id=${logToken(fields.generation_id)}`,
|
|
79
|
+
].join(' ');
|
|
80
|
+
const dest = cursorHookLogPath(root);
|
|
81
|
+
try {
|
|
82
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
83
|
+
fs.appendFileSync(dest, `${line}\n`);
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (!sessionId) return false;
|
|
88
|
+
try {
|
|
89
|
+
return fs.readFileSync(dest, 'utf8').includes(`session_id=${sessionId}`);
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
31
95
|
export function parseInvokeProbeLog(root) {
|
|
32
96
|
const dest = invokeProbeLogPath(root);
|
|
33
97
|
const counts = { preToolUse: 0, preCompact: 0, afterFileEdit: 0, unknown: 0 };
|
|
@@ -228,7 +292,7 @@ export function buildCursorUsageReceipt(root, input = {}) {
|
|
|
228
292
|
preToolUseCount: probe.counts.preToolUse,
|
|
229
293
|
afterFileEditCount: probe.counts.afterFileEdit,
|
|
230
294
|
eventClass,
|
|
231
|
-
probeLogExists:
|
|
295
|
+
probeLogExists: input.probeLogExists === true,
|
|
232
296
|
},
|
|
233
297
|
usage,
|
|
234
298
|
repertoire,
|
|
@@ -299,3 +363,32 @@ export function writeCursorUsageReceipt(root, input = {}) {
|
|
|
299
363
|
return null;
|
|
300
364
|
}
|
|
301
365
|
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Per-session copy of the latest precompact + usage receipts.
|
|
369
|
+
* The next arm overwrites cursor-precompact.json and cursor-usage-receipt.json.
|
|
370
|
+
*/
|
|
371
|
+
export function writeCursorSessionReceipt(root, sessionId, paths = {}) {
|
|
372
|
+
const dest = cursorSessionReceiptPath(root, sessionId);
|
|
373
|
+
if (!dest) return null;
|
|
374
|
+
if (!paths.precompactPath && !paths.usagePath) return null;
|
|
375
|
+
try {
|
|
376
|
+
const payload = {
|
|
377
|
+
sessionId: typeof sessionId === 'string' ? sessionId : null,
|
|
378
|
+
precompact: null,
|
|
379
|
+
usage: null,
|
|
380
|
+
};
|
|
381
|
+
if (paths.precompactPath && fs.existsSync(paths.precompactPath)) {
|
|
382
|
+
payload.precompact = JSON.parse(fs.readFileSync(paths.precompactPath, 'utf8'));
|
|
383
|
+
}
|
|
384
|
+
if (paths.usagePath && fs.existsSync(paths.usagePath)) {
|
|
385
|
+
payload.usage = JSON.parse(fs.readFileSync(paths.usagePath, 'utf8'));
|
|
386
|
+
}
|
|
387
|
+
if (!payload.precompact && !payload.usage) return null;
|
|
388
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
389
|
+
fs.writeFileSync(dest, JSON.stringify(payload, null, 2));
|
|
390
|
+
return dest;
|
|
391
|
+
} catch {
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
@@ -10,15 +10,18 @@ import {
|
|
|
10
10
|
buildSessionBootPayload,
|
|
11
11
|
classifyPreCompactEvent,
|
|
12
12
|
cursorGenerationId,
|
|
13
|
-
|
|
13
|
+
cursorCompactProofRoots,
|
|
14
14
|
cursorSessionId,
|
|
15
|
+
EVENT_CLASS_HOST,
|
|
15
16
|
cursorWorkspaceRoot,
|
|
16
17
|
readStdinJson,
|
|
17
18
|
writeCursorPrecompactReceipt,
|
|
18
19
|
writeSessionBoot,
|
|
19
20
|
} from './cursor-hook-utils.js';
|
|
20
21
|
import {
|
|
22
|
+
appendCursorCompactProofLog,
|
|
21
23
|
hostUsageFromPreCompactEvent,
|
|
24
|
+
writeCursorSessionReceipt,
|
|
22
25
|
writeCursorUsageReceipt,
|
|
23
26
|
} from './cursor-usage-receipt.js';
|
|
24
27
|
|
|
@@ -122,7 +125,7 @@ async function main() {
|
|
|
122
125
|
} catch {
|
|
123
126
|
plates = null;
|
|
124
127
|
}
|
|
125
|
-
for (const root of
|
|
128
|
+
for (const root of cursorCompactProofRoots(event)) {
|
|
126
129
|
const payload = buildSessionBootPayload(root, '0xray/cursor-compact', {
|
|
127
130
|
host: 'cursor',
|
|
128
131
|
hookEvent: 'pre_compact',
|
|
@@ -132,6 +135,20 @@ async function main() {
|
|
|
132
135
|
});
|
|
133
136
|
bootPath = writeSessionBoot(root, payload);
|
|
134
137
|
stationLine = payload.stationLine;
|
|
138
|
+
const stampedAt = new Date().toISOString();
|
|
139
|
+
const hostProof = eventClass === EVENT_CLASS_HOST;
|
|
140
|
+
const proofLogged = hostProof
|
|
141
|
+
? appendCursorCompactProofLog(root, {
|
|
142
|
+
sessionId,
|
|
143
|
+
timestamp: stampedAt,
|
|
144
|
+
context_tokens: typeof event.context_tokens === 'number' ? event.context_tokens : null,
|
|
145
|
+
context_usage_percent:
|
|
146
|
+
typeof event.context_usage_percent === 'number' ? event.context_usage_percent : null,
|
|
147
|
+
context_window_size:
|
|
148
|
+
typeof event.context_window_size === 'number' ? event.context_window_size : null,
|
|
149
|
+
generation_id: generationId,
|
|
150
|
+
})
|
|
151
|
+
: false;
|
|
135
152
|
receiptPath = writeCursorPrecompactReceipt(root, {
|
|
136
153
|
event_class: eventClass,
|
|
137
154
|
hookEvent: 'pre_compact',
|
|
@@ -145,13 +162,20 @@ async function main() {
|
|
|
145
162
|
messages_to_compact:
|
|
146
163
|
typeof event.messages_to_compact === 'number' ? event.messages_to_compact : null,
|
|
147
164
|
bootPath,
|
|
148
|
-
timestamp:
|
|
165
|
+
timestamp: stampedAt,
|
|
149
166
|
});
|
|
150
167
|
usagePath = writeCursorUsageReceipt(root, {
|
|
151
168
|
eventClass,
|
|
152
169
|
sessionId,
|
|
170
|
+
probeLogExists: proofLogged,
|
|
153
171
|
usage: hostUsageFromPreCompactEvent(event),
|
|
154
172
|
});
|
|
173
|
+
if (hostProof) {
|
|
174
|
+
writeCursorSessionReceipt(root, sessionId, {
|
|
175
|
+
precompactPath: receiptPath,
|
|
176
|
+
usagePath,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
155
179
|
if (plates) {
|
|
156
180
|
try {
|
|
157
181
|
const named = plates.recallPlate(payload.intent || intent || '');
|
|
@@ -4,13 +4,18 @@ export interface LessonInput {
|
|
|
4
4
|
taskId: string;
|
|
5
5
|
assignedAgent: string;
|
|
6
6
|
sessionId: string;
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Signals the finished task already named. When set, text matching is not used.
|
|
9
|
+
* An empty list with a lesson still stores that lesson under a name taken from the task.
|
|
10
|
+
*/
|
|
8
11
|
signals?: string[];
|
|
9
12
|
/** Approaches, solutions, or the wrong turn from the sessions that named the law. */
|
|
10
13
|
lesson?: string;
|
|
11
14
|
}
|
|
12
15
|
/**
|
|
13
16
|
* A finished task names the signals its text actually matched and says
|
|
14
|
-
* whether the outcome was good. That is the one-tenth step.
|
|
17
|
+
* whether the outcome was good. That is the one-tenth step.
|
|
18
|
+
* A lesson with no matched signal is stored under a hyphenated name from the
|
|
19
|
+
* task, so the same task text recalls it. No lesson and no match, no write.
|
|
15
20
|
*/
|
|
16
21
|
export declare function recordLesson(input: LessonInput): string[];
|
|
@@ -1,14 +1,48 @@
|
|
|
1
1
|
import { ensureMemoryRoutingProviderSync } from "./provider-registry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Hyphenated phrase whose spaced form is still inside the task.
|
|
4
|
+
* A later routing read of that same task hits the name.
|
|
5
|
+
*/
|
|
6
|
+
function signalNameForUnmatchedLesson(task) {
|
|
7
|
+
const words = task
|
|
8
|
+
.toLowerCase()
|
|
9
|
+
.split(/[^a-z0-9]+/)
|
|
10
|
+
.filter((word) => word.length >= 3);
|
|
11
|
+
const normalized = task.toLowerCase();
|
|
12
|
+
const kept = [];
|
|
13
|
+
for (const word of words) {
|
|
14
|
+
const next = [...kept, word];
|
|
15
|
+
const phrase = next.join(" ");
|
|
16
|
+
const hyphen = next.join("-");
|
|
17
|
+
if (!normalized.includes(phrase) || hyphen.length > 120)
|
|
18
|
+
break;
|
|
19
|
+
kept.push(word);
|
|
20
|
+
}
|
|
21
|
+
if (kept.length === 0)
|
|
22
|
+
return null;
|
|
23
|
+
return kept.join("-");
|
|
24
|
+
}
|
|
2
25
|
/**
|
|
3
26
|
* A finished task names the signals its text actually matched and says
|
|
4
|
-
* whether the outcome was good. That is the one-tenth step.
|
|
27
|
+
* whether the outcome was good. That is the one-tenth step.
|
|
28
|
+
* A lesson with no matched signal is stored under a hyphenated name from the
|
|
29
|
+
* task, so the same task text recalls it. No lesson and no match, no write.
|
|
5
30
|
*/
|
|
6
31
|
export function recordLesson(input) {
|
|
7
32
|
const provider = ensureMemoryRoutingProviderSync();
|
|
8
33
|
if (provider.id === "null" || !provider.ingestFeedback)
|
|
9
34
|
return [];
|
|
10
|
-
const
|
|
11
|
-
const
|
|
35
|
+
const lesson = (input.lesson ?? "").trim();
|
|
36
|
+
const supplied = input.signals;
|
|
37
|
+
const named = supplied !== undefined
|
|
38
|
+
? supplied
|
|
39
|
+
: provider.buildRoutingContext(input.operation).matchedSignals;
|
|
40
|
+
let names = [...new Set(named.filter((name) => name.length > 0))];
|
|
41
|
+
if (names.length === 0 && lesson.length > 0) {
|
|
42
|
+
const coined = signalNameForUnmatchedLesson(input.operation);
|
|
43
|
+
if (coined)
|
|
44
|
+
names = [coined];
|
|
45
|
+
}
|
|
12
46
|
if (names.length === 0)
|
|
13
47
|
return [];
|
|
14
48
|
provider.ingestFeedback({
|
|
@@ -62,7 +62,7 @@ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
|
|
|
62
62
|
|
|
63
63
|
## Lead cadence (syncopation)
|
|
64
64
|
|
|
65
|
-
The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/
|
|
65
|
+
The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`).
|
|
66
66
|
|
|
67
67
|
Jargon is not the job. Review and cadence ask whether the change works. Do not spend the loop reciting dest names, mill liturgy, or host mantras.
|
|
68
68
|
|
|
@@ -76,8 +76,8 @@ Jargon is not the job. Review and cadence ask whether the change works. Do not s
|
|
|
76
76
|
- **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
|
|
77
77
|
- **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
|
|
78
78
|
- **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
|
|
79
|
-
- **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `
|
|
80
|
-
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture.
|
|
79
|
+
- **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `grok-bot/OP-PROC.md` (team specifics live in `house/`). Do not paste a command novel. When a law is spoken twice, encode it this wake.
|
|
80
|
+
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Memory scoring rules: [docs/memory-scoring.md](https://github.com/0xRayAI/xray/blob/main/docs/memory-scoring.md).
|
|
81
81
|
- **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
|
|
82
82
|
- **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
|
|
83
83
|
|
|
@@ -96,7 +96,7 @@ This suite is the engine that builds the engine. When a seat sees OP-PROC, write
|
|
|
96
96
|
|
|
97
97
|
Operating planes: code, OP-PROC, model, suit, mill, host, and test/ship. Test/ship is the critical OP-PROC plane. Test then ship is the hero. Ship without that proof is the catastrophe. Long-term memory is the project law list. Each wake refreshes a changed stack definition and keeps observation stats. Heat writes the matched names onto Station, the short-term card that survives compaction. Reactive decisions move out of TypeScript into OP-PROC as the model improves. That move is why the mill and the suit exist. It is not fully proved. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish. Do not freeze the live cut.
|
|
98
98
|
- **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
|
|
99
|
-
- **Board:** critic Strict comments;
|
|
99
|
+
- **Board:** critic Strict comments; the implementer implements; lead stays main thread.
|
|
100
100
|
- **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
|
|
101
|
-
- **Ship matrix:** `
|
|
101
|
+
- **Ship matrix:** `grok-bot/OP-PROC.md` Decision matrix (team specifics live in `house/`) — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
|
|
102
102
|
- **Metamorphosis:** LLM → OP-PROC is in-context worn seats (same critic, same dummy, resume only). Not more bots.
|
|
@@ -96,7 +96,7 @@ codex_terms: [5, 7, 32] # Related Codex term numbers
|
|
|
96
96
|
```markdown
|
|
97
97
|
## What Next?
|
|
98
98
|
|
|
99
|
-
- Related Codex terms: [codex.json](
|
|
99
|
+
- Related Codex terms: [codex.json](../../../.xray/codex.json)
|
|
100
100
|
- Next story to write: [suggestion]
|
|
101
101
|
```
|
|
102
102
|
|
package/llms.txt
CHANGED
|
@@ -8,7 +8,10 @@ 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) plus Cursor `.cursor/hooks.json`, 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`. Lead cadence: `grok-bot/
|
|
11
|
+
- `npm install 0xray` — postinstall fastens mill+inspect, writes 7 MCP `.mcp.json`, four host bridges (OpenCode, Grok, Hermes, OpenClaw) plus Cursor `.cursor/hooks.json`, 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`. Lead cadence: `grok-bot/OP-PROC.md` (team specifics live in `house/`) — a peer continues from Station + Repertoire; dummy tests `SKILLS.md`; same-sess wear; branch/PR; OTP then poll; loop until Station; live ticks, not idle pacers.
|
|
12
|
+
- Memory scoring rules: [docs/memory-scoring.md](docs/memory-scoring.md). The orchestrator links that file. It does not copy the rules.
|
|
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
|
+
- `@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`.
|
|
12
15
|
|
|
13
16
|
- `npx @0xray/foundry mint --skip-live` — re-fasten mill plant, then inspect.
|
|
14
17
|
- `npx @0xray/foundry inspect --skip-live` — plant-vs-worn, receipt, CI. Chat is not a receipt.
|
|
@@ -58,5 +61,6 @@ Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.8 ships
|
|
|
58
61
|
- [SKILLS.md](SKILLS.md) — catalog (costume / self-plant, not default sync)
|
|
59
62
|
- [Foundry](docs-site/docs/architecture/v4-foundry.md) — mill vs exo, foundry-plant/0, shopPlant
|
|
60
63
|
- [Features since 3.1](docs-site/docs/guides/features-since-3.1.md)
|
|
64
|
+
- [Memory scoring](docs/memory-scoring.md)
|
|
61
65
|
|
|
62
66
|
Playwright / UI: n/a. This mill is CLI.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "0xray",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.27",
|
|
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",
|
|
@@ -80,8 +80,9 @@
|
|
|
80
80
|
"test:code-analysis": "npm test -- src/__tests__/unit/codebase-context-analyzer.test.ts src/__tests__/unit/dependency-graph-builder.test.ts src/__tests__/unit/rule-enforcer.test.ts src/__tests__/unit/codex-parser.test.ts src/__tests__/unit/codex-injector.test.ts",
|
|
81
81
|
"test:processors": "npm test -- src/__tests__/unit/processor-activation.test.ts src/__tests__/unit/typescript-compilation-processor.test.ts",
|
|
82
82
|
"test:miscellaneous": "npm test -- src/__tests__/unit/blocked-test.test.ts",
|
|
83
|
+
"test:grok-bot": "npm test -- src/__tests__/unit/grok-bot-seat-doctor.test.ts src/__tests__/unit/grok-bot-op-proc-map.test.ts src/__tests__/unit/lead-cadence.test.ts src/__tests__/unit/grok-bot-auto-review-policy.test.ts",
|
|
83
84
|
"test:quick": "npm test -- src/__tests__/integration/boot-orchestrator.integration.test.ts src/__tests__/unit/config-loader.test.ts src/__tests__/unit/state-manager.test.ts",
|
|
84
|
-
"test:comprehensive": "npm run typecheck && npm run test:unit && npm run test:core-framework && npm run test:security && npm run test:performance && npm run test:session-management && npm run test:code-analysis && npm run test:processors && npm run test:miscellaneous && npm test -- src/__tests__/unit/llm-governance-provider.test.ts src/__tests__/unit/mcp-server-smoke.test.ts src/__tests__/unit/cursor-hooks.test.ts src/__tests__/unit/host-vs-mill-score.test.ts",
|
|
85
|
+
"test:comprehensive": "npm run typecheck && npm run test:unit && npm run test:core-framework && npm run test:security && npm run test:performance && npm run test:session-management && npm run test:code-analysis && npm run test:processors && npm run test:miscellaneous && npm test -- src/__tests__/unit/llm-governance-provider.test.ts src/__tests__/unit/mcp-server-smoke.test.ts src/__tests__/unit/cursor-hooks.test.ts src/__tests__/unit/host-vs-mill-score.test.ts && npm run test:grok-bot",
|
|
85
86
|
"test:integration-all": "npm test -- src/__tests__/integration/",
|
|
86
87
|
"test:performance-all": "npm test -- src/__tests__/performance/ src/__tests__/unit/performance-system.test.ts src/__tests__/unit/benchmark.test.ts src/__tests__/unit/analytics.test.ts",
|
|
87
88
|
"test:agents-all": "echo 'Legacy agents test entry retired'",
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* npx @0xray/foundry reconcile patch --apply
|
|
12
12
|
*
|
|
13
13
|
* --apply writes package.json and the package-lock.json version fields.
|
|
14
|
-
* --check
|
|
14
|
+
* --check passes when package.json is equal to the registry (already published)
|
|
15
|
+
* or greater (the pre-publish bump). It fails when package.json is behind npm,
|
|
16
|
+
* or when the lock does not match package.json.
|
|
15
17
|
*/
|
|
16
18
|
|
|
17
19
|
import { execSync } from "child_process";
|
|
@@ -91,6 +93,21 @@ function fail(msg) {
|
|
|
91
93
|
process.exit(1);
|
|
92
94
|
}
|
|
93
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Registry gate for --check.
|
|
98
|
+
* Equal to npm is a shipped release. Greater is the pre-publish bump.
|
|
99
|
+
* Only a package.json behind the registry fails.
|
|
100
|
+
* @param {string} local
|
|
101
|
+
* @param {string} npmVersion
|
|
102
|
+
* @returns {string | null}
|
|
103
|
+
*/
|
|
104
|
+
export function publishedVersionCheckError(local, npmVersion) {
|
|
105
|
+
if (compare(local, npmVersion) < 0) {
|
|
106
|
+
return `package.json (${local}) must be >= npm (${npmVersion}). Run: npx @0xray/foundry reconcile patch --apply`;
|
|
107
|
+
}
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
94
111
|
function main() {
|
|
95
112
|
const local = readLocalVersion();
|
|
96
113
|
const npm = readPublishedVersion();
|
|
@@ -138,9 +155,12 @@ function main() {
|
|
|
138
155
|
return;
|
|
139
156
|
}
|
|
140
157
|
|
|
141
|
-
// Strict checks for release gate / pre-tag
|
|
142
|
-
|
|
143
|
-
|
|
158
|
+
// Strict checks for release gate / pre-tag.
|
|
159
|
+
// `local` is the version read before --apply. Apply still writes
|
|
160
|
+
// bumpVersion(max(npm, tag)) and is not this gate.
|
|
161
|
+
const behindNpm = publishedVersionCheckError(local, npm);
|
|
162
|
+
if (behindNpm) {
|
|
163
|
+
fail(behindNpm);
|
|
144
164
|
}
|
|
145
165
|
|
|
146
166
|
const pkgVersion = readLocalVersion();
|
|
@@ -62,7 +62,7 @@ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
|
|
|
62
62
|
|
|
63
63
|
## Lead cadence (syncopation)
|
|
64
64
|
|
|
65
|
-
The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/
|
|
65
|
+
The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`).
|
|
66
66
|
|
|
67
67
|
Jargon is not the job. Review and cadence ask whether the change works. Do not spend the loop reciting dest names, mill liturgy, or host mantras.
|
|
68
68
|
|
|
@@ -76,8 +76,8 @@ Jargon is not the job. Review and cadence ask whether the change works. Do not s
|
|
|
76
76
|
- **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
|
|
77
77
|
- **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
|
|
78
78
|
- **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
|
|
79
|
-
- **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `
|
|
80
|
-
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture.
|
|
79
|
+
- **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `grok-bot/OP-PROC.md` (team specifics live in `house/`). Do not paste a command novel. When a law is spoken twice, encode it this wake.
|
|
80
|
+
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Memory scoring rules: [docs/memory-scoring.md](https://github.com/0xRayAI/xray/blob/main/docs/memory-scoring.md).
|
|
81
81
|
- **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
|
|
82
82
|
- **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
|
|
83
83
|
|
|
@@ -96,7 +96,7 @@ This suite is the engine that builds the engine. When a seat sees OP-PROC, write
|
|
|
96
96
|
|
|
97
97
|
Operating planes: code, OP-PROC, model, suit, mill, host, and test/ship. Test/ship is the critical OP-PROC plane. Test then ship is the hero. Ship without that proof is the catastrophe. Long-term memory is the project law list. Each wake refreshes a changed stack definition and keeps observation stats. Heat writes the matched names onto Station, the short-term card that survives compaction. Reactive decisions move out of TypeScript into OP-PROC as the model improves. That move is why the mill and the suit exist. It is not fully proved. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish. Do not freeze the live cut.
|
|
98
98
|
- **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
|
|
99
|
-
- **Board:** critic Strict comments;
|
|
99
|
+
- **Board:** critic Strict comments; the implementer implements; lead stays main thread.
|
|
100
100
|
- **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
|
|
101
|
-
- **Ship matrix:** `
|
|
101
|
+
- **Ship matrix:** `grok-bot/OP-PROC.md` Decision matrix (team specifics live in `house/`) — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
|
|
102
102
|
- **Metamorphosis:** LLM → OP-PROC is in-context worn seats (same critic, same dummy, resume only). Not more bots.
|
|
@@ -96,7 +96,7 @@ codex_terms: [5, 7, 32] # Related Codex term numbers
|
|
|
96
96
|
```markdown
|
|
97
97
|
## What Next?
|
|
98
98
|
|
|
99
|
-
- Related Codex terms: [codex.json](
|
|
99
|
+
- Related Codex terms: [codex.json](../../../.xray/codex.json)
|
|
100
100
|
- Next story to write: [suggestion]
|
|
101
101
|
```
|
|
102
102
|
|