0xray 4.0.40 → 4.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.grok-plugin/plugin.json +1 -1
- package/.opencode/agents/api-design.yml +31 -0
- package/.opencode/agents/architect.yml +15 -0
- package/.opencode/agents/architecture-patterns.yml +14 -0
- package/.opencode/agents/auto-format.yml +14 -0
- package/.opencode/agents/backend-engineer.yml +12 -0
- package/.opencode/agents/boot-orchestrator.yml +14 -0
- package/.opencode/agents/bug-triage-specialist.yml +15 -0
- package/.opencode/agents/code-analyzer.yml +12 -0
- package/.opencode/agents/code-reviewer.yml +14 -0
- package/.opencode/agents/content-creator.yml +12 -0
- package/.opencode/agents/database-engineer.yml +12 -0
- package/.opencode/agents/devops-engineer.yml +12 -0
- package/.opencode/agents/framework-compliance-audit.yml +14 -0
- package/.opencode/agents/frontend-engineer.yml +12 -0
- package/.opencode/agents/frontend-ui-ux-engineer.yml +12 -0
- package/.opencode/agents/git-workflow.yml +15 -0
- package/.opencode/agents/growth-strategist.yml +12 -0
- package/.opencode/agents/hermes-agent.yml +12 -0
- package/.opencode/agents/inference-improve.yml +12 -0
- package/.opencode/agents/lint.yml +14 -0
- package/.opencode/agents/log-monitor.yml +12 -0
- package/.opencode/agents/mobile-developer.yml +12 -0
- package/.opencode/agents/model-health-check.yml +12 -0
- package/.opencode/agents/multimodal-looker.yml +12 -0
- package/.opencode/agents/performance-analysis.yml +12 -0
- package/.opencode/agents/performance-engineer.yml +12 -0
- package/.opencode/agents/performance-optimization.yml +12 -0
- package/.opencode/agents/processor-pipeline.yml +14 -0
- package/.opencode/agents/project-analysis.yml +12 -0
- package/.opencode/agents/refactorer.yml +12 -0
- package/.opencode/agents/researcher.yml +12 -0
- package/.opencode/agents/security-auditor.yml +12 -0
- package/.opencode/agents/security-scan.yml +12 -0
- package/.opencode/agents/seo-consultant.yml +12 -0
- package/.opencode/agents/session-management.yml +12 -0
- package/.opencode/agents/state-manager.yml +12 -0
- package/.opencode/agents/storyteller.yml +12 -0
- package/.opencode/agents/strategist.yml +12 -0
- package/.opencode/agents/tech-writer.yml +12 -0
- package/.opencode/agents/testing-best-practices.yml +12 -0
- package/.opencode/agents/testing-lead.yml +12 -0
- package/.opencode/agents/ui-ux-design.yml +12 -0
- package/.opencode/codex.codex +8 -0
- package/.opencode/commands/auto-format.md +99 -0
- package/.opencode/commands/auto-summary-capture.md +90 -0
- package/.opencode/commands/dependency-audit.md +184 -0
- package/.opencode/commands/enforcer-daily-scan.md +137 -0
- package/.opencode/commands/framework-compliance-audit.md +205 -0
- package/.opencode/commands/interactive-validator.md +75 -0
- package/.opencode/commands/job-summary-logger.md +68 -0
- package/.opencode/commands/lint.md +11 -0
- package/.opencode/commands/mode-switch.md +95 -0
- package/.opencode/commands/model-health-check.md +186 -0
- package/.opencode/commands/performance-analysis.md +144 -0
- package/.opencode/commands/pre-commit-introspection.md +185 -0
- package/.opencode/commands/pre-commit-introspection.sh +133 -0
- package/.opencode/commands/security-scan.md +157 -0
- package/.opencode/commands/sisyphus-validation.md +128 -0
- package/.opencode/commands/summary-logger.md +83 -0
- package/.opencode/enforcer-config.json +282 -0
- package/.opencode/skills/orchestrator/SKILL.md +12 -0
- package/.opencode/workflows/post-deployment-audit.yml +123 -0
- package/.xray/features.json +1 -1
- package/.xray/features.schema.json +1 -1
- package/AGENTS-consumer.md +2 -0
- package/AGENTS.md +2 -0
- package/README.md +52 -12
- package/SKILLS.md +2 -0
- package/dist/AGENTS.md +2 -0
- package/dist/CHANGELOG.md +29 -0
- package/dist/README.md +52 -12
- package/dist/SKILLS.md +2 -0
- package/dist/cli/commands/openclaw-install.js +1 -1
- package/dist/cli/index.js +12 -0
- package/dist/enforcement/index.d.ts +4 -0
- package/dist/enforcement/index.js +4 -0
- package/dist/enforcement/validators/code-quality-validators.js +6 -4
- package/dist/governance/llm-governance-provider.d.ts +7 -1
- package/dist/governance/llm-governance-provider.js +72 -14
- package/dist/governance/local-confer.d.ts +4 -1
- package/dist/governance/local-confer.js +22 -1
- package/dist/integrations/grok/grok-cli.js +10 -37
- package/dist/integrations/grok/hooks/grok-hook-utils.js +29 -2
- package/dist/integrations/grok/hooks/session-start.js +2 -20
- package/dist/integrations/hooks/confer-hook-runtime.mjs +23 -1
- package/dist/integrations/hooks/goggles-mcp.mjs +36 -4
- package/dist/integrations/hooks/goggles-pipeline.mjs +55 -15
- package/dist/integrations/hooks/goggles-planes.json +13 -4
- package/dist/integrations/hooks/plates.cjs +22 -0
- package/dist/integrations/hooks/session-note-index.cjs +298 -0
- package/dist/integrations/hooks/session-note-index.mjs +22 -0
- package/dist/integrations/hooks/sleeve.cjs +335 -0
- package/dist/integrations/hooks/sleeve.mjs +18 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +205 -9
- package/dist/integrations/hooks/wake-cascade.cjs +102 -0
- package/dist/integrations/hooks/wake-cascade.mjs +16 -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 -2
- package/dist/mcps/config/server-config-registry.js +8 -6
- package/dist/mcps/governance.server.d.ts +1 -0
- package/dist/mcps/governance.server.js +46 -0
- package/dist/mcps/knowledge-skills/code-review.server.js +7 -0
- package/dist/mcps/knowledge-skills/security-audit.server.js +5 -3
- package/dist/mcps/mcp-client.js +1 -1
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
- package/dist/mcps/researcher.server.js +12 -3
- package/dist/memory-routing/plates.d.ts +1 -1
- package/dist/memory-routing/plates.js +1 -0
- package/dist/nucleus/autonomy-kernel.d.ts +2 -0
- package/dist/nucleus/autonomy-kernel.js +17 -13
- package/dist/nucleus/confer-host.d.ts +35 -0
- package/dist/nucleus/confer-host.js +55 -0
- package/dist/nucleus/confer.d.ts +19 -3
- package/dist/nucleus/confer.js +111 -55
- package/dist/nucleus/lead-dev-plan-persistence.js +4 -2
- package/dist/nucleus/suit-temperament.d.ts +1 -1
- package/dist/nucleus/suit-temperament.js +2 -2
- package/dist/nucleus/synthesis-consult-receipt.d.ts +7 -1
- package/dist/nucleus/synthesis-consult-receipt.js +86 -35
- package/dist/reporting/framework-reporting-system.js +2 -5
- package/dist/reporting/log-parser.d.ts +2 -0
- package/dist/reporting/log-parser.js +7 -6
- package/dist/skills/orchestrator/SKILL.md +12 -0
- package/docs-site/docs/plates/activity-log.md +1 -1
- package/docs-site/docs/plates/boot.md +2 -0
- package/docs-site/docs/plates/centrifuge.md +30 -0
- package/docs-site/docs/plates/cursor-compact.md +1 -1
- package/docs-site/docs/plates/glossary.md +1 -2
- package/docs-site/docs/plates/goggles.md +4 -0
- package/docs-site/docs/plates/governance.md +2 -0
- package/docs-site/docs/plates/grok-compact.md +1 -1
- package/docs-site/docs/plates/grokbot.md +1 -1
- package/docs-site/docs/plates/host-pack.md +2 -0
- package/docs-site/docs/plates/house.md +1 -1
- package/docs-site/docs/plates/index.md +3 -1
- package/docs-site/docs/plates/inference-files.md +1 -1
- package/docs-site/docs/plates/kept-line.md +1 -1
- package/docs-site/docs/plates/kits.md +2 -0
- package/docs-site/docs/plates/lens-gate.md +1 -1
- package/docs-site/docs/plates/lens-page.md +1 -1
- package/docs-site/docs/plates/live-mesh.md +1 -1
- package/docs-site/docs/plates/memory-recall.md +4 -0
- package/docs-site/docs/plates/notes-page.md +2 -1
- package/docs-site/docs/plates/orchestration.md +2 -0
- package/docs-site/docs/plates/package-face.md +1 -1
- package/docs-site/docs/plates/payload-heat.md +1 -1
- package/docs-site/docs/plates/pickup-stamp.md +1 -1
- package/docs-site/docs/plates/pre-tool.md +1 -1
- package/docs-site/docs/plates/processor.md +2 -0
- package/docs-site/docs/plates/record-map.md +2 -1
- package/docs-site/docs/plates/reflection-page.md +1 -1
- package/docs-site/docs/plates/reporting.md +2 -0
- package/docs-site/docs/plates/review.md +1 -1
- package/docs-site/docs/plates/routing.md +2 -0
- package/docs-site/docs/plates/session-capture.md +1 -1
- package/docs-site/docs/plates/site-manual.md +1 -1
- package/docs-site/docs/plates/stamp-plate.md +1 -1
- package/docs-site/docs/plates/station-card.md +4 -1
- package/docs-site/docs/plates/station-heat.md +1 -1
- package/docs-site/docs/plates/suit-organs.md +1 -1
- package/docs-site/docs/plates/suit-settings.md +1 -1
- package/docs-site/docs/plates/suit-wear.md +3 -1
- package/docs-site/docs/plates/suit.md +2 -0
- package/docs-site/docs/plates/trail-state.md +1 -1
- package/docs-site/docs/plates/work-fresh.md +1 -1
- package/docs-site/docs/plates/write-home.md +1 -1
- package/llms.txt +2 -0
- package/package.json +2 -2
- package/scripts/mjs/verify-confer-core.mjs +153 -29
- package/scripts/mjs/verify-user-aside-core.mjs +3 -4
- package/scripts/node/bridge-mcp-wiring.cjs +273 -9
- package/scripts/node/confer-switch.cjs +66 -0
- package/scripts/node/install-bridges.cjs +188 -60
- package/scripts/node/setup.cjs +2 -46
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/architect-tools.server.ts +26 -2
- package/src/mcps/config/__tests__/server-config-registry.test.ts +15 -6
- package/src/mcps/config/server-config-registry.ts +9 -6
- package/src/mcps/governance.server.ts +49 -0
- package/src/mcps/knowledge-skills/code-review.server.ts +8 -0
- package/src/mcps/knowledge-skills/security-audit.server.ts +11 -12
- package/src/mcps/mcp-client.ts +1 -1
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
- package/src/mcps/researcher.server.ts +19 -10
- package/src/skills/orchestrator/SKILL.md +12 -0
- package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +5 -51
- package/xray/features.json +1 -1
- package/xray/features.schema.json +1 -1
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
import { frameworkLogger } from '../../core/framework-logger.js';
|
|
18
18
|
import fs from 'fs';
|
|
19
19
|
import path from 'path';
|
|
20
|
-
import { execSync } from 'child_process';
|
|
21
20
|
import { createRequire } from 'module';
|
|
22
21
|
import { fileURLToPath } from 'node:url';
|
|
23
22
|
import { syncBuiltinSkills } from '../../cli/commands/skill-install.js';
|
|
@@ -27,27 +26,13 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
27
26
|
const packageRoot = path.resolve(__dirname, '..', '..', '..');
|
|
28
27
|
const requireCjs = createRequire(import.meta.url);
|
|
29
28
|
const { resolveConsumerTargetDir, patchGrokHooks } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
|
|
30
|
-
const {
|
|
31
|
-
function registerGrokMcpServers(targetDir) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
for (const s of XRAY_MCP_SERVERS) {
|
|
40
|
-
try {
|
|
41
|
-
const envEntries = { ...s.env, XRAY_ROOT: targetDir };
|
|
42
|
-
const envFlags = Object.entries(envEntries)
|
|
43
|
-
.map(([k, v]) => `--env "${k}=${v}"`)
|
|
44
|
-
.join(' ');
|
|
45
|
-
execSync(`grok mcp add ${s.name} --command npx --args "-y" "0xray" "mcp" "${s.mcpCmd}" ${envFlags}`, { stdio: 'pipe' });
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
// already registered or grok config conflict — non-blocking
|
|
49
|
-
}
|
|
50
|
-
}
|
|
29
|
+
const { resolveRepertoireMcp, resolveGogglesMcp } = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
|
|
30
|
+
function registerGrokMcpServers(targetDir, env) {
|
|
31
|
+
const wiring = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
|
|
32
|
+
const tomlPath = wiring.writeProjectSuitMcp(targetDir);
|
|
33
|
+
const trustPath = wiring.trustGrokFolder(targetDir, env);
|
|
34
|
+
process.stdout.write(`Project Grok MCP written to ${tomlPath}\n`);
|
|
35
|
+
process.stdout.write(`Grok folder trust written to ${trustPath}\n`);
|
|
51
36
|
}
|
|
52
37
|
export async function installForGrokCLI(options = {}) {
|
|
53
38
|
frameworkLogger.log('grok-integration', 'install-start', 'info', {
|
|
@@ -115,21 +100,9 @@ export async function installForGrokCLI(options = {}) {
|
|
|
115
100
|
writeProjectRepertoireMcp(targetDir);
|
|
116
101
|
writeProjectGogglesMcp(targetDir);
|
|
117
102
|
mintAfterWear(targetDir);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
console.log('\x1b[32m✓ Auto-trusted the 0xray plugin with Grok CLI\x1b[0m');
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
console.log('\nPlease run this command to fully trust the plugin:');
|
|
125
|
-
console.log(` grok plugins trust "${primary}"`);
|
|
126
|
-
}
|
|
127
|
-
if (isolated) {
|
|
128
|
-
registerGrokMcpServers(targetDir);
|
|
129
|
-
console.log('\x1b[32m✓ Registered 7 xray MCP servers with Grok CLI (npx)\x1b[0m');
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
console.log('\x1b[32m✓ Project-scoped Grok plugin worn (machine ~/.grok/plugins/0xray not written)\x1b[0m');
|
|
103
|
+
registerGrokMcpServers(targetDir, env);
|
|
104
|
+
if (!isolated) {
|
|
105
|
+
process.stdout.write('Project-scoped Grok plugin worn (machine ~/.grok/plugins/0xray not written)\n');
|
|
133
106
|
}
|
|
134
107
|
console.log('\n✅ 0xRay is now installed as a first-class Grok CLI plugin!');
|
|
135
108
|
console.log('Restart Grok or run `grok` to load the new hooks and MCP servers.');
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
updatePlanTodoStatusInPlace,
|
|
20
20
|
loadDelegationGateFeatures,
|
|
21
21
|
} from '../../hooks/delegation-gate-runtime.mjs';
|
|
22
|
-
import { isConferPendingForSession } from '../../hooks/confer-hook-runtime.mjs';
|
|
22
|
+
import { isConferPendingForSession, readConferReviewHint } from '../../hooks/confer-hook-runtime.mjs';
|
|
23
23
|
import { getActiveUserAsideBoot } from '../../hooks/user-aside-hook-runtime.mjs';
|
|
24
24
|
import {
|
|
25
25
|
applyStationHeat,
|
|
@@ -282,6 +282,25 @@ export function loadConferPending(root = workspaceRoot(), sessionId = null) {
|
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
export function resolveGrokHookEvent(event = {}, argv = process.argv, env = process.env) {
|
|
286
|
+
if (env && env.GROK_HOOK_EVENT) return env.GROK_HOOK_EVENT;
|
|
287
|
+
const flag = (argv || []).find((arg) => String(arg).startsWith('--hook-event='));
|
|
288
|
+
if (flag) return String(flag).slice('--hook-event='.length);
|
|
289
|
+
const named = String((event && (event.hookEventName || event.hook)) || '')
|
|
290
|
+
.toLowerCase()
|
|
291
|
+
.replace(/[-_\s]/g, '');
|
|
292
|
+
if (named === 'precompact') return 'pre_compact';
|
|
293
|
+
if (named === 'postcompact') return 'post_compact';
|
|
294
|
+
if (named === 'sessionstart') return 'session_start';
|
|
295
|
+
if (
|
|
296
|
+
(event && (event.prompt != null || event.userMessage != null || event.user_prompt != null)) ||
|
|
297
|
+
named === 'userpromptsubmit'
|
|
298
|
+
) {
|
|
299
|
+
return 'user_prompt_submit';
|
|
300
|
+
}
|
|
301
|
+
return 'session_start';
|
|
302
|
+
}
|
|
303
|
+
|
|
285
304
|
export function buildSessionBootPayload(root, source = '0xray/grok-session-start', extra = {}) {
|
|
286
305
|
const features = loadFeatures(root);
|
|
287
306
|
const blockingTerms = loadBlockingCodexTerms();
|
|
@@ -289,6 +308,7 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
289
308
|
const sessionId =
|
|
290
309
|
extra.sessionId || process.env.GROK_SESSION_ID || process.env.GROK_SESSION || null;
|
|
291
310
|
const conferPending = loadConferPending(root, sessionId);
|
|
311
|
+
const conferReview = readConferReviewHint(root);
|
|
292
312
|
const userAsideBoot = getActiveUserAsideBoot(root, sessionId);
|
|
293
313
|
const gateFeatures = loadDelegationGateFeatures(root, 'grok');
|
|
294
314
|
const frontier = gateFeatures.ceremony === 'lite';
|
|
@@ -313,11 +333,18 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
313
333
|
...heat,
|
|
314
334
|
...(siblingRoots.length > 0 ? { siblingWorkspaceRoots: siblingRoots } : {}),
|
|
315
335
|
...(conferPending ? { conferPending: true, conferTrigger: 'analyze-complexity at synthesis checkpoint' } : {}),
|
|
336
|
+
...(conferReview
|
|
337
|
+
? {
|
|
338
|
+
conferReview,
|
|
339
|
+
conferReviewHint: 'UNREVIEWED — abstain without a governance LLM blocks the consult todo',
|
|
340
|
+
}
|
|
341
|
+
: {}),
|
|
316
342
|
...(userAsideBoot ?? {}),
|
|
317
343
|
sessionId,
|
|
318
344
|
...extra,
|
|
319
345
|
...heat,
|
|
320
346
|
...compactHold,
|
|
347
|
+
arrivedHook: extra && extra.hookEvent ? String(extra.hookEvent) : "",
|
|
321
348
|
hook: source,
|
|
322
349
|
source,
|
|
323
350
|
timestamp: new Date().toISOString(),
|
|
@@ -328,8 +355,8 @@ export function writeSessionBoot(root, payload) {
|
|
|
328
355
|
try {
|
|
329
356
|
const stateDir = path.join(root, '.xray', 'state');
|
|
330
357
|
fs.mkdirSync(stateDir, { recursive: true });
|
|
331
|
-
fs.writeFileSync(sessionBootPath(root), JSON.stringify(payload, null, 2));
|
|
332
358
|
writeStationMarkdown(root, payload);
|
|
359
|
+
fs.writeFileSync(sessionBootPath(root), JSON.stringify(payload, null, 2));
|
|
333
360
|
const hook = String((payload && (payload.hookEvent || payload.source)) || "");
|
|
334
361
|
if (!/compact/i.test(hook)) {
|
|
335
362
|
try {
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
clearPendingDelegationsForSessionChange,
|
|
10
10
|
ensureSessionBoot,
|
|
11
11
|
readStdinJson,
|
|
12
|
+
resolveGrokHookEvent,
|
|
12
13
|
resolveSessionId,
|
|
13
14
|
normalizeWorkspaceRoot,
|
|
14
15
|
workspaceRoot,
|
|
@@ -25,25 +26,6 @@ import {
|
|
|
25
26
|
import { maintainLens } from '../../hooks/goggles-pipeline.mjs';
|
|
26
27
|
import { readSavedFreshness, refreshFreshness } from '../../../nucleus/work-freshness.mjs';
|
|
27
28
|
|
|
28
|
-
function resolveHookEvent(event) {
|
|
29
|
-
if (process.env.GROK_HOOK_EVENT) return process.env.GROK_HOOK_EVENT;
|
|
30
|
-
const flag = process.argv.find((a) => a.startsWith('--hook-event='));
|
|
31
|
-
if (flag) return flag.slice('--hook-event='.length);
|
|
32
|
-
const named = event.hookEventName || event.hook;
|
|
33
|
-
if (named === 'PreCompact' || named === 'pre_compact') return 'pre_compact';
|
|
34
|
-
if (named === 'PostCompact' || named === 'post_compact') return 'post_compact';
|
|
35
|
-
if (
|
|
36
|
-
event.prompt != null ||
|
|
37
|
-
event.userMessage != null ||
|
|
38
|
-
event.user_prompt != null ||
|
|
39
|
-
named === 'UserPromptSubmit' ||
|
|
40
|
-
named === 'user_prompt_submit'
|
|
41
|
-
) {
|
|
42
|
-
return 'user_prompt_submit';
|
|
43
|
-
}
|
|
44
|
-
return 'session_start';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
29
|
function extractIntent(event) {
|
|
48
30
|
return event.prompt || event.userMessage || event.user_prompt || event.compactContext || null;
|
|
49
31
|
}
|
|
@@ -117,7 +99,7 @@ async function main() {
|
|
|
117
99
|
let HOOK_EVENT = 'session_start';
|
|
118
100
|
try {
|
|
119
101
|
const event = await readStdinJson();
|
|
120
|
-
HOOK_EVENT =
|
|
102
|
+
HOOK_EVENT = resolveGrokHookEvent(event);
|
|
121
103
|
const eventRoot = normalizeWorkspaceRoot(event.workspaceRoot || event.cwd || root);
|
|
122
104
|
const sessionId = resolveSessionId(event);
|
|
123
105
|
if (HOOK_EVENT === 'user_prompt_submit' && sessionId) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lazy-load confer SSOT for Grok session-boot hints.
|
|
4
4
|
*/
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
|
-
import { existsSync } from 'node:fs';
|
|
6
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
7
7
|
import { dirname, join, resolve } from 'node:path';
|
|
8
8
|
import { fileURLToPath } from 'node:url';
|
|
9
9
|
|
|
@@ -46,4 +46,26 @@ export function isConferPendingForSession(projectRoot, sessionId = null) {
|
|
|
46
46
|
const mod = loadConfer();
|
|
47
47
|
if (!mod?.isConferPending) return false;
|
|
48
48
|
return mod.isConferPending(projectRoot, sessionId);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** 'UNREVIEWED' when a consult receipt recorded abstain-without-model. */
|
|
52
|
+
export function readConferReviewHint(projectRoot) {
|
|
53
|
+
const stateDir = join(projectRoot, '.xray', 'state');
|
|
54
|
+
if (!existsSync(stateDir)) return null;
|
|
55
|
+
let names;
|
|
56
|
+
try {
|
|
57
|
+
names = readdirSync(stateDir);
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
for (const name of names) {
|
|
62
|
+
if (!name.startsWith('synthesis-consult-') || !name.endsWith('.json')) continue;
|
|
63
|
+
try {
|
|
64
|
+
const receipt = JSON.parse(readFileSync(join(stateDir, name), 'utf8'));
|
|
65
|
+
if (receipt && receipt.verdict === 'UNREVIEWED') return 'UNREVIEWED';
|
|
66
|
+
} catch {
|
|
67
|
+
/* unreadable receipt is not a hint */
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
49
71
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
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, realpathSync } from 'node:fs';
|
|
6
|
-
import { basename, join, resolve } from 'node:path';
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
7
7
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
8
8
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
9
9
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
@@ -162,6 +162,29 @@ function publicCard(view) {
|
|
|
162
162
|
if (view.exam) notes.push(view.exam);
|
|
163
163
|
}
|
|
164
164
|
const skills = view.skills ? basename(String(view.skills)) : '';
|
|
165
|
+
const cascade = view.cascade
|
|
166
|
+
? {
|
|
167
|
+
plane: view.cascade.plane,
|
|
168
|
+
station: view.cascade.station,
|
|
169
|
+
notesPage: view.cascade.notesPage,
|
|
170
|
+
index: view.cascade.index,
|
|
171
|
+
laws: Array.isArray(view.cascade.laws) ? view.cascade.laws : [],
|
|
172
|
+
notes: Array.isArray(view.cascade.notes) ? view.cascade.notes : [],
|
|
173
|
+
}
|
|
174
|
+
: null;
|
|
175
|
+
const sleeve = view.sleeve
|
|
176
|
+
? {
|
|
177
|
+
on: Boolean(view.sleeve.on),
|
|
178
|
+
missing: Array.isArray(view.sleeve.missing) ? view.sleeve.missing : [],
|
|
179
|
+
stitches: Array.isArray(view.sleeve.stitches)
|
|
180
|
+
? view.sleeve.stitches.map((row) => ({
|
|
181
|
+
name: String(row && row.name || ''),
|
|
182
|
+
on: Boolean(row && row.on),
|
|
183
|
+
at: Array.isArray(row && row.at) ? row.at.map((item) => String(item)) : [],
|
|
184
|
+
}))
|
|
185
|
+
: [],
|
|
186
|
+
}
|
|
187
|
+
: null;
|
|
165
188
|
if (view.narrow) {
|
|
166
189
|
return {
|
|
167
190
|
plane: view.plane,
|
|
@@ -169,6 +192,8 @@ function publicCard(view) {
|
|
|
169
192
|
digest: view.digest || '',
|
|
170
193
|
files: Array.isArray(view.files) ? view.files : [],
|
|
171
194
|
notes,
|
|
195
|
+
...(cascade ? { cascade } : {}),
|
|
196
|
+
...(sleeve ? { sleeve } : {}),
|
|
172
197
|
};
|
|
173
198
|
}
|
|
174
199
|
return {
|
|
@@ -185,6 +210,8 @@ function publicCard(view) {
|
|
|
185
210
|
teardown: view.teardown || '',
|
|
186
211
|
worn: view.worn || '',
|
|
187
212
|
notes,
|
|
213
|
+
...(cascade ? { cascade } : {}),
|
|
214
|
+
...(sleeve ? { sleeve } : {}),
|
|
188
215
|
};
|
|
189
216
|
}
|
|
190
217
|
|
|
@@ -205,11 +232,16 @@ export async function answerLook(raw, root) {
|
|
|
205
232
|
return { ok: true, quiet: false, mode: 'kind0', content: line };
|
|
206
233
|
}
|
|
207
234
|
const argv = argvFrom(args);
|
|
208
|
-
const text = api.look(argv).text;
|
|
235
|
+
const text = api.look(argv, here).text;
|
|
209
236
|
if (text === 'Name one plane.') return deny('name_one', 'Name one plane.');
|
|
210
|
-
const cards = api.lookCards(argv);
|
|
237
|
+
const cards = api.lookCards(argv, here);
|
|
211
238
|
if (Array.isArray(cards) && cards.length) {
|
|
212
239
|
const shown = cards.map(publicCard);
|
|
240
|
+
if (shown.length === 1 && shown[0] && typeof shown[0].plane === 'string') {
|
|
241
|
+
const dest = join(here, '.xray', 'state', 'goggles-plane.json');
|
|
242
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
243
|
+
writeFileSync(dest, `${JSON.stringify({ plane: shown[0].plane })}\n`);
|
|
244
|
+
}
|
|
213
245
|
return {
|
|
214
246
|
ok: true,
|
|
215
247
|
quiet: false,
|
|
@@ -18,7 +18,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
18
18
|
const FIELD_ORDER = ['plate', 'entry', 'exit', 'files', 'skills', 'setup', 'teardown', 'worn'];
|
|
19
19
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
const WORN_PLANES = ['dichotomy', 'syncopate', 'synthesis', 'digest', 'triage', 'loop'];
|
|
21
|
-
const CARD_PLANES = ['ground', 'routing', 'house', 'boot', 'governance', 'memory-recall', 'orchestration', 'processor', 'reporting', 'stamp-plate', 'record-map', 'write-home', 'activity-log', 'session-capture', 'suit-wear', 'suit-organs', 'station-card', 'notes-page', 'reflection-page', 'site-manual', 'package-face', 'suit-settings', 'trail-state', 'inference-files', 'grok-compact', 'payload-heat', 'station-heat', 'pickup-stamp', 'cursor-compact', 'work-fresh', 'kept-line', 'lens-gate', 'pre-tool', 'lens-page'];
|
|
21
|
+
const CARD_PLANES = ['ground', 'routing', 'house', 'boot', 'governance', 'memory-recall', 'orchestration', 'processor', 'reporting', 'stamp-plate', 'record-map', 'write-home', 'activity-log', 'session-capture', 'suit-wear', 'suit-organs', 'station-card', 'notes-page', 'reflection-page', 'site-manual', 'package-face', 'suit-settings', 'trail-state', 'inference-files', 'grok-compact', 'payload-heat', 'station-heat', 'pickup-stamp', 'cursor-compact', 'work-fresh', 'kept-line', 'lens-gate', 'pre-tool', 'lens-page', 'centrifuge'];
|
|
22
22
|
const CARD_FLAVORS = ['digest', 'triage'];
|
|
23
23
|
const SCOPE_ZOOM = ['ecosystem', 'part', 'one flow', 'one artifact'];
|
|
24
24
|
|
|
@@ -211,7 +211,7 @@ function namesTheSet(lower) {
|
|
|
211
211
|
return planes.length === 1 && planes[0] === 'loop' && findScopes(lower).length === 0;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
function gogglesAnswer(argv) {
|
|
214
|
+
function gogglesAnswer(argv, projectRoot) {
|
|
215
215
|
const words = [];
|
|
216
216
|
for (const raw of argv || []) {
|
|
217
217
|
const arg = String(raw || '').trim();
|
|
@@ -234,14 +234,14 @@ function gogglesAnswer(argv) {
|
|
|
234
234
|
if (flavors.length === 1) {
|
|
235
235
|
const others = acceptedPlanes().filter((name) => name !== flavors[0] && lower.includes(name));
|
|
236
236
|
if (others.length) return none('');
|
|
237
|
-
const cards = collectCards(flavors[0], lower);
|
|
237
|
+
const cards = collectCards(flavors[0], lower, projectRoot);
|
|
238
238
|
if (!cards) return none('');
|
|
239
239
|
return { text: cards.map((card) => formatCardText(card)).join('\n\n'), cards };
|
|
240
240
|
}
|
|
241
241
|
const planes = acceptedPlanes().filter((name) => lower.includes(name));
|
|
242
242
|
if (planes.length !== 1) {
|
|
243
243
|
if (!planes.length && cardPlanesNamed(lower).length) {
|
|
244
|
-
const cards = collectCards('digest', lower);
|
|
244
|
+
const cards = collectCards('digest', lower, projectRoot);
|
|
245
245
|
if (cards && cards.length) {
|
|
246
246
|
return { text: cards.map((card) => formatCardText(card)).join('\n\n'), cards };
|
|
247
247
|
}
|
|
@@ -255,12 +255,12 @@ function gogglesAnswer(argv) {
|
|
|
255
255
|
return none(file ? `${line} File: ${file}` : line);
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
export function readGoggles(argv) {
|
|
259
|
-
return ok(gogglesAnswer(argv).text);
|
|
258
|
+
export function readGoggles(argv, projectRoot) {
|
|
259
|
+
return ok(gogglesAnswer(argv, projectRoot).text);
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
export function lookCards(argv) {
|
|
263
|
-
return gogglesAnswer(argv).cards;
|
|
262
|
+
export function lookCards(argv, projectRoot) {
|
|
263
|
+
return gogglesAnswer(argv, projectRoot).cards;
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
function cardPlanesNamed(lower) {
|
|
@@ -271,7 +271,22 @@ function listedFiles(plane) {
|
|
|
271
271
|
return Array.isArray(plane.files) ? plane.files.map(String) : [];
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
function
|
|
274
|
+
function cascadeApi() {
|
|
275
|
+
return createRequire(import.meta.url)('./wake-cascade.cjs');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function sleeveApi() {
|
|
279
|
+
return createRequire(import.meta.url)('./sleeve.cjs');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function appendLining(text, view) {
|
|
283
|
+
let next = text;
|
|
284
|
+
if (view.cascade) next = `${next}\n${cascadeApi().formatCascadeReading(view.cascade)}`;
|
|
285
|
+
if (view.sleeve) next = `${next}\n${sleeveApi().formatSleeveReading(view.sleeve)}`;
|
|
286
|
+
return next;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function cardView(plane, scope, flavor, root, cascadeRoot) {
|
|
275
290
|
const listed = listedFiles(plane);
|
|
276
291
|
const view = {
|
|
277
292
|
plane: plane.id,
|
|
@@ -290,6 +305,20 @@ function cardView(plane, scope, flavor, root) {
|
|
|
290
305
|
worn: plane.worn || '',
|
|
291
306
|
};
|
|
292
307
|
view.exam = examinePlane(plane, root).text;
|
|
308
|
+
if (cascadeApi().isCascadePlane(plane.id)) {
|
|
309
|
+
try {
|
|
310
|
+
view.cascade = cascadeApi().readWakeCascade(cascadeRoot || stateRoot());
|
|
311
|
+
} catch {
|
|
312
|
+
view.cascade = null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (sleeveApi().isSleevePlane(plane.id)) {
|
|
316
|
+
try {
|
|
317
|
+
view.sleeve = sleeveApi().readSleeve(cascadeRoot || stateRoot());
|
|
318
|
+
} catch {
|
|
319
|
+
view.sleeve = null;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
293
322
|
if (flavor === 'triage') {
|
|
294
323
|
const filled = new Set(filledOf(plane));
|
|
295
324
|
view.empty = FIELD_ORDER.filter((name) => !filled.has(name));
|
|
@@ -328,7 +357,7 @@ function formatCardText(view) {
|
|
|
328
357
|
} else if (typeof view.exam === 'string' && view.exam.startsWith('Drift:')) {
|
|
329
358
|
text = `${text}\n${view.exam}`;
|
|
330
359
|
}
|
|
331
|
-
return text;
|
|
360
|
+
return appendLining(text, view);
|
|
332
361
|
}
|
|
333
362
|
|
|
334
363
|
export function formatCardPane(view) {
|
|
@@ -345,10 +374,11 @@ export function formatCardPane(view) {
|
|
|
345
374
|
const top = `┌ ${title} ${'─'.repeat(Math.max(0, width - title.length - 1))}┐`;
|
|
346
375
|
const mid = body.map((line) => `│ ${line.padEnd(width)} │`);
|
|
347
376
|
const bot = `└${'─'.repeat(width + 2)}┘`;
|
|
348
|
-
|
|
377
|
+
const pane = [top, ...mid, bot].join('\n');
|
|
378
|
+
return appendLining(pane, view);
|
|
349
379
|
}
|
|
350
380
|
|
|
351
|
-
function collectCards(flavor, lower) {
|
|
381
|
+
function collectCards(flavor, lower, projectRoot) {
|
|
352
382
|
const named = cardPlanesNamed(lower);
|
|
353
383
|
const scopes = findScopes(lower.filter((word) => word !== flavor && !named.includes(word)));
|
|
354
384
|
if (scopes.length > 1) return null;
|
|
@@ -359,7 +389,7 @@ function collectCards(flavor, lower) {
|
|
|
359
389
|
const cards = [];
|
|
360
390
|
for (const id of ids) {
|
|
361
391
|
const plane = growPlane(id, platesDir, stateRoot());
|
|
362
|
-
cards.push(cardView(plane, scope, flavor, root));
|
|
392
|
+
cards.push(cardView(plane, scope, flavor, root, projectRoot));
|
|
363
393
|
}
|
|
364
394
|
return cards;
|
|
365
395
|
}
|
|
@@ -929,6 +959,15 @@ function lensPage(root, names) {
|
|
|
929
959
|
return parts.join('\n\n');
|
|
930
960
|
}
|
|
931
961
|
|
|
962
|
+
|
|
963
|
+
export function holdPlane(root, id) {
|
|
964
|
+
const plane = String(id || "").trim();
|
|
965
|
+
if (!plane || plane.includes(" ")) return;
|
|
966
|
+
const dest = join(root, ".xray", "state", "goggles-plane.json");
|
|
967
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
968
|
+
writeFileSync(dest, `${JSON.stringify({ plane })}\n`);
|
|
969
|
+
}
|
|
970
|
+
|
|
932
971
|
function stampPlane(root, id) {
|
|
933
972
|
try {
|
|
934
973
|
const plates = createRequire(import.meta.url)('./plates.cjs');
|
|
@@ -953,6 +992,7 @@ export function lensBeforeResearch(root, toolName, text) {
|
|
|
953
992
|
if (!research) return null;
|
|
954
993
|
const names = CARD_PLANES.filter((name) => intentWords(spoken).includes(name));
|
|
955
994
|
if (names.length === 1) {
|
|
995
|
+
holdPlane(root, names[0]);
|
|
956
996
|
stampPlane(root, names[0]);
|
|
957
997
|
rememberOpened(root, spoken);
|
|
958
998
|
return null;
|
|
@@ -1095,8 +1135,8 @@ export function examinePlane(plane, root) {
|
|
|
1095
1135
|
}
|
|
1096
1136
|
|
|
1097
1137
|
|
|
1098
|
-
export function look(argv) {
|
|
1099
|
-
return readGoggles(argv);
|
|
1138
|
+
export function look(argv, projectRoot) {
|
|
1139
|
+
return readGoggles(argv, projectRoot);
|
|
1100
1140
|
}
|
|
1101
1141
|
|
|
1102
1142
|
|
|
@@ -38,7 +38,10 @@
|
|
|
38
38
|
"plates": ["suit-wear"]
|
|
39
39
|
},
|
|
40
40
|
"governance": {
|
|
41
|
-
"files": [
|
|
41
|
+
"files": [
|
|
42
|
+
"src/governance/governance-service.ts",
|
|
43
|
+
"src/governance/llm-governance-provider.ts"
|
|
44
|
+
],
|
|
42
45
|
"skills": ".agents/skills/governance/SKILL.md"
|
|
43
46
|
},
|
|
44
47
|
"memory-recall": {
|
|
@@ -68,7 +71,7 @@
|
|
|
68
71
|
"plates": ["review"]
|
|
69
72
|
},
|
|
70
73
|
"record-map": {
|
|
71
|
-
"files": ["docs-site/docs/plates/record-map.md"],
|
|
74
|
+
"files": ["docs-site/docs/plates/record-map.md", "src/integrations/hooks/wake-cascade.cjs", "src/integrations/hooks/session-note-index.cjs"],
|
|
72
75
|
"skills": ".agents/skills/record-map/SKILL.md",
|
|
73
76
|
"plates": ["station-card", "notes-page", "reflection-page", "site-manual", "package-face", "write-home", "activity-log", "session-capture", "lens-page"]
|
|
74
77
|
},
|
|
@@ -103,13 +106,13 @@
|
|
|
103
106
|
"plates": ["activity-log", "session-capture", "inference-files", "trail-state"]
|
|
104
107
|
},
|
|
105
108
|
"station-card": {
|
|
106
|
-
"files": ["src/integrations/hooks/station-hook-runtime.cjs"],
|
|
109
|
+
"files": ["src/integrations/hooks/station-hook-runtime.cjs", "src/integrations/hooks/wake-cascade.cjs"],
|
|
107
110
|
"mark": "formatStationMarkdown",
|
|
108
111
|
"skills": ".agents/skills/station-card/SKILL.md",
|
|
109
112
|
"plates": ["notes-page", "record-map", "kept-line"]
|
|
110
113
|
},
|
|
111
114
|
"notes-page": {
|
|
112
|
-
"files": ["src/integrations/hooks/station-hook-runtime.cjs"],
|
|
115
|
+
"files": ["src/integrations/hooks/station-hook-runtime.cjs", "src/integrations/hooks/session-note-index.cjs"],
|
|
113
116
|
"mark": "stampNotesPickup",
|
|
114
117
|
"skills": ".agents/skills/notes-page/SKILL.md",
|
|
115
118
|
"plates": ["station-card", "record-map"]
|
|
@@ -210,6 +213,12 @@
|
|
|
210
213
|
"mark": "export function formatCardPane",
|
|
211
214
|
"skills": ".agents/skills/lens-page/SKILL.md",
|
|
212
215
|
"plates": ["record-map", "lens-gate"]
|
|
216
|
+
},
|
|
217
|
+
"centrifuge": {
|
|
218
|
+
"files": ["src/integrations/hooks/station-hook-runtime.cjs"],
|
|
219
|
+
"mark": "function wakeOrder",
|
|
220
|
+
"skills": ".agents/skills/centrifuge/SKILL.md",
|
|
221
|
+
"plates": ["station-card", "goggles"]
|
|
213
222
|
}
|
|
214
223
|
}
|
|
215
224
|
|
|
@@ -46,6 +46,7 @@ const PLATE_IDS = Object.freeze([
|
|
|
46
46
|
"lens-gate",
|
|
47
47
|
"pre-tool",
|
|
48
48
|
"lens-page",
|
|
49
|
+
"centrifuge",
|
|
49
50
|
]);
|
|
50
51
|
|
|
51
52
|
/** Id token, then extra phrases. Equal top scores recall nothing. */
|
|
@@ -229,6 +230,11 @@ const CUES = {
|
|
|
229
230
|
[/lens page/i, 6],
|
|
230
231
|
[/plates\/lens-page/i, 6],
|
|
231
232
|
],
|
|
233
|
+
centrifuge: [
|
|
234
|
+
[/centrifuge plate/i, 6],
|
|
235
|
+
[/the centrifuge/i, 5],
|
|
236
|
+
[/plates\/centrifuge/i, 6],
|
|
237
|
+
],
|
|
232
238
|
};
|
|
233
239
|
|
|
234
240
|
function platesDir() {
|
|
@@ -317,6 +323,21 @@ function stampPlateIfMissing(projectRoot, id) {
|
|
|
317
323
|
return { id, path, written: true };
|
|
318
324
|
}
|
|
319
325
|
|
|
326
|
+
function ensureWornPlate(projectRoot, id) {
|
|
327
|
+
const path = wornPlatePath(projectRoot, id);
|
|
328
|
+
const source = readFileSync(plateSourcePath(id), "utf8");
|
|
329
|
+
if (existsSync(path)) {
|
|
330
|
+
try {
|
|
331
|
+
if (readFileSync(path, "utf8") === source) return { id, path, written: false };
|
|
332
|
+
} catch {
|
|
333
|
+
/* rewrite a plate the process cannot keep */
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
337
|
+
writeFileSync(path, source);
|
|
338
|
+
return { id, path, written: true };
|
|
339
|
+
}
|
|
340
|
+
|
|
320
341
|
function organFile(intent) {
|
|
321
342
|
try {
|
|
322
343
|
const { suitHint } = require("./goggles-pipeline.mjs");
|
|
@@ -342,6 +363,7 @@ module.exports = {
|
|
|
342
363
|
loadPlate,
|
|
343
364
|
recallPlate,
|
|
344
365
|
stampPlateIfMissing,
|
|
366
|
+
ensureWornPlate,
|
|
345
367
|
plateStockLine,
|
|
346
368
|
wornPlatePath,
|
|
347
369
|
};
|