0xray 4.0.30 → 4.0.32

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.
Files changed (49) hide show
  1. package/.grok-plugin/plugin.json +1 -1
  2. package/.mcp.json +8 -0
  3. package/.opencode/skills/orchestrator/SKILL.md +12 -0
  4. package/.xray/features.json +1 -1
  5. package/dist/CHANGELOG.md +17 -0
  6. package/dist/cli/commands/status.d.ts +4 -2
  7. package/dist/cli/commands/status.js +6 -3
  8. package/dist/cli/commands/validate.js +9 -0
  9. package/dist/cli/goggles-status.d.ts +13 -0
  10. package/dist/cli/goggles-status.js +76 -0
  11. package/dist/cli/index.js +41 -2
  12. package/dist/integrations/grok/grok-cli.d.ts +3 -0
  13. package/dist/integrations/grok/grok-cli.js +41 -1
  14. package/dist/integrations/grok/hooks/grok-hook-utils.js +24 -4
  15. package/dist/integrations/grok/hooks/post-tool-use.js +2 -1
  16. package/dist/integrations/grok/hooks/pre-tool-use.js +90 -5
  17. package/dist/integrations/grok/hooks/session-start.js +7 -2
  18. package/dist/integrations/hooks/goggles-mcp.mjs +371 -0
  19. package/dist/integrations/hooks/goggles-pipeline.mjs +632 -0
  20. package/dist/integrations/hooks/goggles-planes.json +28 -0
  21. package/dist/integrations/hooks/plates.cjs +23 -0
  22. package/dist/integrations/hooks/station-hook-runtime.cjs +40 -11
  23. package/dist/integrations/hooks/station-memory-ingest.mjs +3 -0
  24. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  25. package/dist/mcps/orchestrator/config/agent-capabilities.js +7 -0
  26. package/dist/memory-routing/plates.d.ts +1 -1
  27. package/dist/memory-routing/plates.js +5 -0
  28. package/dist/memory-routing/provider-loader.js +2 -0
  29. package/dist/nucleus/thin-dispatch.d.ts +1 -0
  30. package/dist/nucleus/thin-dispatch.js +4 -2
  31. package/dist/skills/orchestrator/SKILL.md +12 -0
  32. package/docs-site/docs/plates/glossary.md +27 -0
  33. package/docs-site/docs/plates/goggles.md +18 -0
  34. package/docs-site/docs/plates/grokbot.md +41 -0
  35. package/docs-site/docs/plates/host-pack.md +32 -0
  36. package/docs-site/docs/plates/house.md +42 -39
  37. package/docs-site/docs/plates/index.md +13 -1
  38. package/docs-site/docs/plates/kits.md +28 -0
  39. package/docs-site/docs/plates/suit.md +40 -0
  40. package/package.json +2 -1
  41. package/scripts/foundry/assert-packed-dist-cli.mjs +9 -0
  42. package/scripts/mjs/run-goggles-mcp.mjs +41 -0
  43. package/scripts/node/bridge-mcp-wiring.cjs +61 -21
  44. package/scripts/node/consumer-install-smoke.mjs +5 -0
  45. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  46. package/src/mcps/orchestrator/config/agent-capabilities.ts +8 -0
  47. package/src/skills/orchestrator/SKILL.md +12 -0
  48. package/vendor/@0xray/repertoire/dist/paths.js +4 -0
  49. package/xray/features.json +1 -1
@@ -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);
@@ -0,0 +1,371 @@
1
+ /**
2
+ * Goggles MCP. Stdio. Server name `goggles`.
3
+ * Tools: look, status_lens. Same organ as the CLI.
4
+ */
5
+ import { existsSync, readFileSync } from 'node:fs';
6
+ import { basename, join, resolve } from 'node:path';
7
+ import { pathToFileURL, fileURLToPath } from 'node:url';
8
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
11
+ import * as bundled from './goggles-pipeline.mjs';
12
+
13
+ const HERE = fileURLToPath(new URL('.', import.meta.url));
14
+ const SERVER_NAME = 'goggles';
15
+ const DRAWING = /docs-site\/docs\/plates\/[a-z0-9-]+\.md/i;
16
+ const CARD_PLANES = [
17
+ 'ground',
18
+ 'routing',
19
+ 'house',
20
+ 'boot',
21
+ 'governance',
22
+ 'memory-recall',
23
+ 'orchestration',
24
+ 'processor',
25
+ 'reporting',
26
+ ];
27
+ const SCOPES = ['ecosystem', 'part', 'one flow', 'one artifact'];
28
+
29
+ const LOOK_SCHEMA = {
30
+ type: 'object',
31
+ additionalProperties: false,
32
+ properties: {
33
+ kind: {
34
+ type: 'string',
35
+ description: 'Optional. Use "0" or "actuality" for the lens. Omit when naming an outer.',
36
+ enum: ['0', 'actuality'],
37
+ },
38
+ outer: {
39
+ type: 'string',
40
+ description: 'One outer name. digest and triage return a card. The others return a reading.',
41
+ enum: ['dichotomy', 'syncopate', 'synthesis', 'digest', 'triage', 'loop'],
42
+ },
43
+ scope: {
44
+ type: 'string',
45
+ description: 'Zoom only. Not a kind. One level.',
46
+ enum: SCOPES,
47
+ },
48
+ plane: {
49
+ type: 'string',
50
+ description: 'Card plane for digest or triage only. Not the lens.',
51
+ enum: CARD_PLANES,
52
+ },
53
+ },
54
+ };
55
+
56
+ export const TOOLS = [
57
+ {
58
+ name: 'look',
59
+ description: 'Kind 0 is quiet on a match. It checks the six outer names. One outer is a reading. digest and triage return a card.',
60
+ inputSchema: LOOK_SCHEMA,
61
+ },
62
+ {
63
+ name: 'status_lens',
64
+ description: 'Whether the organ is worn, and the last Kind 0. Quiet is a match. A missing organ is not drift.',
65
+ inputSchema: { type: 'object', additionalProperties: false, properties: {} },
66
+ },
67
+ ];
68
+
69
+ function serverVersion() {
70
+ try {
71
+ const pkg = JSON.parse(readFileSync(join(HERE, '../../../package.json'), 'utf8'));
72
+ return typeof pkg.version === 'string' && pkg.version ? pkg.version : 'local';
73
+ } catch {
74
+ return 'local';
75
+ }
76
+ }
77
+
78
+ function deny(code, reason) {
79
+ return {
80
+ ok: false,
81
+ quiet: false,
82
+ mode: 'deny',
83
+ content: '',
84
+ error: { gate: 'goggles', decision: 'deny', code, reason },
85
+ };
86
+ }
87
+
88
+ function quiet(mode) {
89
+ return { ok: true, quiet: true, mode, content: '' };
90
+ }
91
+
92
+ async function organApi() {
93
+ const override = typeof process.env.GOGGLES_ORGAN_PATH === 'string'
94
+ ? process.env.GOGGLES_ORGAN_PATH.trim()
95
+ : '';
96
+ if (!override) return bundled;
97
+ if (!existsSync(override)) return null;
98
+ return import(pathToFileURL(override).href);
99
+ }
100
+
101
+ function projectRoot(root) {
102
+ if (typeof root === 'string' && root.trim()) return root;
103
+ const env = process.env.GOGGLES_ROOT;
104
+ if (typeof env === 'string' && env.trim() && env.trim() !== '.') return env.trim();
105
+ return process.cwd();
106
+ }
107
+
108
+ function heldReading(root) {
109
+ try {
110
+ const data = JSON.parse(readFileSync(join(root, '.xray', 'state', 'goggles-reading.json'), 'utf8'));
111
+ if (!data || typeof data !== 'object') return null;
112
+ if (typeof data.drift === 'string' && data.drift) return { drift: data.drift };
113
+ if (typeof data.plane !== 'string' || !data.plane) return null;
114
+ return { plane: data.plane, scope: typeof data.scope === 'string' ? data.scope : '' };
115
+ } catch {
116
+ return null;
117
+ }
118
+ }
119
+
120
+ function denyCode(reason) {
121
+ if (/wider|crosses parts|not one flow/i.test(reason)) return 'scope_wider';
122
+ if (/Name one plane/i.test(reason)) return 'name_one';
123
+ return 'leave_plane';
124
+ }
125
+
126
+ function drawingPaths(args) {
127
+ const hits = [];
128
+ for (const value of Object.values(args)) {
129
+ if (typeof value === 'string' && DRAWING.test(value)) hits.push(value);
130
+ }
131
+ return hits;
132
+ }
133
+
134
+ function argvFrom(args) {
135
+ const words = [];
136
+ if (args.kind === '0') words.push('kind', '0');
137
+ else if (args.kind === 'actuality') words.push('actuality');
138
+ else if (args.kind === '1' || args.kind === '2') words.push('kind', String(args.kind));
139
+ else if (typeof args.kind === 'string') words.push(args.kind);
140
+ if (args.outer === 'outer loop') words.push('outer', 'loop');
141
+ else if (typeof args.outer === 'string') words.push(args.outer);
142
+ if (typeof args.plane === 'string' && !DRAWING.test(args.plane)) words.push(args.plane);
143
+ if (args.scope === 'one flow') words.push('one', 'flow');
144
+ else if (args.scope === 'one artifact') words.push('one', 'artifact');
145
+ else if (typeof args.scope === 'string') words.push(args.scope);
146
+ return words;
147
+ }
148
+
149
+ function pureKind0(args) {
150
+ return (args.kind === '0' || args.kind === 'actuality')
151
+ && args.outer == null
152
+ && args.plane == null
153
+ && args.scope == null;
154
+ }
155
+
156
+ function checkArgs(args) {
157
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
158
+ return deny('invalid_args', 'look takes an object.');
159
+ }
160
+ const allowed = new Set(['kind', 'outer', 'scope', 'plane']);
161
+ for (const key of Object.keys(args)) {
162
+ if (!allowed.has(key)) return deny('invalid_args', 'Unknown argument.');
163
+ }
164
+ for (const key of ['kind', 'outer', 'scope', 'plane']) {
165
+ if (args[key] != null && typeof args[key] !== 'string') {
166
+ return deny('invalid_args', `${key} must be a string.`);
167
+ }
168
+ }
169
+ if (args.kind != null && !['0', 'actuality', '1', '2'].includes(args.kind)) {
170
+ return deny('invalid_args', 'kind is 0 or actuality.');
171
+ }
172
+ if (args.outer != null && !LOOK_SCHEMA.properties.outer.enum.includes(args.outer)) {
173
+ const setName = args.outer === 'outer' || args.outer === 'outer-loop' || args.outer === 'outer loop';
174
+ if (!setName) return deny('invalid_args', 'Name one outer.');
175
+ }
176
+ if (args.scope != null && !SCOPES.includes(args.scope)) {
177
+ return deny('invalid_args', 'scope is one zoom level.');
178
+ }
179
+ if (args.plane != null && !CARD_PLANES.includes(args.plane) && !DRAWING.test(args.plane)) {
180
+ return deny('invalid_args', 'plane is a card plane.');
181
+ }
182
+ return null;
183
+ }
184
+
185
+ function publicCard(view) {
186
+ const notes = [];
187
+ if (view.flavor === 'triage') {
188
+ if (Array.isArray(view.empty) && view.empty.length) notes.push(`Empty: ${view.empty.join(', ')}`);
189
+ if (view.exam) notes.push(view.exam);
190
+ }
191
+ const skills = view.skills ? basename(String(view.skills)) : '';
192
+ if (view.narrow) {
193
+ return {
194
+ plane: view.plane,
195
+ flavor: view.flavor,
196
+ digest: view.digest || '',
197
+ files: Array.isArray(view.files) ? view.files : [],
198
+ notes,
199
+ };
200
+ }
201
+ return {
202
+ plane: view.plane,
203
+ flavor: view.flavor,
204
+ from: view.from || '',
205
+ digest: view.digest || '',
206
+ plate: view.plate || '',
207
+ entry: view.entry || '',
208
+ exit: view.exit || '',
209
+ files: Array.isArray(view.files) ? view.files : [],
210
+ skills,
211
+ setup: view.setup || '',
212
+ teardown: view.teardown || '',
213
+ worn: view.worn || '',
214
+ notes,
215
+ };
216
+ }
217
+
218
+ export async function answerLook(raw, root) {
219
+ if (raw != null && (typeof raw !== 'object' || Array.isArray(raw))) {
220
+ return deny('invalid_args', 'look takes an object.');
221
+ }
222
+ const args = raw && typeof raw === 'object' ? raw : {};
223
+ const bad = checkArgs(args);
224
+ if (bad) return bad;
225
+ const api = await organApi();
226
+ if (!api) return deny('invalid_args', 'Goggles organ not found.');
227
+ const here = projectRoot(root);
228
+ const drawings = drawingPaths(args);
229
+ if (drawings.length) {
230
+ const stop = api.organStop(heldReading(here), { text: drawings.join('\n'), paths: drawings, tool: 'look' });
231
+ if (stop && stop.reason) return deny(denyCode(stop.reason), stop.reason);
232
+ return quiet('reading');
233
+ }
234
+ if (pureKind0(args)) {
235
+ api.maintainLens(here);
236
+ const line = api.actualityLine();
237
+ if (!line) return quiet('kind0');
238
+ return { ok: true, quiet: false, mode: 'kind0', content: line };
239
+ }
240
+ const argv = argvFrom(args);
241
+ const text = api.look(argv).text;
242
+ if (text === 'Name one plane.') return deny('name_one', 'Name one plane.');
243
+ const cards = api.lookCards(argv);
244
+ if (Array.isArray(cards) && cards.length) {
245
+ const shown = cards.map(publicCard);
246
+ return {
247
+ ok: true,
248
+ quiet: false,
249
+ mode: 'card',
250
+ content: shown.length === 1 ? shown[0] : shown,
251
+ outer: args.outer,
252
+ scope: args.scope || null,
253
+ };
254
+ }
255
+ if (!text) {
256
+ if (args.kind === '0' || args.kind === 'actuality') return quiet('kind0');
257
+ if (args.outer === 'digest' || args.outer === 'triage') return quiet('card');
258
+ return quiet('reading');
259
+ }
260
+ if (text.startsWith('Actuality. Drift:')) {
261
+ return { ok: true, quiet: false, mode: 'kind0', content: text };
262
+ }
263
+ return {
264
+ ok: true,
265
+ quiet: false,
266
+ mode: 'reading',
267
+ content: text,
268
+ outer: args.outer ?? null,
269
+ scope: args.scope || null,
270
+ };
271
+ }
272
+
273
+ function lensBody(root) {
274
+ const file = join(root, '.xray', 'state', 'LENS.md');
275
+ if (!existsSync(file)) return { found: false, text: '' };
276
+ try {
277
+ return { found: true, text: readFileSync(file, 'utf8').trim() };
278
+ } catch {
279
+ return { found: false, text: '' };
280
+ }
281
+ }
282
+
283
+ export async function answerStatus(root) {
284
+ const api = await organApi();
285
+ const override = typeof process.env.GOGGLES_ORGAN_PATH === 'string'
286
+ ? process.env.GOGGLES_ORGAN_PATH.trim()
287
+ : '';
288
+ const organPath = override || fileURLToPath(new URL('./goggles-pipeline.mjs', import.meta.url));
289
+ const planesPath = api ? api.planesFile() : '';
290
+ const organOk = existsSync(organPath);
291
+ const planesOk = Boolean(planesPath) && existsSync(planesPath);
292
+ const worn = Boolean(api) && organOk && planesOk;
293
+ const here = projectRoot(root);
294
+ const lens = lensBody(here);
295
+ let kind0 = 'none';
296
+ let kind0Text = '';
297
+ if (lens.found && !lens.text) kind0 = 'quiet';
298
+ else if (lens.found) {
299
+ kind0 = 'drift';
300
+ kind0Text = lens.text;
301
+ } else if (worn) {
302
+ const line = api.actualityLine();
303
+ if (line) {
304
+ kind0 = 'drift';
305
+ kind0Text = line;
306
+ }
307
+ }
308
+ return {
309
+ ok: true,
310
+ organ: worn ? 'worn' : 'not_found',
311
+ organPath: organOk ? organPath : '',
312
+ planesPath: planesOk ? planesPath : '',
313
+ kind0,
314
+ kind0Text,
315
+ lensPath: '.xray/state/LENS.md',
316
+ };
317
+ }
318
+
319
+ export async function dispatchTool(name, args, root) {
320
+ const bare = String(name || '').replace(/^goggles__/, '');
321
+ if (bare === 'status_lens') {
322
+ const input = args && typeof args === 'object' ? args : {};
323
+ if (Object.keys(input).length) {
324
+ return { payload: deny('invalid_args', 'status_lens takes no arguments.'), isError: true };
325
+ }
326
+ return { payload: await answerStatus(root), isError: false };
327
+ }
328
+ if (bare === 'look') {
329
+ const payload = await answerLook(args, root);
330
+ return { payload, isError: payload.mode === 'deny' };
331
+ }
332
+ return { payload: deny('invalid_args', 'Unknown tool.'), isError: true };
333
+ }
334
+
335
+ export function createGogglesServer() {
336
+ const server = new Server(
337
+ { name: SERVER_NAME, version: serverVersion() },
338
+ { capabilities: { tools: {} } },
339
+ );
340
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
341
+ tools: TOOLS.map((tool) => ({
342
+ name: tool.name,
343
+ description: tool.description,
344
+ inputSchema: tool.inputSchema,
345
+ })),
346
+ }));
347
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
348
+ const args = request.params.arguments ?? {};
349
+ const { payload, isError } = await dispatchTool(request.params.name, args, projectRoot());
350
+ return {
351
+ content: [{ type: 'text', text: JSON.stringify(payload) }],
352
+ isError,
353
+ };
354
+ });
355
+ return server;
356
+ }
357
+
358
+ async function main() {
359
+ const server = createGogglesServer();
360
+ const transport = new StdioServerTransport();
361
+ await server.connect(transport);
362
+ }
363
+
364
+ const thisFile = fileURLToPath(import.meta.url);
365
+ const invoked = process.argv[1] ? resolve(process.argv[1]) : '';
366
+ if (invoked && resolve(thisFile) === invoked) {
367
+ main().catch((err) => {
368
+ process.stderr.write(`goggles MCP failed: ${err instanceof Error ? err.message : String(err)}\n`);
369
+ process.exit(1);
370
+ });
371
+ }