0xray 4.0.29 → 4.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.grok-plugin/plugin.json +1 -1
- package/.opencode/skills/orchestrator/SKILL.md +12 -0
- package/.xray/features.json +1 -1
- package/README.md +1 -0
- package/dist/CHANGELOG.md +17 -0
- package/dist/README.md +1 -0
- package/dist/cli/commands/validate.js +5 -0
- package/dist/cli/index.js +16 -1
- package/dist/integrations/grok/hooks/grok-hook-utils.js +24 -4
- package/dist/integrations/grok/hooks/post-tool-use.js +2 -1
- package/dist/integrations/grok/hooks/pre-tool-use.js +90 -5
- package/dist/integrations/grok/hooks/session-start.js +7 -2
- package/dist/integrations/hooks/goggles-pipeline.mjs +568 -0
- package/dist/integrations/hooks/goggles-planes.json +28 -0
- package/dist/integrations/hooks/plates.cjs +23 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +40 -11
- package/dist/integrations/hooks/station-memory-ingest.mjs +3 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/orchestrator/config/agent-capabilities.js +7 -0
- package/dist/memory-routing/plates.d.ts +1 -1
- package/dist/memory-routing/plates.js +5 -0
- package/dist/memory-routing/provider-loader.js +2 -0
- package/dist/nucleus/thin-dispatch.d.ts +1 -0
- package/dist/nucleus/thin-dispatch.js +4 -2
- package/dist/skills/orchestrator/SKILL.md +12 -0
- package/docs-site/docs/plates/glossary.md +27 -0
- package/docs-site/docs/plates/goggles.md +18 -0
- package/docs-site/docs/plates/grokbot.md +41 -0
- package/docs-site/docs/plates/host-pack.md +32 -0
- package/docs-site/docs/plates/house.md +42 -39
- package/docs-site/docs/plates/index.md +13 -1
- package/docs-site/docs/plates/kits.md +28 -0
- package/docs-site/docs/plates/suit.md +40 -0
- package/llms.txt +1 -0
- package/package.json +2 -2
- package/scripts/foundry/assert-packed-dist-cli.mjs +5 -0
- package/scripts/node/consumer-install-smoke.mjs +5 -0
- package/scripts/node/install-bridges.cjs +120 -12
- package/scripts/node/setup.cjs +80 -71
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/orchestrator/config/agent-capabilities.ts +8 -0
- package/src/skills/orchestrator/SKILL.md +12 -0
- package/vendor/@0xray/repertoire/dist/paths.js +4 -0
- package/xray/features.json +1 -1
package/.grok-plugin/plugin.json
CHANGED
|
@@ -53,6 +53,18 @@ When `multi_agent_orchestration.lead_dev_mode` is true in `features.json` (defau
|
|
|
53
53
|
| Test failures | bug-triage |
|
|
54
54
|
| Review | code-review |
|
|
55
55
|
|
|
56
|
+
## Goggles
|
|
57
|
+
|
|
58
|
+
Pushed on `feat/goggles-look`. Not merged. Not published. Grok CLI has not shipped this. Wear the local build. From the worn checkout run `node dist/integrations/hooks/goggles-pipeline.mjs`. Do not run `npx 0xray goggles`. If `dist` is older than `src/integrations/hooks/goggles-pipeline.mjs`, build that tree and wear that `dist`. A subagent wears this same local build.
|
|
59
|
+
|
|
60
|
+
Kind 0 is actuality. It compares the list in the file to the same six names in the code. It speaks only when those lists differ. A match is quiet. It does not read the suit that is running. It is not a plate type.
|
|
61
|
+
|
|
62
|
+
Kind 1 names one plane: dichotomy, syncopate, synthesis, or loop. The lens holds that plane. An action on that plane is quiet. An action on another plane, or on a pipeline drawing, is stopped. A pipeline drawing is not a scope stop. Ground is not a scope stop. Scope, when named, is ecosystem, part, one flow, or one artifact, and an action wider than that scope is stopped. One kind and one scope level at a time. Two planes, calling, ground, and a pipeline name do not arm the lens. `outer` without one plane is `Name one plane.` After 1 is empty. Nothing is picked. Calling stays off.
|
|
63
|
+
|
|
64
|
+
`digest` and `triage` return the card already built by `assemblePlane`. The fields are from, digest, plate, entry, exit, files, skills, setup, teardown, and worn. Empty stays empty. The rows are ground, routing, house, boot, governance, memory-recall, orchestration, processor, and reporting. Those nine are not Kind 0. `digest` fills the card. Entry and exit are the plate's input and output box titles when that plate has them. Setup and teardown stay empty unless the row names them. The mill path is `scripts/foundry`. `triage` adds the empty fields and whether the row holds. Zoom after the card is the same ladder: ecosystem, part, one flow, one artifact. One file is one artifact. Several files are not narrowed to a guessed file.
|
|
65
|
+
|
|
66
|
+
The hold lasts for the work that named the plane. It does not stop one tool and then forget. Work that says goggles clears the hold and stays quiet. The suit does not invent the plane.
|
|
67
|
+
|
|
56
68
|
## Hooks (rewired, not new MCPs)
|
|
57
69
|
|
|
58
70
|
- **SessionStart** → `session-start.js` boots lead_dev_mode
|
package/.xray/features.json
CHANGED
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.30** | Fixes 4.0.29: `npx 0xray wear` and `setup` work outside a git checkout again. They write the 4.0.28 project setup, skip only Cursor hooks, and print one warning. Inside a git checkout they restore the 4.0.28 project setup, and `wear` adds Cursor hooks plus the unwear snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
|
|
55
56
|
| **4.0.29** | `npm install` only creates the relative `node_modules/@0xray/repertoire` link to the vendored repertoire and prints `npx 0xray wear`. Run `npx 0xray wear` after install. Wear writes only the consumer project's `.cursor/hooks.json` (installed dist hooks, beside user entries); `npx 0xray unwear` restores the snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
|
|
56
57
|
| **4.0.28** | MCP servers start through `scripts/node/mcp-launch.cjs` and only see PATH, HOME, XRAY_ROOT, plus names on their keep list. Tokens such as NPM_TOKEN are not inherited. User env values stay out of argv. Postinstall keeps user edits to AGENTS.md, .mcp.json, and opencode.json. `house init` does not copy EXAMPLE.md; doctor FAILs while `house/EXAMPLE.md` exists. Inspect adds a machinePlugin check. The Cursor hook defaults XRAY_ROOT to the suit. Companion `@0xray/grok-bot` 0.1.7. Released 2026-09-27. |
|
|
57
58
|
| **4.0.27** | Host compact proof needs a generation id and a numeric usage percent, and the same preCompact receipt is mirrored to nested consumer wear roots. Memory scoring: [docs/memory-scoring.md](docs/memory-scoring.md) (orchestrator links it). Companion `@0xray/grok-bot` 0.1.6: general page vs `house/` overlay, `templates/house/`, `grok-bot house init`, doctor `GROK_BOT_HOUSE` or walk-up. Released 2026-09-26. |
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,7 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
9
|
### Features
|
|
10
|
+
- **Goggles.** Proposed plates for goggles, suit, kits, host pack, and glossary. Goggles views one plane. Recall opens a plate when speech names that plate. Plates only. Not a new skill.
|
|
10
11
|
- **Plates.** Pipeline schematics live in `docs-site/docs/plates/` (routing, governance, boot, orchestration, processor, reporting, memory-recall). Station keeps one pointer line. Pre-compact and the `MEMORY_ROUTING` inject carry that one schematic. A lesson is an episode. A plate is the machine. Not a new skill.
|
|
11
12
|
- **Vendored Repertoire 0.2.8.** `vendor/@0xray/repertoire` is that package. Lesson lines and retained ids stay at 20. Speech that names nothing mints a learned signal, and only those mints evict past 24. Not a new skill.
|
|
12
13
|
- **Feat rebase.** When the mandated work turns into mantra, or the job has split across planes that no longer share one present, stop and answer the original message again from this seat. On `LEAD-CADENCE.md`, the orchestrator skill, and the ship-ready mill gate. Project dest grows the name `feat-rebase` from the stack overlay. Not a new skill.
|
|
@@ -41,6 +42,22 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
|
|
|
41
42
|
- Archive root `integrations/` costume SKILL dump → `docs/archive/integrations-costume/`. Live wear is `src/integrations`.
|
|
42
43
|
- Archive root `commands/` stale copy → `docs/archive/commands-copy/`. Live wear is `src/opencode/commands`.
|
|
43
44
|
|
|
45
|
+
## [4.0.31] - 2026-10-01
|
|
46
|
+
|
|
47
|
+
Next patch after npm `4.0.30`. Not published from this commit.
|
|
48
|
+
|
|
49
|
+
Goggles looks at one pipeline. Kind 0 name-checks the six outer names and stays quiet when the worn list matches the map. Digest and triage return one card. A leave is denied. Session boot hands the card through `handCard` and normalizes the workspace root, including a trailing slash. The mill path is `scripts/foundry`. Run `node dist/integrations/hooks/goggles-pipeline.mjs`. This cut also carries the plate docs and the live project-file signal count that landed on main after 4.0.30. Calling and confer stay off. Companion `@0xray/grok-bot` is unchanged at 0.1.8.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## [4.0.30] - 2026-09-28
|
|
54
|
+
|
|
55
|
+
Next patch after npm `4.0.29`. Released 2026-09-28.
|
|
56
|
+
|
|
57
|
+
Fixes the 4.0.29 regression where `npx 0xray wear` and `npx 0xray setup` exited 1 with `cursor-wear: not a git work tree` outside a git checkout (#147). Outside a git checkout, both commands again write the 4.0.28 consumer project setup and skip only Cursor hooks, with one stderr line: `cursor-wear: hooks skipped because this folder is not a git checkout`. Inside a git checkout, `wear` and `setup` restore the 4.0.28 project setup that 4.0.29 had dropped: managed `AGENTS.md`, `.gitignore` entries, `.xray` config, the `node_modules/@0xray/repertoire` link, the mill/inspect plant, chat bridges, the `.opencode/skills` sync, and the `dist` / `scripts` links. `wear` then adds the Cursor hooks, including the six hook scripts, and the `.xray/state/cursor-hook-wear/` snapshot. Postinstall is unchanged: it links the vendored repertoire and prints `npx 0xray wear`. Companion package `@0xray/grok-bot` is unchanged at 0.1.8.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
44
61
|
## [4.0.29] - 2026-09-28
|
|
45
62
|
|
|
46
63
|
Next patch after npm `4.0.28`. Released 2026-09-28.
|
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.30** | Fixes 4.0.29: `npx 0xray wear` and `setup` work outside a git checkout again. They write the 4.0.28 project setup, skip only Cursor hooks, and print one warning. Inside a git checkout they restore the 4.0.28 project setup, and `wear` adds Cursor hooks plus the unwear snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
|
|
55
56
|
| **4.0.29** | `npm install` only creates the relative `node_modules/@0xray/repertoire` link to the vendored repertoire and prints `npx 0xray wear`. Run `npx 0xray wear` after install. Wear writes only the consumer project's `.cursor/hooks.json` (installed dist hooks, beside user entries); `npx 0xray unwear` restores the snapshot. Companion `@0xray/grok-bot` 0.1.8. Released 2026-09-28. |
|
|
56
57
|
| **4.0.28** | MCP servers start through `scripts/node/mcp-launch.cjs` and only see PATH, HOME, XRAY_ROOT, plus names on their keep list. Tokens such as NPM_TOKEN are not inherited. User env values stay out of argv. Postinstall keeps user edits to AGENTS.md, .mcp.json, and opencode.json. `house init` does not copy EXAMPLE.md; doctor FAILs while `house/EXAMPLE.md` exists. Inspect adds a machinePlugin check. The Cursor hook defaults XRAY_ROOT to the suit. Companion `@0xray/grok-bot` 0.1.7. Released 2026-09-27. |
|
|
57
58
|
| **4.0.27** | Host compact proof needs a generation id and a numeric usage percent, and the same preCompact receipt is mirrored to nested consumer wear roots. Memory scoring: [docs/memory-scoring.md](docs/memory-scoring.md) (orchestrator links it). Companion `@0xray/grok-bot` 0.1.6: general page vs `house/` overlay, `templates/house/`, `grok-bot house init`, doctor `GROK_BOT_HOUSE` or walk-up. Released 2026-09-26. |
|
|
@@ -25,6 +25,11 @@ export const VALIDATE_PACK_PATHS = [
|
|
|
25
25
|
"dist/integrations/hooks/plates.cjs",
|
|
26
26
|
"docs-site/docs/plates/memory-recall.md",
|
|
27
27
|
"docs-site/docs/plates/processor.md",
|
|
28
|
+
"docs-site/docs/plates/goggles.md",
|
|
29
|
+
"docs-site/docs/plates/suit.md",
|
|
30
|
+
"docs-site/docs/plates/kits.md",
|
|
31
|
+
"docs-site/docs/plates/host-pack.md",
|
|
32
|
+
"docs-site/docs/plates/glossary.md",
|
|
28
33
|
];
|
|
29
34
|
export const CONSUMER_WEAR_PATHS = [
|
|
30
35
|
"AGENTS.md",
|
package/dist/cli/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provides commands for installing and managing xray framework
|
|
6
6
|
*/
|
|
7
7
|
import { Command } from "commander";
|
|
8
|
-
import { execSync, spawn } from "child_process";
|
|
8
|
+
import { execSync, spawn, spawnSync } from "child_process";
|
|
9
9
|
import { join, resolve } from "path";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { readFileSync, existsSync } from "fs";
|
|
@@ -76,6 +76,21 @@ program
|
|
|
76
76
|
process.exit(1);
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
|
+
program
|
|
80
|
+
.command("goggles")
|
|
81
|
+
.argument("[args...]", "plane, then examine, triage, cascade, or teardown")
|
|
82
|
+
.description("Glimpse every plane, or one plane's way in. A hit does not open the plane.")
|
|
83
|
+
.action((args) => {
|
|
84
|
+
const built = join(packageRoot, "dist", "integrations", "hooks", "goggles-pipeline.mjs");
|
|
85
|
+
const source = join(packageRoot, "src", "integrations", "hooks", "goggles-pipeline.mjs");
|
|
86
|
+
const script = existsSync(built) ? built : source;
|
|
87
|
+
const result = spawnSync(process.execPath, [script, ...(args ?? [])], { encoding: "utf8" });
|
|
88
|
+
if (result.stdout)
|
|
89
|
+
process.stdout.write(result.stdout);
|
|
90
|
+
if (result.stderr)
|
|
91
|
+
process.stderr.write(result.stderr);
|
|
92
|
+
process.exit(result.status ?? 1);
|
|
93
|
+
});
|
|
79
94
|
program
|
|
80
95
|
.command("wear")
|
|
81
96
|
.description("Wear the 0xray suit in this git checkout")
|
|
@@ -28,6 +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
32
|
|
|
32
33
|
export {
|
|
33
34
|
checkPendingDelegationGate,
|
|
@@ -86,12 +87,18 @@ const WRITE_TOOLS = new Set([
|
|
|
86
87
|
'EditNotebook',
|
|
87
88
|
]);
|
|
88
89
|
|
|
90
|
+
export function normalizeWorkspaceRoot(root) {
|
|
91
|
+
const raw = String(root || '').trim();
|
|
92
|
+
if (!raw) return raw;
|
|
93
|
+
return path.resolve(raw);
|
|
94
|
+
}
|
|
95
|
+
|
|
89
96
|
export function workspaceRoot() {
|
|
90
|
-
return (
|
|
97
|
+
return normalizeWorkspaceRoot(
|
|
91
98
|
process.env.GROK_WORKSPACE_ROOT ||
|
|
92
99
|
process.env.CLAUDE_PROJECT_DIR ||
|
|
93
100
|
process.env.XRAY_ROOT ||
|
|
94
|
-
process.cwd()
|
|
101
|
+
process.cwd(),
|
|
95
102
|
);
|
|
96
103
|
}
|
|
97
104
|
|
|
@@ -198,6 +205,7 @@ export function extractToolContext(event) {
|
|
|
198
205
|
|
|
199
206
|
if (toolInput.path) paths.push(String(toolInput.path));
|
|
200
207
|
if (toolInput.file_path) paths.push(String(toolInput.file_path));
|
|
208
|
+
if (toolInput.target_file) paths.push(String(toolInput.target_file));
|
|
201
209
|
if (toolInput.target_notebook) paths.push(String(toolInput.target_notebook));
|
|
202
210
|
if (Array.isArray(toolInput.paths)) paths.push(...toolInput.paths.map(String));
|
|
203
211
|
|
|
@@ -301,7 +309,7 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
301
309
|
? 'xray-orchestrator analyze-complexity optional on frontier (spawn warns, does not deny)'
|
|
302
310
|
: 'xray-orchestrator → analyze-complexity (required before spawn_subagent)',
|
|
303
311
|
enforcement: 'PreToolUse hook — Codex constitution always on; ceremony scales by suit_temperament',
|
|
304
|
-
workspaceRoot: root,
|
|
312
|
+
workspaceRoot: normalizeWorkspaceRoot(root),
|
|
305
313
|
...heat,
|
|
306
314
|
...(siblingRoots.length > 0 ? { siblingWorkspaceRoots: siblingRoots } : {}),
|
|
307
315
|
...(conferPending ? { conferPending: true, conferTrigger: 'analyze-complexity at synthesis checkpoint' } : {}),
|
|
@@ -322,6 +330,11 @@ export function writeSessionBoot(root, payload) {
|
|
|
322
330
|
fs.mkdirSync(stateDir, { recursive: true });
|
|
323
331
|
fs.writeFileSync(sessionBootPath(root), JSON.stringify(payload, null, 2));
|
|
324
332
|
writeStationMarkdown(root, payload);
|
|
333
|
+
try {
|
|
334
|
+
handCard(root, payload && (payload.cardText || payload.intent));
|
|
335
|
+
} catch {
|
|
336
|
+
/* a missed card must not fail the boot */
|
|
337
|
+
}
|
|
325
338
|
return sessionBootPath(root);
|
|
326
339
|
} catch {
|
|
327
340
|
return null;
|
|
@@ -333,9 +346,16 @@ export function sessionBootNeedsRefresh(existing, root) {
|
|
|
333
346
|
if (existing.lead_dev_mode === undefined) return true;
|
|
334
347
|
if (existing.host !== 'grok') return true;
|
|
335
348
|
if (!existing.suit_profile) return true;
|
|
336
|
-
if (
|
|
349
|
+
if (
|
|
350
|
+
existing.workspaceRoot &&
|
|
351
|
+
normalizeWorkspaceRoot(existing.workspaceRoot) !== normalizeWorkspaceRoot(root)
|
|
352
|
+
) {
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
337
355
|
if (!existing.repertoireResume) return true;
|
|
338
356
|
if (!existing.stationLine) return true;
|
|
357
|
+
const liveResume = buildRepertoireResume(root);
|
|
358
|
+
if (liveResume && existing.repertoireResume !== liveResume) return true;
|
|
339
359
|
return false;
|
|
340
360
|
}
|
|
341
361
|
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
isSubagentTool,
|
|
11
11
|
isWriteTool,
|
|
12
12
|
loadFeatures,
|
|
13
|
+
normalizeWorkspaceRoot,
|
|
13
14
|
readStdinJson,
|
|
14
15
|
resolveSessionId,
|
|
15
16
|
workspaceRoot,
|
|
@@ -33,7 +34,7 @@ function extractToolOutput(event) {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export function handlePostToolUse(event, root = workspaceRoot()) {
|
|
36
|
-
const eventRoot = event.workspaceRoot || event.cwd || root;
|
|
37
|
+
const eventRoot = normalizeWorkspaceRoot(event.workspaceRoot || event.cwd || root);
|
|
37
38
|
const sessionId = resolveSessionId(event);
|
|
38
39
|
const { toolName, toolInput } = extractToolContext(event);
|
|
39
40
|
|
|
@@ -15,11 +15,72 @@ import {
|
|
|
15
15
|
isShellTool,
|
|
16
16
|
isWriteTool,
|
|
17
17
|
loadFeatures,
|
|
18
|
+
normalizeWorkspaceRoot,
|
|
18
19
|
readStdinJson,
|
|
19
20
|
resolveSessionId,
|
|
20
21
|
workspaceRoot,
|
|
21
22
|
} from './grok-hook-utils.js';
|
|
22
23
|
import { appendHookActivity } from './grok-hook-activity.js';
|
|
24
|
+
import { cardStop } from '../../hooks/goggles-pipeline.mjs';
|
|
25
|
+
import { createRequire } from 'node:module';
|
|
26
|
+
import { existsSync } from 'node:fs';
|
|
27
|
+
import { dirname, join } from 'node:path';
|
|
28
|
+
import { fileURLToPath } from 'node:url';
|
|
29
|
+
|
|
30
|
+
const hookDir = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
let scoreAndRouteFn;
|
|
32
|
+
|
|
33
|
+
function loadScoreAndRoute() {
|
|
34
|
+
if (scoreAndRouteFn !== undefined) return scoreAndRouteFn;
|
|
35
|
+
scoreAndRouteFn = null;
|
|
36
|
+
const require = createRequire(import.meta.url);
|
|
37
|
+
const candidates = [
|
|
38
|
+
join(hookDir, '../../../nucleus/thin-dispatch.js'),
|
|
39
|
+
join(hookDir, '../../../../dist/nucleus/thin-dispatch.js'),
|
|
40
|
+
];
|
|
41
|
+
for (const candidate of candidates) {
|
|
42
|
+
if (!existsSync(candidate)) continue;
|
|
43
|
+
try {
|
|
44
|
+
const loaded = require(candidate);
|
|
45
|
+
if (typeof loaded.scoreAndRoute === 'function') {
|
|
46
|
+
scoreAndRouteFn = loaded.scoreAndRoute;
|
|
47
|
+
return scoreAndRouteFn;
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
/* next built copy */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Speak only when the organ changes the agent. A match that leaves the agent is quiet. */
|
|
57
|
+
export function repertoireDecisionFields(routed) {
|
|
58
|
+
if (!routed?.memoryRouting?.overridden || !routed.agent) return null;
|
|
59
|
+
const signals = Array.isArray(routed.memoryRouting.signals)
|
|
60
|
+
? routed.memoryRouting.signals.slice(0, 4).filter(Boolean)
|
|
61
|
+
: [];
|
|
62
|
+
const why = signals.length ? ` on ${signals.join(', ')}` : '';
|
|
63
|
+
return {
|
|
64
|
+
agent: routed.agent,
|
|
65
|
+
gate: 'repertoire',
|
|
66
|
+
hookSpecificOutput: {
|
|
67
|
+
hookEventName: 'PreToolUse',
|
|
68
|
+
additionalContext: `Repertoire changed the route to ${routed.agent}${why}. Follow that agent for this work.`,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function repertoireRoute(operation) {
|
|
74
|
+
const text = String(operation || '').slice(0, 500).trim();
|
|
75
|
+
if (!text) return null;
|
|
76
|
+
try {
|
|
77
|
+
const scoreAndRoute = loadScoreAndRoute();
|
|
78
|
+
if (!scoreAndRoute) return null;
|
|
79
|
+
return repertoireDecisionFields(scoreAndRoute(text, {}));
|
|
80
|
+
} catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
23
84
|
|
|
24
85
|
function finish(root, decision, reason, hint, toolName, extra = {}) {
|
|
25
86
|
const out = { decision, ...extra };
|
|
@@ -30,6 +91,7 @@ function finish(root, decision, reason, hint, toolName, extra = {}) {
|
|
|
30
91
|
tool: toolName,
|
|
31
92
|
reason: reason || hint || null,
|
|
32
93
|
gate: extra.gate || null,
|
|
94
|
+
agent: extra.agent || null,
|
|
33
95
|
livePath: true,
|
|
34
96
|
});
|
|
35
97
|
process.exit(0);
|
|
@@ -41,7 +103,7 @@ async function main() {
|
|
|
41
103
|
|
|
42
104
|
try {
|
|
43
105
|
const event = await readStdinJson();
|
|
44
|
-
const eventRoot = event.workspaceRoot || event.cwd || root;
|
|
106
|
+
const eventRoot = normalizeWorkspaceRoot(event.workspaceRoot || event.cwd || root);
|
|
45
107
|
ensureSessionBoot(eventRoot, '0xray/grok-pre-tool-use-boot');
|
|
46
108
|
|
|
47
109
|
const features = loadFeatures(eventRoot);
|
|
@@ -75,9 +137,28 @@ async function main() {
|
|
|
75
137
|
if (extraBlock) finish(eventRoot, 'deny', extraBlock, null, toolName);
|
|
76
138
|
}
|
|
77
139
|
|
|
140
|
+
const stop = cardStop(
|
|
141
|
+
eventRoot,
|
|
142
|
+
toolName,
|
|
143
|
+
[cmd, content, toolInput.pattern, toolInput.query, ...(ctx.paths || [])].filter(Boolean).join('\n'),
|
|
144
|
+
ctx.paths || [],
|
|
145
|
+
toolInput,
|
|
146
|
+
);
|
|
147
|
+
if (stop?.decision === 'deny') {
|
|
148
|
+
finish(eventRoot, 'deny', stop.reason, null, toolName, { gate: stop.gate });
|
|
149
|
+
}
|
|
150
|
+
if (stop?.decision === 'allow') {
|
|
151
|
+
finish(eventRoot, 'allow', null, null, toolName, {
|
|
152
|
+
gate: stop.gate,
|
|
153
|
+
hookSpecificOutput: stop.hookSpecificOutput,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const route = repertoireRoute([toolName, cmd, content].filter(Boolean).join(' '));
|
|
158
|
+
|
|
78
159
|
if (isShellTool(toolName) && cmd) {
|
|
79
160
|
const testHint = checkFullTestSuite(cmd, features);
|
|
80
|
-
if (testHint) finish(eventRoot, 'allow', null, testHint, toolName);
|
|
161
|
+
if (testHint) finish(eventRoot, 'allow', null, testHint, toolName, route || {});
|
|
81
162
|
}
|
|
82
163
|
|
|
83
164
|
if (gateBlock.reason) {
|
|
@@ -87,11 +168,11 @@ async function main() {
|
|
|
87
168
|
gateBlock.reason,
|
|
88
169
|
gateBlock.hint,
|
|
89
170
|
toolName,
|
|
90
|
-
{ gate: gateBlock.gate, warn: true },
|
|
171
|
+
{ gate: gateBlock.gate, warn: true, ...(route || {}) },
|
|
91
172
|
);
|
|
92
173
|
}
|
|
93
174
|
|
|
94
|
-
finish(eventRoot, 'allow', null, null, toolName);
|
|
175
|
+
finish(eventRoot, 'allow', null, null, toolName, route || {});
|
|
95
176
|
} catch (err) {
|
|
96
177
|
appendHookActivity(root, 'grok-pre-tool-use', 'hook-error', 'error', {
|
|
97
178
|
tool: toolName,
|
|
@@ -116,6 +197,7 @@ function extractFromEvent(event) {
|
|
|
116
197
|
|
|
117
198
|
if (toolInput.path) paths.push(String(toolInput.path));
|
|
118
199
|
if (toolInput.file_path) paths.push(String(toolInput.file_path));
|
|
200
|
+
if (toolInput.target_file) paths.push(String(toolInput.target_file));
|
|
119
201
|
if (toolInput.target_notebook) paths.push(String(toolInput.target_notebook));
|
|
120
202
|
if (Array.isArray(toolInput.paths)) paths.push(...toolInput.paths.map(String));
|
|
121
203
|
|
|
@@ -133,4 +215,7 @@ function extractFromEvent(event) {
|
|
|
133
215
|
};
|
|
134
216
|
}
|
|
135
217
|
|
|
136
|
-
|
|
218
|
+
const launchedAsCli = Boolean(process.argv[1] && process.argv[1].endsWith('pre-tool-use.js'));
|
|
219
|
+
if (launchedAsCli) {
|
|
220
|
+
main();
|
|
221
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
ensureSessionBoot,
|
|
11
11
|
readStdinJson,
|
|
12
12
|
resolveSessionId,
|
|
13
|
+
normalizeWorkspaceRoot,
|
|
13
14
|
workspaceRoot,
|
|
14
15
|
writeSessionBoot,
|
|
15
16
|
} from './grok-hook-utils.js';
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
scheduleAutonomousReportingMarker,
|
|
22
23
|
runInferenceImprovementLight,
|
|
23
24
|
} from '../../hooks/pipeline-hook-runtime.mjs';
|
|
25
|
+
import { maintainLens } from '../../hooks/goggles-pipeline.mjs';
|
|
24
26
|
|
|
25
27
|
function resolveHookEvent(event) {
|
|
26
28
|
if (process.env.GROK_HOOK_EVENT) return process.env.GROK_HOOK_EVENT;
|
|
@@ -115,7 +117,7 @@ async function main() {
|
|
|
115
117
|
try {
|
|
116
118
|
const event = await readStdinJson();
|
|
117
119
|
HOOK_EVENT = resolveHookEvent(event);
|
|
118
|
-
const eventRoot = event.workspaceRoot || event.cwd || root;
|
|
120
|
+
const eventRoot = normalizeWorkspaceRoot(event.workspaceRoot || event.cwd || root);
|
|
119
121
|
const sessionId = resolveSessionId(event);
|
|
120
122
|
if (HOOK_EVENT === 'user_prompt_submit' && sessionId) {
|
|
121
123
|
recordSynthesisTurnSlice(eventRoot, sessionId);
|
|
@@ -149,7 +151,7 @@ async function main() {
|
|
|
149
151
|
const payload = buildSessionBootPayload(eventRoot, source, {
|
|
150
152
|
hookEvent: HOOK_EVENT,
|
|
151
153
|
sessionId: event.sessionId || process.env.GROK_SESSION_ID || null,
|
|
152
|
-
...(intent ? { intent } : {}),
|
|
154
|
+
...(intent ? { intent, cardText: intent } : {}),
|
|
153
155
|
...(matchedSignals.length ? { matchedSignals } : {}),
|
|
154
156
|
});
|
|
155
157
|
|
|
@@ -167,6 +169,9 @@ async function main() {
|
|
|
167
169
|
|
|
168
170
|
try {
|
|
169
171
|
scheduleAutonomousReportingMarker(eventRoot);
|
|
172
|
+
if (HOOK_EVENT === 'pre_compact' || HOOK_EVENT === 'post_compact') {
|
|
173
|
+
maintainLens(eventRoot);
|
|
174
|
+
}
|
|
170
175
|
if (HOOK_EVENT === 'session_start') {
|
|
171
176
|
maybeRunReflectionStub(eventRoot);
|
|
172
177
|
runInferenceImprovementLight(eventRoot);
|