0xray 3.5.4 → 4.0.0
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/.mcp.json +51 -7
- package/.opencode/skills/api-design/SKILL.md +1 -1
- package/.opencode/skills/architect-tools/SKILL.md +1 -1
- package/.opencode/skills/architecture-patterns/SKILL.md +1 -1
- package/.opencode/skills/auto-format/SKILL.md +1 -1
- package/.opencode/skills/boot-orchestrator/SKILL.md +2 -6
- package/.opencode/skills/bug-triage/SKILL.md +1 -1
- package/.opencode/skills/code-analyzer/SKILL.md +1 -1
- package/.opencode/skills/code-review/SKILL.md +1 -1
- package/.opencode/skills/enforcer/SKILL.md +1 -1
- package/.opencode/skills/framework-compliance-audit/SKILL.md +1 -1
- package/.opencode/skills/git-workflow/SKILL.md +1 -1
- package/.opencode/skills/hermes-agent/SKILL.md +36 -36
- package/.opencode/skills/inference-improve/SKILL.md +1 -1
- package/.opencode/skills/lint/SKILL.md +1 -1
- package/.opencode/skills/log-monitor/SKILL.md +1 -1
- package/.opencode/skills/model-health-check/SKILL.md +1 -1
- package/.opencode/skills/multimodal-looker/SKILL.md +1 -1
- package/.opencode/skills/orchestrator/SKILL.md +38 -14
- package/.opencode/skills/performance-analysis/SKILL.md +1 -1
- package/.opencode/skills/performance-optimization/SKILL.md +1 -1
- package/.opencode/skills/processor-pipeline/SKILL.md +1 -1
- package/.opencode/skills/project-analysis/SKILL.md +1 -1
- package/.opencode/skills/refactoring-strategies/SKILL.md +1 -1
- package/.opencode/skills/registry.json +65 -0
- package/.opencode/skills/researcher/SKILL.md +18 -5
- package/.opencode/skills/security-audit/SKILL.md +1 -1
- package/.opencode/skills/security-scan/SKILL.md +1 -1
- package/.opencode/skills/session-management/SKILL.md +1 -1
- package/.opencode/skills/state-manager/SKILL.md +1 -1
- package/.opencode/skills/storyteller/SKILL.md +1 -1
- package/.opencode/skills/strategist/SKILL.md +12 -0
- package/.opencode/skills/testing-best-practices/SKILL.md +37 -0
- package/.opencode/skills/testing-strategy/SKILL.md +14 -3
- package/.opencode/skills/ui-ux-design/SKILL.md +1 -1
- package/.opencode/skills/xray-orchestrator/index.ts +267 -0
- package/.xray/codex.json +12 -3
- package/.xray/features.json +32 -6
- package/.xray/features.schema.json +87 -0
- package/AGENTS-consumer.md +16 -6
- package/AGENTS.md +21 -3
- package/README.md +13 -10
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +21 -3
- package/dist/CHANGELOG.md +98 -0
- package/dist/README.md +13 -10
- package/dist/SKILLS.md +1 -1
- package/dist/cli/commands/hermes-install.js +6 -1
- package/dist/cli/commands/openclaw-install.js +14 -0
- package/dist/cli/index.js +0 -0
- package/dist/core/features-config.d.ts +30 -2
- package/dist/governance/governance-service.d.ts +1 -0
- package/dist/governance/governance-service.js +81 -6
- package/dist/infrastructure/schemas/cloud-schemas.d.ts +1 -1
- package/dist/integrations/enforcement-gate.js +15 -5
- package/dist/integrations/grok/grok-cli.d.ts +3 -0
- package/dist/integrations/grok/grok-cli.js +92 -13
- package/dist/integrations/grok/hooks/grok-hook-utils.js +99 -9
- package/dist/integrations/grok/hooks/post-tool-use.js +68 -25
- package/dist/integrations/grok/hooks/pre-tool-use.js +17 -14
- package/dist/integrations/grok/hooks/session-start.js +114 -4
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
- package/dist/integrations/hermes-agent/__init__.py +11 -1
- package/dist/integrations/hermes-agent/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/integrations/hermes-agent/__pycache__/schemas.cpython-313.pyc +0 -0
- package/dist/integrations/hermes-agent/__pycache__/tools.cpython-313.pyc +0 -0
- package/dist/integrations/hermes-agent/bridge.mjs +92 -11
- package/dist/integrations/hooks/confer-hook-runtime.mjs +49 -0
- package/dist/integrations/hooks/delegation-gate-runtime.mjs +32 -3
- package/dist/integrations/hooks/pipeline-hook-runtime.mjs +211 -0
- package/dist/integrations/hooks/plan-hook-runtime.mjs +68 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +421 -0
- package/dist/integrations/hooks/station-hook-runtime.mjs +24 -0
- package/dist/integrations/hooks/station-memory-ingest.mjs +45 -0
- package/dist/integrations/hooks/station-memory-match.mjs +47 -0
- package/dist/integrations/hooks/user-aside-hook-runtime.mjs +49 -0
- package/dist/integrations/openclaw/client.d.ts +5 -1
- package/dist/integrations/openclaw/client.js +17 -9
- package/dist/integrations/openclaw/config.js +0 -1
- package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +102 -0
- package/dist/integrations/openclaw/index.js +17 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
- package/dist/integrations/openclaw/pre-tool-gate.d.ts +19 -0
- package/dist/integrations/openclaw/pre-tool-gate.js +39 -0
- package/dist/mcps/architect-tools.server.js +6 -1
- package/dist/mcps/orchestrator/handlers/complexity-handler.d.ts +7 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +107 -8
- package/dist/mcps/orchestrator/handlers/task-handler.d.ts +6 -0
- package/dist/mcps/orchestrator/handlers/task-handler.js +75 -0
- package/dist/mcps/orchestrator/server.js +54 -5
- package/dist/memory-routing/index.d.ts +1 -1
- package/dist/memory-routing/index.js +1 -1
- package/dist/memory-routing/provider-loader.d.ts +4 -0
- package/dist/memory-routing/provider-loader.js +74 -4
- package/dist/memory-routing/provider-registry.js +3 -2
- package/dist/nucleus/aside-worktree.d.ts +41 -0
- package/dist/nucleus/aside-worktree.js +164 -0
- package/dist/nucleus/autonomy-kernel.d.ts +2 -2
- package/dist/nucleus/autonomy-kernel.js +17 -6
- package/dist/nucleus/confer.d.ts +57 -0
- package/dist/nucleus/confer.js +322 -0
- package/dist/nucleus/delegation-gate.d.ts +18 -8
- package/dist/nucleus/delegation-gate.js +234 -20
- package/dist/nucleus/lead-dev-plan-persistence.d.ts +27 -3
- package/dist/nucleus/lead-dev-plan-persistence.js +201 -19
- package/dist/nucleus/spawn-plan-resolution.d.ts +20 -0
- package/dist/nucleus/spawn-plan-resolution.js +42 -0
- package/dist/nucleus/suit-temperament.d.ts +40 -0
- package/dist/nucleus/suit-temperament.js +157 -0
- package/dist/nucleus/synthesis-consult-receipt.js +18 -2
- package/dist/nucleus/synthesis-context.js +1 -1
- package/dist/nucleus/user-aside.d.ts +70 -0
- package/dist/nucleus/user-aside.js +393 -0
- package/dist/plugin/xray-codex-injection.js +14 -3
- package/dist/postprocessor/PostProcessor.d.ts +1 -0
- package/dist/postprocessor/PostProcessor.js +11 -0
- package/dist/postprocessor/triggers/GitHookTrigger.js +11 -5
- package/dist/processors/implementations/session-summary-processor.d.ts +1 -1
- package/dist/processors/implementations/session-summary-processor.js +9 -6
- package/opencode.json +88 -0
- package/package.json +25 -6
- package/scripts/hooks/install-hooks.cjs +21 -6
- package/scripts/hooks/run-hook.js +237 -88
- package/scripts/mjs/run-repertoire-mcp.mjs +39 -0
- package/scripts/mjs/verify-confer-core.mjs +103 -0
- package/scripts/mjs/verify-delegation-gate-core.mjs +76 -3
- package/scripts/mjs/verify-four-floor-compact.mjs +524 -0
- package/scripts/mjs/verify-hermes-session-start.mjs +137 -0
- package/scripts/mjs/verify-pipeline-facets.mjs +215 -0
- package/scripts/mjs/verify-pre-push-diff-core.mjs +87 -0
- package/scripts/mjs/verify-temperament-live.mjs +261 -0
- package/scripts/mjs/verify-user-aside-core.mjs +137 -0
- package/scripts/node/bridge-mcp-wiring.cjs +287 -29
- package/scripts/node/install-bridges.cjs +198 -44
- package/scripts/node/load-reflection-config.mjs +2 -2
- package/scripts/node/postinstall.cjs +50 -27
- package/scripts/node/release-gate.mjs +8 -4
- package/scripts/node/release.mjs +2 -2
- package/scripts/node/validate-release-docs.mjs +20 -33
- package/scripts/node/version-manager.mjs +25 -10
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
- package/src/integrations/openclaw/README.md +134 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
- package/src/mcps/architect-tools.server.ts +6 -1
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +180 -21
- package/src/mcps/orchestrator/handlers/task-handler.ts +99 -0
- package/src/mcps/orchestrator/server.ts +56 -5
- package/vendor/@0xray/repertoire/AGENTS.md +163 -0
- package/vendor/@0xray/repertoire/LICENSE +21 -0
- package/vendor/@0xray/repertoire/README.md +120 -0
- package/vendor/@0xray/repertoire/data/curated_signals.json +208 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +78 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.js +153 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts +39 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js +60 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/index.d.ts +14 -0
- package/vendor/@0xray/repertoire/dist/index.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/index.js +14 -0
- package/vendor/@0xray/repertoire/dist/index.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts +26 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js +109 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts +18 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js +94 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts +7 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js +18 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts +31 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js +83 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts +6 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.js +173 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts +27 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js +107 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts +11 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js +32 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts +9 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +72 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts +5 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js +18 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts +31 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +218 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/paths.d.ts +24 -0
- package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/paths.js +74 -0
- package/vendor/@0xray/repertoire/dist/paths.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +141 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +210 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +48 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +221 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts +11 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js +43 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts +15 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js +35 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts +3 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js +24 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts +24 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js +148 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts +4 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js +44 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts +22 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js +66 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/types.d.ts +210 -0
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/types.js +2 -0
- package/vendor/@0xray/repertoire/dist/types.js.map +1 -0
- package/vendor/@0xray/repertoire/docs/MEMORY-ROUTING-PROVIDER.md +54 -0
- package/vendor/@0xray/repertoire/hermes-mcp.example.json +20 -0
- package/vendor/@0xray/repertoire/mcp-config.example.json +11 -0
- package/vendor/@0xray/repertoire/package.json +124 -0
- package/vendor/@0xray/repertoire/schemas/curated-signal.schema.json +68 -0
- package/vendor/@0xray/repertoire/schemas/inference-log.schema.json +82 -0
- package/vendor/@0xray/repertoire/scripts/confirm-suit-all.mjs +253 -0
- package/vendor/@0xray/repertoire/scripts/confirm-suit-harness.mjs +220 -0
- package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +215 -0
- package/vendor/@0xray/repertoire/scripts/suit-bridge-shared.mjs +139 -0
- package/vendor/@0xray/repertoire/scripts/verify-grok-suit.mjs +304 -0
- package/vendor/@0xray/repertoire/scripts/verify-hermes-suit.mjs +163 -0
- package/vendor/@0xray/repertoire/scripts/verify-openclaw-suit.mjs +125 -0
- package/vendor/@0xray/repertoire/scripts/verify-opencode-suit.mjs +127 -0
- package/vendor/@0xray/repertoire/scripts/verify-synthesis-dogfood.mjs +207 -0
- package/vendor/@0xray/repertoire/skills/repertoire-trap-handling/SKILL.md +206 -0
- package/xray/codex.json +12 -3
- package/xray/features.json +32 -6
- package/xray/features.schema.json +87 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Live synthesis checkpoint driver — repertoire core (real .xray/state, not tmp).
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node scripts/run-live-synthesis-checkpoint.mjs seed [--session-id=ID]
|
|
7
|
+
* node scripts/run-live-synthesis-checkpoint.mjs status
|
|
8
|
+
* node scripts/run-live-synthesis-checkpoint.mjs complete-todo --id=s.1
|
|
9
|
+
* node scripts/run-live-synthesis-checkpoint.mjs finish
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { dirname, join } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const root = join(__dirname, '..');
|
|
17
|
+
const xrayRoot = join(root, 'node_modules/0xray');
|
|
18
|
+
const stateDir = join(root, '.xray', 'state');
|
|
19
|
+
const checkpointPath = join(stateDir, 'synthesis-checkpoint.json');
|
|
20
|
+
const planPath = join(stateDir, 'lead-dev-plan.json');
|
|
21
|
+
|
|
22
|
+
const DEFAULT_SESSION = 'live-synthesis-repertoire';
|
|
23
|
+
|
|
24
|
+
const log = (msg) => process.stdout.write(`${msg}\n`);
|
|
25
|
+
const err = (msg) => process.stderr.write(`${msg}\n`);
|
|
26
|
+
|
|
27
|
+
function parseSessionId() {
|
|
28
|
+
const arg = process.argv.find((a) => a.startsWith('--session-id='));
|
|
29
|
+
return arg?.split('=')[1] || process.env.GROK_SESSION_ID || DEFAULT_SESSION;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function loadFeatures() {
|
|
33
|
+
return JSON.parse(readFileSync(join(root, '.xray/features.json'), 'utf8'));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function loadXray() {
|
|
37
|
+
const synthesis = await import(join(xrayRoot, 'dist/nucleus/synthesis.js'));
|
|
38
|
+
const persistence = await import(join(xrayRoot, 'dist/nucleus/lead-dev-plan-persistence.js'));
|
|
39
|
+
const kernel = await import(join(xrayRoot, 'dist/nucleus/autonomy-kernel.js'));
|
|
40
|
+
return { synthesis, persistence, kernel };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function cmdSeed() {
|
|
44
|
+
const sessionId = parseSessionId();
|
|
45
|
+
const grokSession = process.env.GROK_SESSION_ID;
|
|
46
|
+
if (grokSession && grokSession !== sessionId) {
|
|
47
|
+
err(
|
|
48
|
+
`❌ GROK_SESSION_ID (${grokSession}) ≠ seed sessionId (${sessionId}) — hooks will skip synthesis due`,
|
|
49
|
+
);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const features = loadFeatures();
|
|
53
|
+
const threshold = features.synthesis?.every_n_gates ?? 12;
|
|
54
|
+
if (!features.synthesis?.enabled) {
|
|
55
|
+
err('❌ synthesis.enabled is false in .xray/features.json');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
mkdirSync(stateDir, { recursive: true });
|
|
60
|
+
const { synthesis, kernel, persistence } = await loadXray();
|
|
61
|
+
|
|
62
|
+
// Reset prior checkpoint for clean live run
|
|
63
|
+
if (existsSync(checkpointPath)) {
|
|
64
|
+
const prior = synthesis.loadSynthesisCheckpointState(root);
|
|
65
|
+
if (prior?.synthesisDue) {
|
|
66
|
+
log('ℹ️ Clearing prior due checkpoint for fresh live run');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let becameDue = false;
|
|
71
|
+
for (let i = 0; i < threshold; i++) {
|
|
72
|
+
const result = synthesis.recordExecutionSlice('gate', { projectRoot: root, sessionId });
|
|
73
|
+
if (result.becameDue) becameDue = true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const state = synthesis.loadSynthesisCheckpointState(root);
|
|
77
|
+
const due = synthesis.isSynthesisCheckpointDue(root, sessionId);
|
|
78
|
+
|
|
79
|
+
log(`📊 sessionId: ${sessionId}`);
|
|
80
|
+
log(`📊 gate slices recorded: ${threshold}`);
|
|
81
|
+
log(`📊 synthesisDue: ${due}`);
|
|
82
|
+
log(`📊 dueReason: ${state?.dueReason ?? 'null'}`);
|
|
83
|
+
log(`📊 synthesisCount: ${state?.synthesisCount ?? 0}`);
|
|
84
|
+
|
|
85
|
+
if (!due) {
|
|
86
|
+
err('❌ Checkpoint not due after seeding');
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Write session boot marker for hooks
|
|
91
|
+
writeFileSync(
|
|
92
|
+
join(stateDir, 'session-boot.json'),
|
|
93
|
+
JSON.stringify(
|
|
94
|
+
{
|
|
95
|
+
hook: 'live-synthesis-seed',
|
|
96
|
+
lead_dev_mode: true,
|
|
97
|
+
sessionId,
|
|
98
|
+
workspaceRoot: root,
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
100
|
+
},
|
|
101
|
+
null,
|
|
102
|
+
2,
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
log('\n✅ Live synthesis checkpoint SEEDED');
|
|
107
|
+
log('Next: CallMcpTool xray-orchestrator analyze-complexity with sessionId');
|
|
108
|
+
log(` sessionId: "${sessionId}"`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function cmdStatus() {
|
|
112
|
+
const sessionId = parseSessionId();
|
|
113
|
+
const { synthesis, persistence } = await loadXray();
|
|
114
|
+
const state = synthesis.loadSynthesisCheckpointState(root);
|
|
115
|
+
const due = synthesis.isSynthesisCheckpointDue(root, sessionId);
|
|
116
|
+
const plan = persistence.loadPersistedLeadDevPlan(root);
|
|
117
|
+
const consultTodos = plan ? persistence.getSynthesisConsultTodos(plan) : [];
|
|
118
|
+
|
|
119
|
+
log(JSON.stringify(
|
|
120
|
+
{
|
|
121
|
+
sessionId,
|
|
122
|
+
synthesisDue: due,
|
|
123
|
+
dueReason: state?.dueReason ?? null,
|
|
124
|
+
synthesisCount: state?.synthesisCount ?? 0,
|
|
125
|
+
planActive: plan?.active ?? false,
|
|
126
|
+
phaseId: plan?.phases?.[0]?.id ?? null,
|
|
127
|
+
consultTodos: consultTodos.map((t) => ({ id: t.id, subagent: t.subagent, status: t.status })),
|
|
128
|
+
},
|
|
129
|
+
null,
|
|
130
|
+
2,
|
|
131
|
+
));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function cmdCompleteTodo() {
|
|
135
|
+
const todoId = process.argv.find((a) => a.startsWith('--id='))?.split('=')[1];
|
|
136
|
+
const verdict = process.argv.find((a) => a.startsWith('--verdict='))?.split('=')[1];
|
|
137
|
+
if (!todoId) {
|
|
138
|
+
err('Usage: complete-todo --id=s.1 --verdict=PASS|CONDITIONAL|FAIL');
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
141
|
+
if (!verdict || !['PASS', 'CONDITIONAL', 'FAIL'].includes(verdict)) {
|
|
142
|
+
err('❌ --verdict=PASS|CONDITIONAL|FAIL required (consult receipt gate)');
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const sessionId = parseSessionId();
|
|
147
|
+
const { persistence } = await loadXray();
|
|
148
|
+
const { writeSynthesisConsultReceipt } = await import(
|
|
149
|
+
join(xrayRoot, 'dist/nucleus/synthesis-consult-receipt.js'),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const plan = persistence.loadPersistedLeadDevPlan(root);
|
|
153
|
+
const consultTodo = plan
|
|
154
|
+
? persistence.getSynthesisConsultTodos(plan).find((t) => t.id === todoId)
|
|
155
|
+
: null;
|
|
156
|
+
if (!consultTodo) {
|
|
157
|
+
err(`❌ Consult todo ${todoId} not found in lead-dev plan`);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
writeSynthesisConsultReceipt(
|
|
162
|
+
todoId,
|
|
163
|
+
{
|
|
164
|
+
sessionId: plan?.sessionId ?? sessionId,
|
|
165
|
+
subagent: consultTodo.subagent,
|
|
166
|
+
verdict,
|
|
167
|
+
topRisks: [],
|
|
168
|
+
hardeningNote: process.argv.find((a) => a.startsWith('--note='))?.split('=')[1] ?? '',
|
|
169
|
+
},
|
|
170
|
+
root,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const updated = persistence.updatePlanTodoStatus(todoId, 'completed', root);
|
|
174
|
+
if (!updated) {
|
|
175
|
+
err(`❌ Receipt gate blocked completion for ${todoId}`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const refreshed = persistence.loadPersistedLeadDevPlan(root);
|
|
180
|
+
const todos = refreshed ? persistence.getSynthesisConsultTodos(refreshed) : [];
|
|
181
|
+
const allDone = todos.length > 0 && todos.every((t) => t.status === 'completed');
|
|
182
|
+
log(`✅ Marked ${todoId} completed (receipt: ${verdict})`);
|
|
183
|
+
log(`📊 consult todos: ${todos.map((t) => `${t.id}:${t.status}`).join(', ')}`);
|
|
184
|
+
if (allDone) log('🎉 All consult todos complete — checkpoint should clear on next gate eval');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function cmdFinish() {
|
|
188
|
+
const sessionId = parseSessionId();
|
|
189
|
+
const { synthesis } = await loadXray();
|
|
190
|
+
const due = synthesis.isSynthesisCheckpointDue(root, sessionId);
|
|
191
|
+
const state = synthesis.loadSynthesisCheckpointState(root);
|
|
192
|
+
if (due) {
|
|
193
|
+
err('❌ Checkpoint still due — complete all consult todos first');
|
|
194
|
+
await cmdStatus();
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
log('✅ Live synthesis checkpoint CLEARED');
|
|
198
|
+
log(`📊 synthesisCount: ${state?.synthesisCount ?? 0}`);
|
|
199
|
+
log(`📊 lastSynthesisAt: ${state?.lastSynthesisAt ?? 'null'}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const cmd = process.argv[2] || 'seed';
|
|
203
|
+
const handlers = {
|
|
204
|
+
seed: cmdSeed,
|
|
205
|
+
status: cmdStatus,
|
|
206
|
+
'complete-todo': cmdCompleteTodo,
|
|
207
|
+
finish: cmdFinish,
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const handler = handlers[cmd];
|
|
211
|
+
if (!handler) {
|
|
212
|
+
err(`Unknown command: ${cmd}`);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
await handler();
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Consumer-side helpers for suit verification — constants from 0xray bridge-mcp-wiring (SSOT).
|
|
4
|
+
*/
|
|
5
|
+
import { createRequire } from 'node:module';
|
|
6
|
+
import { execSync, spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
8
|
+
import { join, resolve } from 'node:path';
|
|
9
|
+
|
|
10
|
+
const packageRoot = resolve(import.meta.dirname, '..');
|
|
11
|
+
|
|
12
|
+
/** Consumer project root (hoisted 0xray lives here, not under @0xray/repertoire). */
|
|
13
|
+
export function resolveConsumerRoot() {
|
|
14
|
+
if (process.env.SUIT_VERIFY_ROOT) return resolve(process.env.SUIT_VERIFY_ROOT);
|
|
15
|
+
if (existsSync(join(process.cwd(), '.xray', 'features.json'))) return resolve(process.cwd());
|
|
16
|
+
return packageRoot;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function xrayPathCandidates(...segments) {
|
|
20
|
+
const consumerRoot = resolveConsumerRoot();
|
|
21
|
+
const roots =
|
|
22
|
+
consumerRoot === packageRoot ? [packageRoot] : [consumerRoot, packageRoot];
|
|
23
|
+
const candidates = roots.map((r) => join(r, 'node_modules/0xray', ...segments));
|
|
24
|
+
candidates.push(resolve(packageRoot, '../xray', ...segments));
|
|
25
|
+
return candidates;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function resolveXrayBridgeModule() {
|
|
29
|
+
const found = xrayPathCandidates('scripts/node/bridge-mcp-wiring.cjs').find((p) =>
|
|
30
|
+
existsSync(p),
|
|
31
|
+
);
|
|
32
|
+
if (!found) {
|
|
33
|
+
throw new Error('0xray bridge-mcp-wiring.cjs missing — run npm install');
|
|
34
|
+
}
|
|
35
|
+
return createRequire(import.meta.url)(found);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const wiring = resolveXrayBridgeModule();
|
|
39
|
+
|
|
40
|
+
export const {
|
|
41
|
+
XRAY_MCP_SERVERS,
|
|
42
|
+
HERMES_CONFIG_PATH,
|
|
43
|
+
HERMES_PLUGIN_DIR,
|
|
44
|
+
OPENCLAW_CONFIG_PATH,
|
|
45
|
+
OPENCLAW_STATE_DIR,
|
|
46
|
+
} = wiring;
|
|
47
|
+
|
|
48
|
+
/** Repertoire consumer MCP surface (local dist when developing this repo). */
|
|
49
|
+
export const REPERTOIRE_MCP = {
|
|
50
|
+
name: 'repertoire',
|
|
51
|
+
npxArgs: ['-y', '@0xray/repertoire', 'mcp'],
|
|
52
|
+
localArgs: ['node', 'dist/mcp/server.js'],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export function resolveXrayScript(filename) {
|
|
56
|
+
return xrayPathCandidates('scripts/node', filename).find((p) => existsSync(p)) ?? null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function readInstalledXrayVersion() {
|
|
60
|
+
const pkgPath = xrayPathCandidates('package.json').find((p) => existsSync(p));
|
|
61
|
+
if (!pkgPath) return 'unknown';
|
|
62
|
+
try {
|
|
63
|
+
const pkg = createRequire(import.meta.url)(pkgPath);
|
|
64
|
+
return pkg.version ?? 'unknown';
|
|
65
|
+
} catch {
|
|
66
|
+
return 'unknown';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Re-run native install when xray-consumer-root.txt points at wrong cwd (e.g. npx cache). */
|
|
71
|
+
export function ensureConsumerRootMarker(markerPath, installCmd) {
|
|
72
|
+
const consumerRoot = resolveConsumerRoot();
|
|
73
|
+
let marked = '';
|
|
74
|
+
if (existsSync(markerPath)) {
|
|
75
|
+
marked = readFileSync(markerPath, 'utf8').trim();
|
|
76
|
+
if (marked === consumerRoot) return consumerRoot;
|
|
77
|
+
}
|
|
78
|
+
process.stdout.write(
|
|
79
|
+
`⚠ consumer root ${marked ? `drift (${marked})` : 'missing'} — running ${installCmd}\n`,
|
|
80
|
+
);
|
|
81
|
+
execSync(installCmd, { cwd: consumerRoot, stdio: 'inherit' });
|
|
82
|
+
return consumerRoot;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function mcpStdioInitializeProbe({ cwd, command, args, env = {}, timeoutMs = 6000 }) {
|
|
86
|
+
return new Promise((resolveProbe, rejectProbe) => {
|
|
87
|
+
const init = JSON.stringify({
|
|
88
|
+
jsonrpc: '2.0',
|
|
89
|
+
id: 1,
|
|
90
|
+
method: 'initialize',
|
|
91
|
+
params: {
|
|
92
|
+
protocolVersion: '2024-11-05',
|
|
93
|
+
capabilities: {},
|
|
94
|
+
clientInfo: { name: 'suit-bridge-probe', version: '1.0' },
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const proc = spawn(command, args, {
|
|
99
|
+
cwd,
|
|
100
|
+
env: { ...process.env, ...env },
|
|
101
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
102
|
+
});
|
|
103
|
+
let out = '';
|
|
104
|
+
const timer = setTimeout(() => {
|
|
105
|
+
proc.kill();
|
|
106
|
+
rejectProbe(new Error(`timeout after ${timeoutMs}ms`));
|
|
107
|
+
}, timeoutMs);
|
|
108
|
+
|
|
109
|
+
const finish = (ok) => {
|
|
110
|
+
if (finished) return;
|
|
111
|
+
finished = true;
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
try {
|
|
114
|
+
proc.kill('SIGTERM');
|
|
115
|
+
} catch {
|
|
116
|
+
/* already exited */
|
|
117
|
+
}
|
|
118
|
+
if (ok) resolveProbe(out);
|
|
119
|
+
else rejectProbe(new Error(out.slice(0, 200) || 'no serverInfo in MCP response'));
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
let finished = false;
|
|
123
|
+
|
|
124
|
+
const onData = (chunk) => {
|
|
125
|
+
out += chunk.toString();
|
|
126
|
+
if (out.includes('serverInfo')) finish(true);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
proc.stdout.on('data', onData);
|
|
130
|
+
proc.stderr.on('data', onData);
|
|
131
|
+
|
|
132
|
+
proc.on('close', () => {
|
|
133
|
+
if (!finished) finish(out.includes('serverInfo'));
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
proc.stdin.write(`${init}\n`);
|
|
137
|
+
proc.stdin.end();
|
|
138
|
+
});
|
|
139
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Verify 0xRay suit is fully wearable in Grok Build for this repo.
|
|
4
|
+
* Run: npm run build && node scripts/verify-grok-suit.mjs
|
|
5
|
+
*/
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join, resolve } from 'node:path';
|
|
10
|
+
import { mcpStdioInitializeProbe, resolveConsumerRoot } from './suit-bridge-shared.mjs';
|
|
11
|
+
|
|
12
|
+
function resolveMemoryProviderPath(projectRoot) {
|
|
13
|
+
const local = join(projectRoot, 'dist/provider/memory-routing-provider.js');
|
|
14
|
+
if (existsSync(local)) return local;
|
|
15
|
+
const installed = join(
|
|
16
|
+
projectRoot,
|
|
17
|
+
'node_modules/@0xray/repertoire/dist/provider/memory-routing-provider.js',
|
|
18
|
+
);
|
|
19
|
+
if (existsSync(installed)) return installed;
|
|
20
|
+
return local;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const root = resolveConsumerRoot();
|
|
24
|
+
let failed = 0;
|
|
25
|
+
|
|
26
|
+
function pass(name, detail = '') {
|
|
27
|
+
console.log(`✅ ${name}${detail ? ` — ${detail}` : ''}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function fail(name, detail = '') {
|
|
31
|
+
failed++;
|
|
32
|
+
console.error(`❌ ${name}${detail ? ` — ${detail}` : ''}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function resolveLiveHook(name) {
|
|
36
|
+
const candidates = [
|
|
37
|
+
join(root, 'node_modules/0xray/dist/integrations/grok/hooks', name),
|
|
38
|
+
join(homedir(), 'dev/xray/dist/integrations/grok/hooks', name),
|
|
39
|
+
];
|
|
40
|
+
return candidates.find((p) => existsSync(p)) || null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function tailActivityLog(workspace, tailBytes = 32768) {
|
|
44
|
+
const logFile = join(workspace, 'logs', 'framework', 'activity.log');
|
|
45
|
+
if (!existsSync(logFile)) return '';
|
|
46
|
+
const stat = statSync(logFile);
|
|
47
|
+
const start = Math.max(0, stat.size - tailBytes);
|
|
48
|
+
const buf = readFileSync(logFile).subarray(start);
|
|
49
|
+
return buf.toString('utf8');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function runHook(hookPath, fixture, env = {}) {
|
|
53
|
+
const payload = JSON.stringify(fixture);
|
|
54
|
+
return execSync(`printf '%s' '${payload.replace(/'/g, "'\\''")}' | node "${hookPath}"`, {
|
|
55
|
+
encoding: 'utf8',
|
|
56
|
+
env: { ...process.env, GROK_WORKSPACE_ROOT: root, ...env },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 1. .xray layout
|
|
61
|
+
for (const f of ['codex.json', 'features.json', 'config.json']) {
|
|
62
|
+
const p = join(root, '.xray', f);
|
|
63
|
+
existsSync(p) ? pass(`.xray/${f}`) : fail(`.xray/${f}`, 'missing');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 2. features.json contract
|
|
67
|
+
try {
|
|
68
|
+
const features = JSON.parse(readFileSync(join(root, '.xray/features.json'), 'utf8'));
|
|
69
|
+
let installedXrayVersion = 'unknown';
|
|
70
|
+
try {
|
|
71
|
+
const xrayPkg = JSON.parse(
|
|
72
|
+
readFileSync(join(root, 'node_modules/0xray/package.json'), 'utf8'),
|
|
73
|
+
);
|
|
74
|
+
installedXrayVersion = xrayPkg.version ?? 'unknown';
|
|
75
|
+
} catch {
|
|
76
|
+
/* optional */
|
|
77
|
+
}
|
|
78
|
+
if (features.version === installedXrayVersion) {
|
|
79
|
+
pass('features.json version', installedXrayVersion);
|
|
80
|
+
} else {
|
|
81
|
+
fail('features.json version', `got ${features.version}, expected ${installedXrayVersion}`);
|
|
82
|
+
}
|
|
83
|
+
if (features.inference_governance?.enabled) pass('inference_governance');
|
|
84
|
+
else fail('inference_governance', 'not enabled');
|
|
85
|
+
if (features.memory_routing?.enabled) pass('memory_routing');
|
|
86
|
+
else fail('memory_routing', 'not enabled');
|
|
87
|
+
if (features.synthesis?.enabled) pass('synthesis.enabled');
|
|
88
|
+
else fail('synthesis.enabled', 'not enabled');
|
|
89
|
+
} catch (e) {
|
|
90
|
+
fail('features.json parse', e.message);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 3. Memory provider built (local dist or installed @0xray/repertoire)
|
|
94
|
+
const provider = resolveMemoryProviderPath(root);
|
|
95
|
+
existsSync(provider)
|
|
96
|
+
? pass('memory-routing-provider.js')
|
|
97
|
+
: fail('memory-routing-provider.js', 'npm install @0xray/repertoire or npm run build');
|
|
98
|
+
|
|
99
|
+
// 4. .mcp.json — 7 xray + repertoire
|
|
100
|
+
try {
|
|
101
|
+
const mcp = JSON.parse(readFileSync(join(root, '.mcp.json'), 'utf8'));
|
|
102
|
+
const servers = Object.keys(mcp.mcpServers || {});
|
|
103
|
+
const xrayCount = servers.filter((s) => s.startsWith('xray-')).length;
|
|
104
|
+
if (xrayCount === 7) pass('.mcp.json xray servers', '7/7');
|
|
105
|
+
else fail('.mcp.json xray servers', `${xrayCount}/7`);
|
|
106
|
+
servers.includes('repertoire') ? pass('.mcp.json repertoire') : fail('.mcp.json repertoire', 'missing');
|
|
107
|
+
const mcpRaw = readFileSync(join(root, '.mcp.json'), 'utf8');
|
|
108
|
+
if (/\/Users\/[^"'\s]+/.test(mcpRaw)) {
|
|
109
|
+
fail('.mcp.json portable paths', 'absolute /Users/ path in committed .mcp.json');
|
|
110
|
+
} else {
|
|
111
|
+
pass('.mcp.json portable paths');
|
|
112
|
+
}
|
|
113
|
+
} catch (e) {
|
|
114
|
+
fail('.mcp.json', e.message);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 5. Grok plugin + UserPromptSubmit boot hook
|
|
118
|
+
const grokPlugin = join(homedir(), '.grok/plugins/0xray');
|
|
119
|
+
const grokHooks = join(grokPlugin, 'hooks/hooks.json');
|
|
120
|
+
existsSync(grokPlugin) ? pass('Grok plugin', grokPlugin) : fail('Grok plugin', 'run: npx 0xray grok install --force');
|
|
121
|
+
if (existsSync(grokHooks)) {
|
|
122
|
+
const hooksRaw = readFileSync(grokHooks, 'utf8');
|
|
123
|
+
hooksRaw.includes('session-start.js')
|
|
124
|
+
? pass('SessionStart hook')
|
|
125
|
+
: fail('SessionStart hook', 're-run: npx 0xray grok install --force');
|
|
126
|
+
hooksRaw.includes('pre-tool-use.js')
|
|
127
|
+
? pass('PreToolUse hook (live Grok path)')
|
|
128
|
+
: fail('PreToolUse hook', 'missing from hooks.json');
|
|
129
|
+
hooksRaw.includes('UserPromptSubmit')
|
|
130
|
+
? pass('UserPromptSubmit boot hook')
|
|
131
|
+
: fail('UserPromptSubmit boot hook', 'add session-start.js — npx 0xray grok install --force');
|
|
132
|
+
} else {
|
|
133
|
+
fail('Grok hooks.json', 'missing');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const features = JSON.parse(readFileSync(join(root, '.xray/features.json'), 'utf8'));
|
|
138
|
+
if (features.multi_agent_orchestration?.lead_dev_mode) pass('lead_dev_mode in features.json');
|
|
139
|
+
else fail('lead_dev_mode', 'not enabled');
|
|
140
|
+
if (features.multi_agent_orchestration?.no_new_surface !== false) pass('no_new_surface in features.json');
|
|
141
|
+
else fail('no_new_surface', 'disabled');
|
|
142
|
+
} catch (e) {
|
|
143
|
+
fail('lead_dev_mode', e.message);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
const codex = JSON.parse(readFileSync(join(root, '.xray/codex.json'), 'utf8'));
|
|
148
|
+
if (codex.terms?.['69']) pass('codex term 69 (no new surface)');
|
|
149
|
+
else fail('codex term 69', 'missing');
|
|
150
|
+
} catch (e) {
|
|
151
|
+
fail('codex term 69', e.message);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 6. 0xray package xray field (server-config-registry — no fallback)
|
|
155
|
+
try {
|
|
156
|
+
const xrayPkg = JSON.parse(
|
|
157
|
+
readFileSync(join(root, 'node_modules/0xray/package.json'), 'utf8'),
|
|
158
|
+
);
|
|
159
|
+
if (xrayPkg.xray?.mcpServersPath || xrayPkg.xray?.dist) pass('0xray package.json xray field');
|
|
160
|
+
else fail('0xray package.json xray field', 'missing — npm link ~/dev/xray && rebuild');
|
|
161
|
+
} catch (e) {
|
|
162
|
+
fail('0xray package.json xray field', e.message);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 7. CLI health
|
|
166
|
+
try {
|
|
167
|
+
execSync('npx 0xray health', { cwd: root, stdio: 'pipe', encoding: 'utf8' });
|
|
168
|
+
pass('npx 0xray health');
|
|
169
|
+
} catch {
|
|
170
|
+
fail('npx 0xray health');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const preToolHook = resolveLiveHook('pre-tool-use.js');
|
|
174
|
+
const sessionHook = resolveLiveHook('session-start.js');
|
|
175
|
+
if (!preToolHook) fail('Live PreToolUse hook path', 'not found in node_modules/0xray');
|
|
176
|
+
else pass('Live PreToolUse hook path', preToolHook);
|
|
177
|
+
|
|
178
|
+
if (!sessionHook) fail('Live SessionStart hook path', 'not found');
|
|
179
|
+
else pass('Live SessionStart hook path', sessionHook);
|
|
180
|
+
|
|
181
|
+
// 8. SessionStart → session-boot.json + activity.log
|
|
182
|
+
const bootPath = join(root, '.xray', 'state', 'session-boot.json');
|
|
183
|
+
const activityBefore = tailActivityLog(root);
|
|
184
|
+
if (sessionHook) {
|
|
185
|
+
try {
|
|
186
|
+
runHook(
|
|
187
|
+
sessionHook,
|
|
188
|
+
{
|
|
189
|
+
hookEventName: 'session_start',
|
|
190
|
+
sessionId: 'verify-suit-probe',
|
|
191
|
+
workspaceRoot: root,
|
|
192
|
+
cwd: root,
|
|
193
|
+
},
|
|
194
|
+
{ GROK_HOOK_EVENT: 'session_start', GROK_SESSION_ID: 'verify-suit-probe' },
|
|
195
|
+
);
|
|
196
|
+
if (existsSync(bootPath)) {
|
|
197
|
+
const boot = JSON.parse(readFileSync(bootPath, 'utf8'));
|
|
198
|
+
if (boot.lead_dev_mode === true) pass('session-boot.json written', 'lead_dev_mode=true');
|
|
199
|
+
else fail('session-boot.json', 'lead_dev_mode not true');
|
|
200
|
+
} else {
|
|
201
|
+
fail('session-boot.json', 'missing after SessionStart hook');
|
|
202
|
+
}
|
|
203
|
+
const activityAfter = tailActivityLog(root);
|
|
204
|
+
if (/grok-session-start.*session-boot-written/.test(activityAfter)) {
|
|
205
|
+
pass('SessionStart logged to activity.log');
|
|
206
|
+
} else {
|
|
207
|
+
fail('SessionStart activity.log', 'no grok-session-start entry');
|
|
208
|
+
}
|
|
209
|
+
} catch (e) {
|
|
210
|
+
fail('SessionStart hook probe', e.message?.slice(0, 160));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 9. PreToolUse deny + activity.log (same path Grok uses live)
|
|
215
|
+
if (preToolHook) {
|
|
216
|
+
try {
|
|
217
|
+
const out = runHook(preToolHook, {
|
|
218
|
+
toolName: 'search_replace',
|
|
219
|
+
workspaceRoot: root,
|
|
220
|
+
toolInput: { path: 'src/mcps/new-thing.server.ts', new_string: 'export {}' },
|
|
221
|
+
});
|
|
222
|
+
if (/"decision"\s*:\s*"deny"/.test(out)) pass('PreToolUse deny (live hook path)');
|
|
223
|
+
else fail('PreToolUse deny', `got: ${out.slice(0, 120)}`);
|
|
224
|
+
|
|
225
|
+
const activity = tailActivityLog(root);
|
|
226
|
+
if (/grok-pre-tool-use.*deny/.test(activity)) {
|
|
227
|
+
pass('PreToolUse deny logged to activity.log');
|
|
228
|
+
} else {
|
|
229
|
+
fail('PreToolUse activity.log', 'no grok-pre-tool-use deny entry');
|
|
230
|
+
}
|
|
231
|
+
} catch (e) {
|
|
232
|
+
fail('PreToolUse hook probe', e.message?.slice(0, 160));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 10. MCP enforcer stdio + no server-config-registry fallback (Node probe — no GNU timeout)
|
|
237
|
+
const activityBeforeEnforcer = tailActivityLog(root);
|
|
238
|
+
try {
|
|
239
|
+
await mcpStdioInitializeProbe({
|
|
240
|
+
cwd: root,
|
|
241
|
+
command: 'npx',
|
|
242
|
+
args: ['0xray', 'mcp', 'enforcer'],
|
|
243
|
+
timeoutMs: 6000,
|
|
244
|
+
});
|
|
245
|
+
pass('MCP enforcer stdio');
|
|
246
|
+
|
|
247
|
+
const activityNew = tailActivityLog(root).slice(activityBeforeEnforcer.length);
|
|
248
|
+
if (/using-fallback-path/.test(activityNew)) {
|
|
249
|
+
fail('server-config-registry', 'using-fallback-path in activity.log after enforcer boot');
|
|
250
|
+
} else {
|
|
251
|
+
pass('server-config-registry resolved (no fallback warning)');
|
|
252
|
+
}
|
|
253
|
+
} catch (e) {
|
|
254
|
+
fail('MCP enforcer stdio', e.message?.slice(0, 120));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// 11. Orchestrator behavior assertions (0xray@3.4.10+)
|
|
258
|
+
const behaviorScript = join(root, 'node_modules/0xray/scripts/mjs/verify-orchestrator-behavior.mjs');
|
|
259
|
+
if (!existsSync(behaviorScript)) {
|
|
260
|
+
fail('Orchestrator behavior assertions', 'missing script — npm install 0xray@^3.4.10');
|
|
261
|
+
} else {
|
|
262
|
+
try {
|
|
263
|
+
execSync(`node "${behaviorScript}"`, { cwd: root, stdio: 'pipe', encoding: 'utf8' });
|
|
264
|
+
pass('Orchestrator behavior assertions');
|
|
265
|
+
} catch (e) {
|
|
266
|
+
const detail = (e.stderr || e.stdout || e.message || '').toString().slice(0, 160);
|
|
267
|
+
fail('Orchestrator behavior assertions', detail);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// 12. Grok delegation + synthesis gate fixtures (0xray@3.5.0+)
|
|
272
|
+
for (const [label, scriptName] of [
|
|
273
|
+
['Grok delegation gate fixture', 'verify-grok-delegation-gate.mjs'],
|
|
274
|
+
['Grok synthesis gate fixture', 'verify-grok-synthesis-gate.mjs'],
|
|
275
|
+
]) {
|
|
276
|
+
const gateScript = join(root, 'node_modules/0xray/scripts/mjs', scriptName);
|
|
277
|
+
if (!existsSync(gateScript)) {
|
|
278
|
+
fail(label, 'missing script — npm install 0xray@main (3.5.0+)');
|
|
279
|
+
} else {
|
|
280
|
+
try {
|
|
281
|
+
execSync(`node "${gateScript}"`, { cwd: root, stdio: 'pipe', encoding: 'utf8' });
|
|
282
|
+
pass(label);
|
|
283
|
+
} catch (e) {
|
|
284
|
+
const detail = (e.stderr || e.stdout || e.message || '').toString().slice(0, 160);
|
|
285
|
+
fail(label, detail);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 13. Installed Grok plugin PostToolUse hook (3.5.0 auto-chain)
|
|
291
|
+
const installedGrokHooks = join(grokPlugin, 'hooks/hooks.json');
|
|
292
|
+
if (existsSync(installedGrokHooks)) {
|
|
293
|
+
const installedRaw = readFileSync(installedGrokHooks, 'utf8');
|
|
294
|
+
if (installedRaw.includes('PostToolUse') && installedRaw.includes('post-tool-use.js')) {
|
|
295
|
+
pass('Grok plugin PostToolUse hook installed');
|
|
296
|
+
} else {
|
|
297
|
+
fail('Grok plugin PostToolUse hook', 'run: npx 0xray grok install --force');
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
fail('Grok plugin PostToolUse hook', 'hooks.json missing — npx 0xray grok install --force');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
console.log('\n' + (failed === 0 ? '🎉 Suit wearable — operate within 0xRay.' : `⚠️ ${failed} check(s) failed — fix before tuning.`));
|
|
304
|
+
process.exit(failed === 0 ? 0 : 1);
|