0xray 4.0.35 → 4.0.37
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/.xray/features.json +1 -1
- package/dist/CHANGELOG.md +25 -0
- package/dist/analytics/emerging-pattern-detector.d.ts +12 -1
- package/dist/analytics/emerging-pattern-detector.js +37 -12
- package/dist/analytics/pattern-learning-engine.js +1 -9
- package/dist/analytics/predictive-analytics.js +51 -33
- package/dist/analytics/prompt-pattern-analyzer.d.ts +1 -0
- package/dist/analytics/prompt-pattern-analyzer.js +39 -20
- package/dist/analytics/routing-performance-analyzer.d.ts +2 -0
- package/dist/analytics/routing-performance-analyzer.js +89 -37
- package/dist/analytics/simple-pattern-analyzer.d.ts +4 -0
- package/dist/analytics/simple-pattern-analyzer.js +66 -28
- package/dist/architect/architect-tools.d.ts +3 -0
- package/dist/architect/architect-tools.js +22 -0
- package/dist/cli/commands/grok-install.js +1 -1
- package/dist/cli/commands/hermes-install.js +11 -5
- package/dist/cli/commands/openclaw-install.js +13 -7
- package/dist/cli/commands/opencode-install.js +7 -4
- package/dist/cli/commands/suit-monitor.d.ts +30 -0
- package/dist/cli/commands/suit-monitor.js +128 -0
- package/dist/cli/index.js +52 -15
- package/dist/cli/suit-pulse.d.ts +29 -0
- package/dist/cli/suit-pulse.js +270 -0
- package/dist/delegation/agent-delegator.d.ts +4 -2
- package/dist/delegation/agent-delegator.js +46 -27
- package/dist/delegation/agent-expertise.js +2 -1
- package/dist/delegation/analytics/outcome-tracker.d.ts +6 -0
- package/dist/delegation/analytics/outcome-tracker.js +17 -3
- package/dist/delegation/ast-code-parser.d.ts +5 -0
- package/dist/delegation/ast-code-parser.js +53 -48
- package/dist/delegation/codebase-context-analyzer.d.ts +3 -7
- package/dist/delegation/codebase-context-analyzer.js +188 -159
- package/dist/delegation/session-coordinator.js +3 -2
- package/dist/enforcement/loaders/codex-loader.js +18 -14
- package/dist/enforcement/validators/architecture-validators.js +115 -9
- package/dist/governance/codex-policy.service.d.ts +12 -2
- package/dist/governance/codex-policy.service.js +91 -16
- package/dist/integrations/grok/hooks/session-start.js +6 -6
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +6 -6
- package/dist/integrations/hooks/goggles-mcp.mjs +10 -3
- package/dist/integrations/hooks/goggles-pipeline.mjs +221 -44
- package/dist/integrations/hooks/goggles-planes.json +172 -8
- package/dist/integrations/hooks/plates.cjs +138 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +63 -5
- package/dist/integrations/hooks/write-home.cjs +59 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/architect-tools.server.d.ts +6 -0
- package/dist/mcps/architect-tools.server.js +19 -18
- package/dist/mcps/orchestrator/server.d.ts +4 -3
- package/dist/mcps/orchestrator/server.js +29 -17
- package/dist/memory-routing/lookup-cache.d.ts +8 -0
- package/dist/memory-routing/lookup-cache.js +72 -0
- package/dist/memory-routing/plates.d.ts +1 -1
- package/dist/memory-routing/plates.js +26 -0
- package/dist/memory-routing/provider-loader.js +3 -0
- package/dist/metrics/agent-metrics.d.ts +14 -5
- package/dist/metrics/agent-metrics.js +362 -224
- package/dist/nucleus/synthesis-consult-receipt.js +38 -16
- package/dist/orchestrator/enhanced-multi-agent-orchestrator.d.ts +5 -0
- package/dist/orchestrator/enhanced-multi-agent-orchestrator.js +9 -0
- package/dist/orchestrator/multi-agent-orchestration-coordinator.js +1 -2
- package/dist/orchestrator/orchestrator.js +1 -2
- package/dist/processors/implementations/agents-md-validation-processor.d.ts +0 -1
- package/dist/processors/implementations/agents-md-validation-processor.js +0 -11
- package/dist/processors/implementations/console-log-guard-processor.js +39 -50
- package/dist/processors/implementations/performance-budget-processor.d.ts +0 -5
- package/dist/processors/implementations/performance-budget-processor.js +29 -38
- package/dist/processors/implementations/storytelling-trigger-processor.d.ts +5 -0
- package/dist/processors/implementations/storytelling-trigger-processor.js +69 -16
- package/dist/processors/implementations/test-auto-creation-processor.js +39 -36
- package/dist/reporting/framework-reporting-system.d.ts +3 -0
- package/dist/reporting/framework-reporting-system.js +61 -8
- package/dist/reporting/log-parser.js +188 -105
- package/dist/reporting/metrics.js +42 -18
- package/dist/security/prompt-security-validator.js +8 -7
- package/dist/security/security-auditor.d.ts +4 -0
- package/dist/security/security-auditor.js +132 -57
- package/dist/security/security-hardener.d.ts +2 -0
- package/dist/security/security-hardener.js +31 -6
- package/dist/security/security-headers.d.ts +2 -0
- package/dist/security/security-headers.js +23 -21
- package/dist/security/security-scanner.js +18 -4
- package/dist/session/session-cleanup-manager.d.ts +2 -0
- package/dist/session/session-cleanup-manager.js +29 -8
- package/dist/session/session-monitor.d.ts +14 -4
- package/dist/session/session-monitor.js +208 -106
- package/dist/session/session-state-manager.d.ts +11 -0
- package/dist/session/session-state-manager.js +90 -8
- package/docs-site/docs/plates/activity-log.md +38 -0
- package/docs-site/docs/plates/cursor-compact.md +35 -0
- package/docs-site/docs/plates/grok-compact.md +35 -0
- package/docs-site/docs/plates/index.md +25 -3
- package/docs-site/docs/plates/inference-files.md +35 -0
- package/docs-site/docs/plates/kept-line.md +35 -0
- package/docs-site/docs/plates/lens-gate.md +35 -0
- package/docs-site/docs/plates/lens-page.md +35 -0
- package/docs-site/docs/plates/notes-page.md +35 -0
- package/docs-site/docs/plates/package-face.md +35 -0
- package/docs-site/docs/plates/payload-heat.md +35 -0
- package/docs-site/docs/plates/pickup-stamp.md +35 -0
- package/docs-site/docs/plates/pre-tool.md +35 -0
- package/docs-site/docs/plates/record-map.md +41 -0
- package/docs-site/docs/plates/reflection-page.md +35 -0
- package/docs-site/docs/plates/review.md +57 -0
- package/docs-site/docs/plates/session-capture.md +38 -0
- package/docs-site/docs/plates/site-manual.md +35 -0
- package/docs-site/docs/plates/stamp-plate.md +35 -0
- package/docs-site/docs/plates/station-card.md +35 -0
- package/docs-site/docs/plates/station-heat.md +35 -0
- package/docs-site/docs/plates/suit-organs.md +38 -0
- package/docs-site/docs/plates/suit-settings.md +35 -0
- package/docs-site/docs/plates/suit-wear.md +37 -0
- package/docs-site/docs/plates/trail-state.md +35 -0
- package/docs-site/docs/plates/work-fresh.md +35 -0
- package/docs-site/docs/plates/write-home.md +38 -0
- package/package.json +4 -2
- package/scripts/mjs/run-grok-hook.mjs +50 -0
- package/scripts/node/install-bridges.cjs +305 -81
- package/scripts/node/postinstall.cjs +14 -3
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +6 -6
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/architect-tools.server.ts +25 -20
- package/src/mcps/orchestrator/server.ts +33 -19
- package/xray/features.json +1 -1
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/index.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/index.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/mcp/server.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/paths.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/paths.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/confidence-decay.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/confidence-decay.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +0 -1
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +0 -1
- package/vendor/@0xray/repertoire/dist/types.js.map +0 -1
|
@@ -278,6 +278,108 @@ export class ErrorResolutionValidator extends BaseValidator {
|
|
|
278
278
|
return this.createSuccessResult("Error resolution patterns are properly implemented");
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
|
+
/** Code points matched by a non-unicode `\s` in this Node. */
|
|
282
|
+
function isCallWhitespace(ch) {
|
|
283
|
+
const c = ch.charCodeAt(0);
|
|
284
|
+
if (c <= 32) {
|
|
285
|
+
return c === 9 || c === 10 || c === 11 || c === 12 || c === 13 || c === 32;
|
|
286
|
+
}
|
|
287
|
+
if (c >= 0x2000 && c <= 0x200a)
|
|
288
|
+
return true;
|
|
289
|
+
return (c === 0xa0 ||
|
|
290
|
+
c === 0x1680 ||
|
|
291
|
+
c === 0x2028 ||
|
|
292
|
+
c === 0x2029 ||
|
|
293
|
+
c === 0x202f ||
|
|
294
|
+
c === 0x205f ||
|
|
295
|
+
c === 0x3000 ||
|
|
296
|
+
c === 0xfeff);
|
|
297
|
+
}
|
|
298
|
+
/** Per-name scans are cheaper below this; one automaton wins above it. */
|
|
299
|
+
const CALL_SCAN_NAME_THRESHOLD = 48;
|
|
300
|
+
/**
|
|
301
|
+
* Counts `name\\s*\\(` for every name.
|
|
302
|
+
* Suffix hits count (`foo` inside `myfoo(`), matching a separate global regex per name.
|
|
303
|
+
*/
|
|
304
|
+
function countNameCallSites(code, names) {
|
|
305
|
+
if (names.length < CALL_SCAN_NAME_THRESHOLD) {
|
|
306
|
+
return names.map((funcName) => (code.match(new RegExp(`${funcName}\\s*\\(`, "g")) || []).length);
|
|
307
|
+
}
|
|
308
|
+
const counts = new Array(names.length).fill(0);
|
|
309
|
+
if (code.length === 0)
|
|
310
|
+
return counts;
|
|
311
|
+
const nodes = [{ next: new Map(), fail: 0, out: [] }];
|
|
312
|
+
for (let nameIndex = 0; nameIndex < names.length; nameIndex++) {
|
|
313
|
+
const name = names[nameIndex] ?? "";
|
|
314
|
+
let state = 0;
|
|
315
|
+
for (let i = 0; i < name.length; i++) {
|
|
316
|
+
const ch = name.charAt(i);
|
|
317
|
+
const current = nodes[state];
|
|
318
|
+
if (!current)
|
|
319
|
+
break;
|
|
320
|
+
let next = current.next.get(ch);
|
|
321
|
+
if (next === undefined) {
|
|
322
|
+
next = nodes.length;
|
|
323
|
+
nodes.push({ next: new Map(), fail: 0, out: [] });
|
|
324
|
+
current.next.set(ch, next);
|
|
325
|
+
}
|
|
326
|
+
state = next;
|
|
327
|
+
}
|
|
328
|
+
nodes[state]?.out.push(nameIndex);
|
|
329
|
+
}
|
|
330
|
+
const queue = [];
|
|
331
|
+
const root = nodes[0];
|
|
332
|
+
if (!root)
|
|
333
|
+
return counts;
|
|
334
|
+
for (const next of root.next.values())
|
|
335
|
+
queue.push(next);
|
|
336
|
+
let head = 0;
|
|
337
|
+
while (head < queue.length) {
|
|
338
|
+
const currentIndex = queue[head++];
|
|
339
|
+
const current = currentIndex === undefined ? undefined : nodes[currentIndex];
|
|
340
|
+
if (!current)
|
|
341
|
+
continue;
|
|
342
|
+
for (const [ch, childIndex] of current.next) {
|
|
343
|
+
queue.push(childIndex);
|
|
344
|
+
let fail = current.fail;
|
|
345
|
+
while (fail !== 0 && !nodes[fail]?.next.has(ch)) {
|
|
346
|
+
fail = nodes[fail]?.fail ?? 0;
|
|
347
|
+
}
|
|
348
|
+
const down = nodes[fail]?.next.get(ch);
|
|
349
|
+
const child = nodes[childIndex];
|
|
350
|
+
if (!child)
|
|
351
|
+
continue;
|
|
352
|
+
child.fail = down !== undefined && down !== childIndex ? down : 0;
|
|
353
|
+
const failOut = nodes[child.fail]?.out;
|
|
354
|
+
if (failOut && failOut.length > 0) {
|
|
355
|
+
child.out = child.out.concat(failOut);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
let state = 0;
|
|
360
|
+
for (let i = 0; i < code.length; i++) {
|
|
361
|
+
const ch = code.charAt(i);
|
|
362
|
+
while (state !== 0 && !nodes[state]?.next.has(ch)) {
|
|
363
|
+
state = nodes[state]?.fail ?? 0;
|
|
364
|
+
}
|
|
365
|
+
const down = nodes[state]?.next.get(ch);
|
|
366
|
+
state = down === undefined ? 0 : down;
|
|
367
|
+
const outs = nodes[state]?.out;
|
|
368
|
+
if (!outs || outs.length === 0)
|
|
369
|
+
continue;
|
|
370
|
+
let k = i + 1;
|
|
371
|
+
while (k < code.length && isCallWhitespace(code.charAt(k)))
|
|
372
|
+
k++;
|
|
373
|
+
if (code.charAt(k) !== "(")
|
|
374
|
+
continue;
|
|
375
|
+
for (const nameIndex of outs) {
|
|
376
|
+
const current = counts[nameIndex];
|
|
377
|
+
if (current !== undefined)
|
|
378
|
+
counts[nameIndex] = current + 1;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return counts;
|
|
382
|
+
}
|
|
281
383
|
/**
|
|
282
384
|
* Validates loop safety (Codex Term #8).
|
|
283
385
|
* Prevents infinite loops by checking for proper termination conditions.
|
|
@@ -322,15 +424,19 @@ export class LoopSafetyValidator extends BaseValidator {
|
|
|
322
424
|
// Check for recursion without base case detection (basic)
|
|
323
425
|
const functionMatches = newCode.match(/function\s+\w+\s*\([^)]*\)/g);
|
|
324
426
|
if (functionMatches) {
|
|
325
|
-
const functionNames =
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
427
|
+
const functionNames = [];
|
|
428
|
+
for (const match of functionMatches) {
|
|
429
|
+
const name = match.match(/function\s+(\w+)/)?.[1];
|
|
430
|
+
if (name)
|
|
431
|
+
functionNames.push(name);
|
|
432
|
+
}
|
|
433
|
+
const callCounts = countNameCallSites(newCode, functionNames);
|
|
434
|
+
for (let i = 0; i < functionNames.length; i++) {
|
|
435
|
+
const funcName = functionNames[i];
|
|
436
|
+
if (!funcName)
|
|
437
|
+
continue;
|
|
438
|
+
// Same count a per-name /name\s*\(/g scan would return, including suffix hits.
|
|
439
|
+
const selfCalls = callCounts[i] ?? 0;
|
|
334
440
|
if (selfCalls > 1) {
|
|
335
441
|
// More than just the function definition
|
|
336
442
|
// Allow recursive functions with proper base cases (edge case)
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* - Returns ActiveCodexSnapshot compatible with the existing get_active_codex MCP tool.
|
|
16
16
|
* - Provides getTermCount() with safe 60-term fallback (preserves prior behavior of bypasses).
|
|
17
17
|
* - Full frameworkLogger discipline on every load/decision/error.
|
|
18
|
-
* -
|
|
18
|
+
* - Reuses one parsed codex while that file still wins and its mtime and size are unchanged.
|
|
19
|
+
* - No mutation of the cached codex; no enforcement.
|
|
19
20
|
*
|
|
20
21
|
* First wired consumer: src/mcps/enforcer-tools.server.ts (getCodexTermCount bypass removed;
|
|
21
22
|
* now delegates through this service).
|
|
@@ -34,9 +35,18 @@ import type { ActiveCodexSnapshot, ICodexPolicyProvider } from './governance-typ
|
|
|
34
35
|
*/
|
|
35
36
|
export declare class CodexPolicyService implements ICodexPolicyProvider {
|
|
36
37
|
private readonly component;
|
|
38
|
+
/**
|
|
39
|
+
* Winning parse. Invalid when a higher-priority path appears or mtime/size changes,
|
|
40
|
+
* so the next check still parses the bytes a fresh load would have read.
|
|
41
|
+
*/
|
|
42
|
+
private codexCache;
|
|
43
|
+
private candidateKey;
|
|
44
|
+
private fileIdentity;
|
|
45
|
+
private cachedRaw;
|
|
37
46
|
/**
|
|
38
47
|
* Internal loader: resolves candidates, picks first existing, reads + parses.
|
|
39
|
-
*
|
|
48
|
+
* Repeat calls skip the read and JSON.parse while the winning file is unchanged.
|
|
49
|
+
* Logs via frameworkLogger on load, error, and fallback (not on a cache hit).
|
|
40
50
|
*/
|
|
41
51
|
private loadRaw;
|
|
42
52
|
private computeTermCount;
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* - Returns ActiveCodexSnapshot compatible with the existing get_active_codex MCP tool.
|
|
16
16
|
* - Provides getTermCount() with safe 60-term fallback (preserves prior behavior of bypasses).
|
|
17
17
|
* - Full frameworkLogger discipline on every load/decision/error.
|
|
18
|
-
* -
|
|
18
|
+
* - Reuses one parsed codex while that file still wins and its mtime and size are unchanged.
|
|
19
|
+
* - No mutation of the cached codex; no enforcement.
|
|
19
20
|
*
|
|
20
21
|
* First wired consumer: src/mcps/enforcer-tools.server.ts (getCodexTermCount bypass removed;
|
|
21
22
|
* now delegates through this service).
|
|
@@ -29,51 +30,125 @@
|
|
|
29
30
|
*/
|
|
30
31
|
import { frameworkLogger } from '../core/framework-logger.js';
|
|
31
32
|
import { resolveCodexPath } from '../core/config-paths.js';
|
|
32
|
-
import { existsSync } from 'fs';
|
|
33
|
+
import { existsSync, statSync } from 'fs';
|
|
33
34
|
import * as fs from 'fs/promises';
|
|
35
|
+
/** mtimeNs when the stat has it. mtimeMs only when it does not. */
|
|
36
|
+
function codexClock(fileStat) {
|
|
37
|
+
const nanos = fileStat.mtimeNs;
|
|
38
|
+
if (typeof nanos === 'bigint')
|
|
39
|
+
return nanos.toString();
|
|
40
|
+
if (typeof nanos === 'number' && Number.isFinite(nanos))
|
|
41
|
+
return String(nanos);
|
|
42
|
+
if (typeof fileStat.mtimeMs === 'number' && Number.isFinite(fileStat.mtimeMs)) {
|
|
43
|
+
return String(fileStat.mtimeMs);
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
34
47
|
/**
|
|
35
48
|
* Canonical implementation of the Governance Codex/Policy provider.
|
|
36
49
|
* Single owner of the "first read" of any codex.json for the framework.
|
|
37
50
|
*/
|
|
38
51
|
export class CodexPolicyService {
|
|
39
52
|
component = 'codex-policy-service';
|
|
53
|
+
/**
|
|
54
|
+
* Winning parse. Invalid when a higher-priority path appears or mtime/size changes,
|
|
55
|
+
* so the next check still parses the bytes a fresh load would have read.
|
|
56
|
+
*/
|
|
57
|
+
codexCache = null;
|
|
58
|
+
candidateKey(candidates) {
|
|
59
|
+
return JSON.stringify(candidates);
|
|
60
|
+
}
|
|
61
|
+
fileIdentity(sourcePath) {
|
|
62
|
+
try {
|
|
63
|
+
const fileStat = statSync(sourcePath);
|
|
64
|
+
if (!fileStat.isFile())
|
|
65
|
+
return null;
|
|
66
|
+
const clock = codexClock(fileStat);
|
|
67
|
+
if (clock === null)
|
|
68
|
+
return null;
|
|
69
|
+
return `${clock}:${fileStat.size}`;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
cachedRaw(candidates) {
|
|
76
|
+
const cached = this.codexCache;
|
|
77
|
+
if (!cached || cached.candidateKey !== this.candidateKey(candidates))
|
|
78
|
+
return null;
|
|
79
|
+
for (let i = 0; i < cached.index; i++) {
|
|
80
|
+
const higher = candidates[i];
|
|
81
|
+
if (higher && existsSync(higher))
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const identity = this.fileIdentity(cached.sourcePath);
|
|
85
|
+
if (!identity || identity !== cached.identity)
|
|
86
|
+
return null;
|
|
87
|
+
return cached.raw;
|
|
88
|
+
}
|
|
40
89
|
/**
|
|
41
90
|
* Internal loader: resolves candidates, picks first existing, reads + parses.
|
|
42
|
-
*
|
|
91
|
+
* Repeat calls skip the read and JSON.parse while the winning file is unchanged.
|
|
92
|
+
* Logs via frameworkLogger on load, error, and fallback (not on a cache hit).
|
|
43
93
|
*/
|
|
44
94
|
async loadRaw() {
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
?
|
|
48
|
-
:
|
|
49
|
-
|
|
95
|
+
const resolved = resolveCodexPath();
|
|
96
|
+
const candidates = Array.isArray(resolved)
|
|
97
|
+
? resolved
|
|
98
|
+
: resolved
|
|
99
|
+
? [resolved]
|
|
100
|
+
: [];
|
|
101
|
+
const hit = this.cachedRaw(candidates);
|
|
102
|
+
if (hit)
|
|
103
|
+
return hit;
|
|
104
|
+
const index = candidates.findIndex((candidate) => existsSync(candidate));
|
|
105
|
+
const indexed = index >= 0 ? candidates[index] : undefined;
|
|
106
|
+
const sourcePath = indexed ?? candidates[0] ?? null;
|
|
107
|
+
if (index < 0 || !sourcePath) {
|
|
108
|
+
this.codexCache = null;
|
|
50
109
|
await frameworkLogger.log(this.component, 'codex-not-found', 'warning', {
|
|
51
110
|
candidates,
|
|
52
|
-
resolvedPath,
|
|
111
|
+
resolvedPath: sourcePath,
|
|
53
112
|
message: 'No codex.json found in standard locations; using fallback behavior',
|
|
54
113
|
});
|
|
55
|
-
return { path:
|
|
114
|
+
return { path: sourcePath, data: this.getBuiltinFallback(), isFallback: true };
|
|
56
115
|
}
|
|
57
116
|
try {
|
|
58
|
-
const
|
|
117
|
+
const before = this.fileIdentity(sourcePath);
|
|
118
|
+
const content = await fs.readFile(sourcePath, 'utf-8');
|
|
59
119
|
const data = JSON.parse(content);
|
|
60
120
|
const termCount = this.computeTermCount(data);
|
|
121
|
+
const raw = { path: sourcePath, data, isFallback: false };
|
|
122
|
+
const after = this.fileIdentity(sourcePath);
|
|
123
|
+
if (before && after && before === after) {
|
|
124
|
+
this.codexCache = {
|
|
125
|
+
candidateKey: this.candidateKey(candidates),
|
|
126
|
+
index,
|
|
127
|
+
sourcePath,
|
|
128
|
+
identity: after,
|
|
129
|
+
raw,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
this.codexCache = null;
|
|
134
|
+
}
|
|
61
135
|
await frameworkLogger.log(this.component, 'codex-loaded', 'success', {
|
|
62
|
-
source:
|
|
136
|
+
source: sourcePath,
|
|
63
137
|
version: data?.version || 'unknown',
|
|
64
138
|
termCount,
|
|
65
139
|
lastUpdated: data?.lastUpdated,
|
|
66
140
|
});
|
|
67
|
-
return
|
|
141
|
+
return raw;
|
|
68
142
|
}
|
|
69
143
|
catch (error) {
|
|
144
|
+
this.codexCache = null;
|
|
70
145
|
const msg = error instanceof Error ? error.message : String(error);
|
|
71
146
|
await frameworkLogger.log(this.component, 'codex-load-error', 'error', {
|
|
72
|
-
source:
|
|
147
|
+
source: sourcePath,
|
|
73
148
|
error: msg,
|
|
74
149
|
});
|
|
75
150
|
// Safe fallback (never break callers)
|
|
76
|
-
return { path:
|
|
151
|
+
return { path: sourcePath, data: this.getBuiltinFallback(), isFallback: true };
|
|
77
152
|
}
|
|
78
153
|
}
|
|
79
154
|
computeTermCount(data) {
|
|
@@ -121,7 +196,7 @@ export class CodexPolicyService {
|
|
|
121
196
|
? 'Governance CodexPolicyService — builtin fallback (no external codex.json resolved)'
|
|
122
197
|
: 'Returned via Governance CodexPolicyService — V2 Single Source of Truth (S02-REAL)',
|
|
123
198
|
dynamo_required: true,
|
|
124
|
-
...(includeRaw ? { codex: data } : {}),
|
|
199
|
+
...(includeRaw ? { codex: structuredClone(data) } : {}),
|
|
125
200
|
};
|
|
126
201
|
await frameworkLogger.log(this.component, 'get-current-codex', 'info', {
|
|
127
202
|
source: path,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Grok SessionStart / UserPromptSubmit / PreCompact / PostCompact.
|
|
4
|
-
*
|
|
4
|
+
* Compact prints nothing. Station heat is session-boot.json + STATION.md.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import {
|
|
@@ -148,9 +148,10 @@ async function main() {
|
|
|
148
148
|
: '0xray/grok-session-start';
|
|
149
149
|
|
|
150
150
|
const intent = extractIntent(event);
|
|
151
|
-
const matchedSignals =
|
|
152
|
-
HOOK_EVENT === 'user_prompt_submit' ? [] : await matchStationSignals(eventRoot, intent);
|
|
153
151
|
const compact = COMPACT_EVENTS.has(HOOK_EVENT);
|
|
152
|
+
// The compact payload is the whole conversation. Do not match it and do not print it.
|
|
153
|
+
const matchedSignals =
|
|
154
|
+
compact || HOOK_EVENT === 'user_prompt_submit' ? [] : await matchStationSignals(eventRoot, intent);
|
|
154
155
|
let freshnessLine = null;
|
|
155
156
|
if (!compact) {
|
|
156
157
|
try {
|
|
@@ -164,8 +165,7 @@ async function main() {
|
|
|
164
165
|
const payload = buildSessionBootPayload(eventRoot, source, {
|
|
165
166
|
hookEvent: HOOK_EVENT,
|
|
166
167
|
sessionId: event.sessionId || process.env.GROK_SESSION_ID || null,
|
|
167
|
-
...(intent ? { intent } : {}),
|
|
168
|
-
...(!compact && intent ? { cardText: intent } : {}),
|
|
168
|
+
...(!compact && intent ? { intent, cardText: intent } : {}),
|
|
169
169
|
...(matchedSignals.length ? { matchedSignals } : {}),
|
|
170
170
|
...(freshnessLine ? { freshnessLine } : {}),
|
|
171
171
|
});
|
|
@@ -195,7 +195,7 @@ async function main() {
|
|
|
195
195
|
/* non-blocking pipeline facets */
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
console.log(JSON.stringify(payload));
|
|
198
|
+
if (!compact) console.log(JSON.stringify(payload));
|
|
199
199
|
process.exit(0);
|
|
200
200
|
} catch (err) {
|
|
201
201
|
appendHookActivity(root, 'grok-session-start', 'session-boot-error', 'error', {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"hooks": [
|
|
6
6
|
{
|
|
7
7
|
"type": "command",
|
|
8
|
-
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/
|
|
8
|
+
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/scripts/mjs/run-grok-hook.mjs\" pre-tool-use.js",
|
|
9
9
|
"timeout": 30
|
|
10
10
|
}
|
|
11
11
|
]
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"hooks": [
|
|
17
17
|
{
|
|
18
18
|
"type": "command",
|
|
19
|
-
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/
|
|
19
|
+
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/scripts/mjs/run-grok-hook.mjs\" session-start.js",
|
|
20
20
|
"timeout": 30
|
|
21
21
|
}
|
|
22
22
|
]
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "command",
|
|
30
|
-
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/
|
|
30
|
+
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/scripts/mjs/run-grok-hook.mjs\" session-start.js --hook-event=user_prompt_submit",
|
|
31
31
|
"timeout": 30
|
|
32
32
|
}
|
|
33
33
|
]
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"hooks": [
|
|
39
39
|
{
|
|
40
40
|
"type": "command",
|
|
41
|
-
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/
|
|
41
|
+
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/scripts/mjs/run-grok-hook.mjs\" post-tool-use.js",
|
|
42
42
|
"timeout": 30
|
|
43
43
|
}
|
|
44
44
|
]
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"hooks": [
|
|
50
50
|
{
|
|
51
51
|
"type": "command",
|
|
52
|
-
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/
|
|
52
|
+
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/scripts/mjs/run-grok-hook.mjs\" session-start.js --hook-event=pre_compact",
|
|
53
53
|
"timeout": 30
|
|
54
54
|
}
|
|
55
55
|
]
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"hooks": [
|
|
61
61
|
{
|
|
62
62
|
"type": "command",
|
|
63
|
-
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/
|
|
63
|
+
"command": "XRAY_AI_PATH=\"${XRAY_AI_PATH:-node_modules/0xray}\" node \"${XRAY_AI_PATH:-node_modules/0xray}/scripts/mjs/run-grok-hook.mjs\" session-start.js --hook-event=post_compact",
|
|
64
64
|
"timeout": 30
|
|
65
65
|
}
|
|
66
66
|
]
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Goggles MCP. Stdio. Server name `goggles`.
|
|
3
3
|
* Tools: look, status_lens. Same organ as the CLI.
|
|
4
4
|
*/
|
|
5
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs';
|
|
6
6
|
import { basename, join, resolve } from 'node:path';
|
|
7
7
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
8
8
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
@@ -328,9 +328,16 @@ async function main() {
|
|
|
328
328
|
await server.connect(transport);
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
function sameInvoked(argvPath, modulePath) {
|
|
332
|
+
try {
|
|
333
|
+
return realpathSync(argvPath) === realpathSync(modulePath);
|
|
334
|
+
} catch {
|
|
335
|
+
return resolve(argvPath) === resolve(modulePath);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
331
339
|
const thisFile = fileURLToPath(import.meta.url);
|
|
332
|
-
|
|
333
|
-
if (invoked && resolve(thisFile) === invoked) {
|
|
340
|
+
if (process.argv[1] && sameInvoked(process.argv[1], thisFile)) {
|
|
334
341
|
main().catch((err) => {
|
|
335
342
|
process.stderr.write(`goggles MCP failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
336
343
|
process.exit(1);
|