0xray 4.0.31 → 4.0.33
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/.mcp.json +8 -0
- package/.opencode/agents/api-design.yml +31 -0
- package/.opencode/agents/architect.yml +15 -0
- package/.opencode/agents/architecture-patterns.yml +14 -0
- package/.opencode/agents/auto-format.yml +14 -0
- package/.opencode/agents/backend-engineer.yml +12 -0
- package/.opencode/agents/boot-orchestrator.yml +14 -0
- package/.opencode/agents/bug-triage-specialist.yml +15 -0
- package/.opencode/agents/code-analyzer.yml +12 -0
- package/.opencode/agents/code-reviewer.yml +14 -0
- package/.opencode/agents/content-creator.yml +12 -0
- package/.opencode/agents/database-engineer.yml +12 -0
- package/.opencode/agents/devops-engineer.yml +12 -0
- package/.opencode/agents/framework-compliance-audit.yml +14 -0
- package/.opencode/agents/frontend-engineer.yml +12 -0
- package/.opencode/agents/frontend-ui-ux-engineer.yml +12 -0
- package/.opencode/agents/git-workflow.yml +15 -0
- package/.opencode/agents/growth-strategist.yml +12 -0
- package/.opencode/agents/hermes-agent.yml +12 -0
- package/.opencode/agents/inference-improve.yml +12 -0
- package/.opencode/agents/lint.yml +14 -0
- package/.opencode/agents/log-monitor.yml +12 -0
- package/.opencode/agents/mobile-developer.yml +12 -0
- package/.opencode/agents/model-health-check.yml +12 -0
- package/.opencode/agents/multimodal-looker.yml +12 -0
- package/.opencode/agents/performance-analysis.yml +12 -0
- package/.opencode/agents/performance-engineer.yml +12 -0
- package/.opencode/agents/performance-optimization.yml +12 -0
- package/.opencode/agents/processor-pipeline.yml +14 -0
- package/.opencode/agents/project-analysis.yml +12 -0
- package/.opencode/agents/refactorer.yml +12 -0
- package/.opencode/agents/researcher.yml +12 -0
- package/.opencode/agents/security-auditor.yml +12 -0
- package/.opencode/agents/security-scan.yml +12 -0
- package/.opencode/agents/seo-consultant.yml +12 -0
- package/.opencode/agents/session-management.yml +12 -0
- package/.opencode/agents/state-manager.yml +12 -0
- package/.opencode/agents/storyteller.yml +12 -0
- package/.opencode/agents/strategist.yml +12 -0
- package/.opencode/agents/tech-writer.yml +12 -0
- package/.opencode/agents/testing-best-practices.yml +12 -0
- package/.opencode/agents/testing-lead.yml +12 -0
- package/.opencode/agents/ui-ux-design.yml +12 -0
- package/.opencode/codex.codex +8 -0
- package/.opencode/commands/auto-format.md +99 -0
- package/.opencode/commands/auto-summary-capture.md +90 -0
- package/.opencode/commands/dependency-audit.md +184 -0
- package/.opencode/commands/enforcer-daily-scan.md +137 -0
- package/.opencode/commands/framework-compliance-audit.md +205 -0
- package/.opencode/commands/interactive-validator.md +75 -0
- package/.opencode/commands/job-summary-logger.md +68 -0
- package/.opencode/commands/lint.md +11 -0
- package/.opencode/commands/mode-switch.md +95 -0
- package/.opencode/commands/model-health-check.md +186 -0
- package/.opencode/commands/performance-analysis.md +144 -0
- package/.opencode/commands/pre-commit-introspection.md +185 -0
- package/.opencode/commands/pre-commit-introspection.sh +133 -0
- package/.opencode/commands/security-scan.md +157 -0
- package/.opencode/commands/sisyphus-validation.md +128 -0
- package/.opencode/commands/summary-logger.md +83 -0
- package/.opencode/enforcer-config.json +282 -0
- package/.opencode/skills/orchestrator/SKILL.md +5 -5
- package/.opencode/workflows/post-deployment-audit.yml +123 -0
- package/.xray/features.json +1 -1
- package/dist/CHANGELOG.md +16 -0
- package/dist/cli/commands/status.d.ts +4 -2
- package/dist/cli/commands/status.js +6 -3
- package/dist/cli/commands/validate.js +4 -0
- package/dist/cli/goggles-status.d.ts +13 -0
- package/dist/cli/goggles-status.js +76 -0
- package/dist/cli/index.js +31 -7
- package/dist/governance/governance-service.js +11 -1
- package/dist/integrations/grok/grok-cli.d.ts +3 -0
- package/dist/integrations/grok/grok-cli.js +41 -1
- package/dist/integrations/grok/hooks/grok-hook-utils.js +7 -4
- package/dist/integrations/grok/hooks/pre-tool-use.js +7 -1
- package/dist/integrations/grok/hooks/session-start.js +5 -2
- package/dist/integrations/hooks/goggles-mcp.mjs +338 -0
- package/dist/integrations/hooks/goggles-pipeline.d.mts +2 -0
- package/dist/integrations/hooks/goggles-pipeline.mjs +485 -100
- package/dist/integrations/hooks/plates.cjs +15 -1
- package/dist/integrations/hooks/station-hook-runtime.cjs +53 -5
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/orchestrator/config/agent-capabilities.js +5 -0
- package/dist/nucleus/thin-dispatch.d.ts +4 -0
- package/dist/nucleus/thin-dispatch.js +9 -1
- package/dist/skills/orchestrator/SKILL.md +5 -5
- package/package.json +2 -1
- package/scripts/foundry/assert-packed-dist-cli.mjs +4 -0
- package/scripts/foundry/mint-suit.cjs +6 -1
- package/scripts/mjs/run-goggles-mcp.mjs +41 -0
- package/scripts/node/bridge-mcp-wiring.cjs +61 -21
- package/scripts/node/install-bridges.cjs +24 -7
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/orchestrator/config/agent-capabilities.ts +4 -0
- package/src/skills/orchestrator/SKILL.md +5 -5
- package/xray/features.json +1 -1
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Usage: npx 0xray status
|
|
12
12
|
*/
|
|
13
|
+
import type { GogglesStatus } from "../goggles-status.js";
|
|
13
14
|
interface StatusReport {
|
|
14
15
|
opencode: {
|
|
15
16
|
installed: boolean;
|
|
@@ -34,8 +35,9 @@ interface StatusReport {
|
|
|
34
35
|
outcomesCount: number;
|
|
35
36
|
patternsCount: number;
|
|
36
37
|
};
|
|
38
|
+
goggles: GogglesStatus;
|
|
37
39
|
}
|
|
38
|
-
export declare function getStatusReport(cwd?: string): StatusReport;
|
|
40
|
+
export declare function getStatusReport(cwd?: string, packageRoot?: string): StatusReport;
|
|
39
41
|
export declare function printStatus(report: StatusReport): void;
|
|
40
|
-
export declare function statusCommand(): Promise<void>;
|
|
42
|
+
export declare function statusCommand(packageRoot?: string): Promise<void>;
|
|
41
43
|
export default statusCommand;
|
|
@@ -14,6 +14,7 @@ import { readdirSync, existsSync, readFileSync } from "fs";
|
|
|
14
14
|
import { join } from "path";
|
|
15
15
|
import { getConfigDir } from "../../core/config-paths.js";
|
|
16
16
|
import { featuresConfigLoader } from "../../core/features-config.js";
|
|
17
|
+
import { formatGogglesStatus, probeGoggles } from "../goggles-status.js";
|
|
17
18
|
function getSkillsList(cwd) {
|
|
18
19
|
const skills = [];
|
|
19
20
|
const configDir = getConfigDir(cwd);
|
|
@@ -119,7 +120,7 @@ function getInferenceStatus(cwd) {
|
|
|
119
120
|
catch { /* ignore */ }
|
|
120
121
|
return { active, lastTuning, outcomesCount, patternsCount };
|
|
121
122
|
}
|
|
122
|
-
export function getStatusReport(cwd = process.cwd()) {
|
|
123
|
+
export function getStatusReport(cwd = process.cwd(), packageRoot = cwd) {
|
|
123
124
|
const opencodeConfigPath = join(cwd, "opencode.json");
|
|
124
125
|
const cwdSkills = getSkillsList(cwd);
|
|
125
126
|
const agents = getAgentsList(cwd);
|
|
@@ -134,6 +135,7 @@ export function getStatusReport(cwd = process.cwd()) {
|
|
|
134
135
|
agents,
|
|
135
136
|
health,
|
|
136
137
|
inference,
|
|
138
|
+
goggles: probeGoggles(packageRoot, cwd),
|
|
137
139
|
};
|
|
138
140
|
}
|
|
139
141
|
export function printStatus(report) {
|
|
@@ -166,6 +168,7 @@ export function printStatus(report) {
|
|
|
166
168
|
console.log(`⚙️ Inference: ${inferenceStatus} (${report.inference.outcomesCount} outcomes, ${report.inference.patternsCount} patterns)`);
|
|
167
169
|
console.log(`📊 Health: ${healthStatus}`);
|
|
168
170
|
console.log("");
|
|
171
|
+
process.stdout.write(`${formatGogglesStatus(report.goggles).join("\n")}\n`);
|
|
169
172
|
if (report.skills.names.length > 0) {
|
|
170
173
|
console.log("Installed Skills:");
|
|
171
174
|
const cols = 4;
|
|
@@ -191,9 +194,9 @@ export function printStatus(report) {
|
|
|
191
194
|
console.log("");
|
|
192
195
|
}
|
|
193
196
|
}
|
|
194
|
-
export async function statusCommand() {
|
|
197
|
+
export async function statusCommand(packageRoot = process.cwd()) {
|
|
195
198
|
const cwd = process.cwd();
|
|
196
|
-
const report = getStatusReport(cwd);
|
|
199
|
+
const report = getStatusReport(cwd, packageRoot);
|
|
197
200
|
printStatus(report);
|
|
198
201
|
}
|
|
199
202
|
export default statusCommand;
|
|
@@ -23,6 +23,10 @@ export const VALIDATE_PACK_PATHS = [
|
|
|
23
23
|
"dist/integrations/cursor/hooks/pre-compact.sh",
|
|
24
24
|
"dist/integrations/cursor/hooks/after-file-edit.sh",
|
|
25
25
|
"dist/integrations/hooks/plates.cjs",
|
|
26
|
+
"dist/integrations/hooks/goggles-pipeline.mjs",
|
|
27
|
+
"dist/integrations/hooks/goggles-planes.json",
|
|
28
|
+
"dist/integrations/hooks/goggles-mcp.mjs",
|
|
29
|
+
"scripts/mjs/run-goggles-mcp.mjs",
|
|
26
30
|
"docs-site/docs/plates/memory-recall.md",
|
|
27
31
|
"docs-site/docs/plates/processor.md",
|
|
28
32
|
"docs-site/docs/plates/goggles.md",
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goggles on status and health.
|
|
3
|
+
* Organ present is not Kind 0. Quiet is a match. No phone-home.
|
|
4
|
+
*/
|
|
5
|
+
export type GogglesStatus = {
|
|
6
|
+
organPresent: boolean;
|
|
7
|
+
kind0Text: string;
|
|
8
|
+
kind0Quiet: boolean;
|
|
9
|
+
kind0Label: string;
|
|
10
|
+
organLine: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function probeGoggles(packageRoot: string, cwd: string): GogglesStatus;
|
|
13
|
+
export declare function formatGogglesStatus(probe: GogglesStatus): string[];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goggles on status and health.
|
|
3
|
+
* Organ present is not Kind 0. Quiet is a match. No phone-home.
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
const WORN_PLANES = ["dichotomy", "syncopate", "synthesis", "digest", "triage", "loop"];
|
|
8
|
+
const ORGAN_PAIRS = [
|
|
9
|
+
["dist/integrations/hooks/goggles-pipeline.mjs", "dist/integrations/hooks/goggles-planes.json"],
|
|
10
|
+
["src/integrations/hooks/goggles-pipeline.mjs", "src/integrations/hooks/goggles-planes.json"],
|
|
11
|
+
];
|
|
12
|
+
function organPair(packageRoot) {
|
|
13
|
+
for (const pair of ORGAN_PAIRS) {
|
|
14
|
+
if (existsSync(join(packageRoot, pair[0])) && existsSync(join(packageRoot, pair[1]))) {
|
|
15
|
+
return pair;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function lensText(cwd) {
|
|
21
|
+
const file = join(cwd, ".xray", "state", "LENS.md");
|
|
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
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
organPresent,
|
|
68
|
+
kind0Text,
|
|
69
|
+
kind0Quiet,
|
|
70
|
+
kind0Label,
|
|
71
|
+
organLine: organPresent ? "Goggles: worn" : "Goggles: not found",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export function formatGogglesStatus(probe) {
|
|
75
|
+
return [probe.organLine, `Kind 0: ${probe.kind0Label}`];
|
|
76
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -76,20 +76,42 @@ program
|
|
|
76
76
|
process.exit(1);
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
|
-
|
|
80
|
-
|
|
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) => {
|
|
79
|
+
const LOOK_HELP = "Kind 0 is quiet on a match. One outer is a reading. digest and triage return a card.";
|
|
80
|
+
function gogglesScript() {
|
|
84
81
|
const built = join(packageRoot, "dist", "integrations", "hooks", "goggles-pipeline.mjs");
|
|
85
82
|
const source = join(packageRoot, "src", "integrations", "hooks", "goggles-pipeline.mjs");
|
|
86
|
-
|
|
83
|
+
return existsSync(built) ? built : source;
|
|
84
|
+
}
|
|
85
|
+
function runGoggles(args) {
|
|
86
|
+
const script = gogglesScript();
|
|
87
|
+
if (!existsSync(script)) {
|
|
88
|
+
process.stderr.write("Goggles: not found\n");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
if (process.stdout.isTTY) {
|
|
92
|
+
const result = spawnSync(process.execPath, [script, ...(args ?? [])], { stdio: "inherit" });
|
|
93
|
+
process.exit(result.status ?? 1);
|
|
94
|
+
}
|
|
87
95
|
const result = spawnSync(process.execPath, [script, ...(args ?? [])], { encoding: "utf8" });
|
|
88
96
|
if (result.stdout)
|
|
89
97
|
process.stdout.write(result.stdout);
|
|
90
98
|
if (result.stderr)
|
|
91
99
|
process.stderr.write(result.stderr);
|
|
92
100
|
process.exit(result.status ?? 1);
|
|
101
|
+
}
|
|
102
|
+
program
|
|
103
|
+
.command("look")
|
|
104
|
+
.argument("[args...]", "kind 0, one outer, or digest/triage and one card plane")
|
|
105
|
+
.description(LOOK_HELP)
|
|
106
|
+
.action((args) => {
|
|
107
|
+
runGoggles(args);
|
|
108
|
+
});
|
|
109
|
+
program
|
|
110
|
+
.command("goggles")
|
|
111
|
+
.argument("[args...]", "same words as look")
|
|
112
|
+
.description(`Same organ as look. ${LOOK_HELP}`)
|
|
113
|
+
.action((args) => {
|
|
114
|
+
runGoggles(args);
|
|
93
115
|
});
|
|
94
116
|
program
|
|
95
117
|
.command("wear")
|
|
@@ -130,7 +152,7 @@ program
|
|
|
130
152
|
.description("Show comprehensive xray framework status")
|
|
131
153
|
.action(async () => {
|
|
132
154
|
const { statusCommand } = await import("./commands/status.js");
|
|
133
|
-
await statusCommand();
|
|
155
|
+
await statusCommand(packageRoot);
|
|
134
156
|
});
|
|
135
157
|
program
|
|
136
158
|
.command("validate")
|
|
@@ -267,6 +289,8 @@ program
|
|
|
267
289
|
}
|
|
268
290
|
}
|
|
269
291
|
console.log("");
|
|
292
|
+
const { probeGoggles, formatGogglesStatus } = await import("./goggles-status.js");
|
|
293
|
+
process.stdout.write(`${formatGogglesStatus(probeGoggles(packageRoot, process.cwd())).join("\n")}\n\n`);
|
|
270
294
|
if (allHealthy) {
|
|
271
295
|
console.log("🎉 Framework is healthy and ready to use!");
|
|
272
296
|
console.log("");
|
|
@@ -21,6 +21,7 @@ import { getGovernanceIntegration, } from '../integrations/governance/index.js';
|
|
|
21
21
|
import { applyDecisionMatrix, calculateMetamorphosisScore, mergeVotes, } from './governance-core.js';
|
|
22
22
|
import { frameworkLogger } from '../core/framework-logger.js';
|
|
23
23
|
import { featuresConfigLoader } from '../core/features-config.js';
|
|
24
|
+
import { lensPlane } from '../integrations/hooks/goggles-pipeline.mjs';
|
|
24
25
|
export class GovernanceService {
|
|
25
26
|
constructor() {
|
|
26
27
|
// We deliberately do *not* cache the integration here.
|
|
@@ -187,12 +188,21 @@ export class GovernanceService {
|
|
|
187
188
|
finalDecision = 'needs_revision';
|
|
188
189
|
}
|
|
189
190
|
}
|
|
191
|
+
const plane = lensPlane(`${proposal.title} ${proposal.description}`);
|
|
192
|
+
const about = [proposal.title, proposal.description, ...(proposal.evidence ?? [])].join('\n');
|
|
193
|
+
let reasoningSummary = merged.reasoningSummary;
|
|
194
|
+
if (plane.files.length > 0 &&
|
|
195
|
+
finalDecision === 'approve' &&
|
|
196
|
+
!plane.files.some((file) => about.includes(file))) {
|
|
197
|
+
finalDecision = 'needs_revision';
|
|
198
|
+
reasoningSummary = `${reasoningSummary} Not about ${plane.files[0]}.`.trim();
|
|
199
|
+
}
|
|
190
200
|
return {
|
|
191
201
|
proposalId: proposal.id,
|
|
192
202
|
finalDecision,
|
|
193
203
|
averageConfidence,
|
|
194
204
|
votes,
|
|
195
|
-
reasoningSummary
|
|
205
|
+
reasoningSummary,
|
|
196
206
|
moralOverride,
|
|
197
207
|
...(metamorphosisScore != null ? { metamorphosisScore } : {}),
|
|
198
208
|
};
|
|
@@ -24,8 +24,11 @@ export interface GrokInstallOptions {
|
|
|
24
24
|
export declare function installForGrokCLI(options?: GrokInstallOptions): Promise<void>;
|
|
25
25
|
/** Grok TUI reads <project>/.grok/config.toml, not the package copy. */
|
|
26
26
|
export declare function writeProjectRepertoireMcp(projectRoot: string): string | null;
|
|
27
|
+
/** Grok TUI reads <project>/.grok/config.toml. The launcher fills GOGGLES_ROOT from cwd. */
|
|
28
|
+
export declare function writeProjectGogglesMcp(projectRoot: string): string | null;
|
|
27
29
|
declare const _default: {
|
|
28
30
|
installForGrokCLI: typeof installForGrokCLI;
|
|
29
31
|
writeProjectRepertoireMcp: typeof writeProjectRepertoireMcp;
|
|
32
|
+
writeProjectGogglesMcp: typeof writeProjectGogglesMcp;
|
|
30
33
|
};
|
|
31
34
|
export default _default;
|
|
@@ -27,7 +27,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
27
27
|
const packageRoot = path.resolve(__dirname, '..', '..', '..');
|
|
28
28
|
const requireCjs = createRequire(import.meta.url);
|
|
29
29
|
const { resolveConsumerTargetDir, patchGrokHooks } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
|
|
30
|
-
const { XRAY_MCP_SERVERS, resolveRepertoireMcp } = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
|
|
30
|
+
const { XRAY_MCP_SERVERS, resolveRepertoireMcp, resolveGogglesMcp } = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
|
|
31
31
|
function registerGrokMcpServers(targetDir) {
|
|
32
32
|
try {
|
|
33
33
|
execSync('which grok', { stdio: 'ignore' });
|
|
@@ -113,6 +113,7 @@ export async function installForGrokCLI(options = {}) {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
writeProjectRepertoireMcp(targetDir);
|
|
116
|
+
writeProjectGogglesMcp(targetDir);
|
|
116
117
|
mintAfterWear(targetDir);
|
|
117
118
|
const primary = dests[0];
|
|
118
119
|
try {
|
|
@@ -177,6 +178,7 @@ function pinGrokPluginToInstalledDist(pluginDir, xrayRoot, targetDir) {
|
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
180
|
const repertoireMcp = resolveRepertoireMcp(targetDir);
|
|
181
|
+
const gogglesMcp = resolveGogglesMcp(targetDir);
|
|
180
182
|
if (mcp.mcpServers) {
|
|
181
183
|
if (repertoireMcp) {
|
|
182
184
|
mcp.mcpServers.repertoire = {
|
|
@@ -187,6 +189,16 @@ function pinGrokPluginToInstalledDist(pluginDir, xrayRoot, targetDir) {
|
|
|
187
189
|
else {
|
|
188
190
|
delete mcp.mcpServers.repertoire;
|
|
189
191
|
}
|
|
192
|
+
if (gogglesMcp) {
|
|
193
|
+
mcp.mcpServers.goggles = {
|
|
194
|
+
command: 'node',
|
|
195
|
+
args: [gogglesMcp],
|
|
196
|
+
env: { GOGGLES_ROOT: targetDir, GOGGLES_PLANES_PATH: '' },
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
delete mcp.mcpServers.goggles;
|
|
201
|
+
}
|
|
190
202
|
}
|
|
191
203
|
fs.writeFileSync(mcpPath, `${JSON.stringify(mcp, null, 2)}\n`);
|
|
192
204
|
}
|
|
@@ -217,7 +229,35 @@ enabled = true
|
|
|
217
229
|
}
|
|
218
230
|
return tomlPath;
|
|
219
231
|
}
|
|
232
|
+
/** Grok TUI reads <project>/.grok/config.toml. The launcher fills GOGGLES_ROOT from cwd. */
|
|
233
|
+
export function writeProjectGogglesMcp(projectRoot) {
|
|
234
|
+
const gogglesMcp = resolveGogglesMcp(projectRoot);
|
|
235
|
+
if (!gogglesMcp)
|
|
236
|
+
return null;
|
|
237
|
+
const grokDir = path.join(projectRoot, '.grok');
|
|
238
|
+
fs.mkdirSync(grokDir, { recursive: true });
|
|
239
|
+
const tomlPath = path.join(grokDir, 'config.toml');
|
|
240
|
+
const block = `[mcp_servers.goggles]
|
|
241
|
+
command = "node"
|
|
242
|
+
args = [${JSON.stringify(gogglesMcp)}]
|
|
243
|
+
enabled = true
|
|
244
|
+
`;
|
|
245
|
+
let existing = '';
|
|
246
|
+
if (fs.existsSync(tomlPath)) {
|
|
247
|
+
existing = fs.readFileSync(tomlPath, 'utf8');
|
|
248
|
+
}
|
|
249
|
+
if (/\[mcp_servers\.goggles\]/.test(existing)) {
|
|
250
|
+
existing = existing.replace(/\[mcp_servers\.goggles\][\s\S]*?(?=\n\[|$)/, block.trim());
|
|
251
|
+
fs.writeFileSync(tomlPath, existing.endsWith('\n') ? existing : `${existing}\n`);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
const prefix = existing.trim() ? `${existing.trim()}\n\n` : '';
|
|
255
|
+
fs.writeFileSync(tomlPath, `${prefix}${block}`);
|
|
256
|
+
}
|
|
257
|
+
return tomlPath;
|
|
258
|
+
}
|
|
220
259
|
export default {
|
|
221
260
|
installForGrokCLI,
|
|
222
261
|
writeProjectRepertoireMcp,
|
|
262
|
+
writeProjectGogglesMcp,
|
|
223
263
|
};
|
|
@@ -330,10 +330,13 @@ export function writeSessionBoot(root, payload) {
|
|
|
330
330
|
fs.mkdirSync(stateDir, { recursive: true });
|
|
331
331
|
fs.writeFileSync(sessionBootPath(root), JSON.stringify(payload, null, 2));
|
|
332
332
|
writeStationMarkdown(root, payload);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
333
|
+
const hook = String((payload && (payload.hookEvent || payload.source)) || "");
|
|
334
|
+
if (!/compact/i.test(hook)) {
|
|
335
|
+
try {
|
|
336
|
+
handCard(root, payload && (payload.cardText || payload.intent));
|
|
337
|
+
} catch {
|
|
338
|
+
/* a missed card must not fail the boot */
|
|
339
|
+
}
|
|
337
340
|
}
|
|
338
341
|
return sessionBootPath(root);
|
|
339
342
|
} catch {
|
|
@@ -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 { cardStop } from '../../hooks/goggles-pipeline.mjs';
|
|
24
|
+
import { cardStop, lensBeforeResearch } from '../../hooks/goggles-pipeline.mjs';
|
|
25
25
|
import { createRequire } from 'node:module';
|
|
26
26
|
import { existsSync } from 'node:fs';
|
|
27
27
|
import { dirname, join } from 'node:path';
|
|
@@ -154,6 +154,12 @@ async function main() {
|
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
const spoken = [cmd, content, toolInput.pattern, toolInput.query, ...(ctx.paths || [])].filter(Boolean).join('\n');
|
|
158
|
+
const lensStop = lensBeforeResearch(eventRoot, toolName, spoken);
|
|
159
|
+
if (lensStop?.decision === 'deny') {
|
|
160
|
+
finish(eventRoot, 'deny', lensStop.reason, null, toolName, { gate: lensStop.gate });
|
|
161
|
+
}
|
|
162
|
+
|
|
157
163
|
const route = repertoireRoute([toolName, cmd, content].filter(Boolean).join(' '));
|
|
158
164
|
|
|
159
165
|
if (isShellTool(toolName) && cmd) {
|
|
@@ -147,11 +147,14 @@ async function main() {
|
|
|
147
147
|
: '0xray/grok-session-start';
|
|
148
148
|
|
|
149
149
|
const intent = extractIntent(event);
|
|
150
|
-
const matchedSignals =
|
|
150
|
+
const matchedSignals =
|
|
151
|
+
HOOK_EVENT === 'user_prompt_submit' ? [] : await matchStationSignals(eventRoot, intent);
|
|
152
|
+
const compact = COMPACT_EVENTS.has(HOOK_EVENT);
|
|
151
153
|
const payload = buildSessionBootPayload(eventRoot, source, {
|
|
152
154
|
hookEvent: HOOK_EVENT,
|
|
153
155
|
sessionId: event.sessionId || process.env.GROK_SESSION_ID || null,
|
|
154
|
-
...(intent ? { intent
|
|
156
|
+
...(intent ? { intent } : {}),
|
|
157
|
+
...(!compact && intent ? { cardText: intent } : {}),
|
|
155
158
|
...(matchedSignals.length ? { matchedSignals } : {}),
|
|
156
159
|
});
|
|
157
160
|
|