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
|
@@ -32,4 +32,4 @@ export declare function maybeHeatHostStation(projectRoot: string, host: SuitHost
|
|
|
32
32
|
export declare function writeSuitSessionBoot(projectRoot: string, host: SuitHost, extra?: Record<string, unknown>): string;
|
|
33
33
|
export declare function ceremonyForProfile(profile: SuitProfile): CeremonyLevel;
|
|
34
34
|
export declare function spawnPlanModeForProfile(profile: SuitProfile): SpawnPlanMode;
|
|
35
|
-
export declare function conferDefaultForProfile(
|
|
35
|
+
export declare function conferDefaultForProfile(_profile: SuitProfile): boolean;
|
|
@@ -170,6 +170,6 @@ export function spawnPlanModeForProfile(profile) {
|
|
|
170
170
|
return 'warn';
|
|
171
171
|
return 'deny';
|
|
172
172
|
}
|
|
173
|
-
export function conferDefaultForProfile(
|
|
174
|
-
return
|
|
173
|
+
export function conferDefaultForProfile(_profile) {
|
|
174
|
+
return false;
|
|
175
175
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Synthesis consult receipt SSOT — outcome-based completion for s.N todos.
|
|
3
3
|
* Receipts live at `.xray/state/synthesis-consult-{todoId}.json`.
|
|
4
4
|
*/
|
|
5
|
-
export type SynthesisConsultVerdict = 'PASS' | 'CONDITIONAL' | 'FAIL';
|
|
5
|
+
export type SynthesisConsultVerdict = 'PASS' | 'CONDITIONAL' | 'FAIL' | 'UNREVIEWED';
|
|
6
6
|
export interface SynthesisConsultReceipt {
|
|
7
7
|
sessionId: string;
|
|
8
8
|
subagent: string;
|
|
@@ -11,18 +11,24 @@ export interface SynthesisConsultReceipt {
|
|
|
11
11
|
hardeningNote: string;
|
|
12
12
|
todoId?: string;
|
|
13
13
|
recordedAt?: string;
|
|
14
|
+
/** Synthesis plan generation this receipt belongs to. A previous cycle's PASS cannot clear the next s.N. */
|
|
15
|
+
cycleId?: string;
|
|
14
16
|
}
|
|
15
17
|
export declare function isSynthesisConsultTodoId(todoId: string): boolean;
|
|
16
18
|
export declare function synthesisConsultReceiptPath(todoId: string, projectRoot?: string): string;
|
|
17
19
|
export declare function loadSynthesisConsultReceipt(todoId: string, projectRoot?: string): SynthesisConsultReceipt | null;
|
|
18
20
|
export declare function writeSynthesisConsultReceipt(todoId: string, receipt: SynthesisConsultReceipt, projectRoot?: string): string;
|
|
21
|
+
/** Only a real approve (PASS) completes a consult todo. */
|
|
22
|
+
export declare function consultVerdictBlocksCompletion(verdict: SynthesisConsultVerdict | null | undefined): boolean;
|
|
19
23
|
export declare function validateSynthesisConsultReceipt(receipt: SynthesisConsultReceipt, todoId: string, expected?: {
|
|
20
24
|
sessionId?: string | null;
|
|
21
25
|
subagent?: string;
|
|
26
|
+
cycleId?: string;
|
|
22
27
|
}): boolean;
|
|
23
28
|
export declare function hasValidSynthesisConsultReceipt(todoId: string, projectRoot?: string, expected?: {
|
|
24
29
|
sessionId?: string | null;
|
|
25
30
|
subagent?: string;
|
|
31
|
+
cycleId?: string;
|
|
26
32
|
}): boolean;
|
|
27
33
|
export declare function parseConsultVerdictFromText(text: string): SynthesisConsultVerdict | null;
|
|
28
34
|
export declare function extractTopRisksFromText(text: string, max?: number): string[];
|
|
@@ -25,14 +25,30 @@ export function loadSynthesisConsultReceipt(todoId, projectRoot = process.cwd())
|
|
|
25
25
|
export function writeSynthesisConsultReceipt(todoId, receipt, projectRoot = process.cwd()) {
|
|
26
26
|
const receiptPath = synthesisConsultReceiptPath(todoId, projectRoot);
|
|
27
27
|
fs.mkdirSync(path.dirname(receiptPath), { recursive: true });
|
|
28
|
+
const cycleId = receipt.cycleId ?? readPlanConsultCycleId(projectRoot);
|
|
28
29
|
const payload = {
|
|
29
30
|
...receipt,
|
|
30
31
|
todoId,
|
|
31
32
|
recordedAt: receipt.recordedAt ?? new Date().toISOString(),
|
|
33
|
+
...(cycleId ? { cycleId } : {}),
|
|
32
34
|
};
|
|
33
35
|
fs.writeFileSync(receiptPath, JSON.stringify(payload, null, 2));
|
|
34
36
|
return receiptPath;
|
|
35
37
|
}
|
|
38
|
+
function readPlanConsultCycleId(projectRoot) {
|
|
39
|
+
const planPath = path.join(projectRoot, '.xray', 'state', 'lead-dev-plan.json');
|
|
40
|
+
if (!fs.existsSync(planPath))
|
|
41
|
+
return undefined;
|
|
42
|
+
try {
|
|
43
|
+
const data = JSON.parse(fs.readFileSync(planPath, 'utf8'));
|
|
44
|
+
return typeof data.consultCycleId === 'string' && data.consultCycleId.trim()
|
|
45
|
+
? data.consultCycleId
|
|
46
|
+
: undefined;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
36
52
|
function normalizeSubagent(agent) {
|
|
37
53
|
const key = agent.toLowerCase().trim();
|
|
38
54
|
const aliases = {
|
|
@@ -47,7 +63,11 @@ function subagentsAlign(expected, actual) {
|
|
|
47
63
|
return e === a || e.includes(a) || a.includes(e);
|
|
48
64
|
}
|
|
49
65
|
function isValidVerdict(value) {
|
|
50
|
-
return value === 'PASS' || value === 'CONDITIONAL' || value === 'FAIL';
|
|
66
|
+
return value === 'PASS' || value === 'CONDITIONAL' || value === 'FAIL' || value === 'UNREVIEWED';
|
|
67
|
+
}
|
|
68
|
+
/** Only a real approve (PASS) completes a consult todo. */
|
|
69
|
+
export function consultVerdictBlocksCompletion(verdict) {
|
|
70
|
+
return verdict !== 'PASS';
|
|
51
71
|
}
|
|
52
72
|
export function validateSynthesisConsultReceipt(receipt, todoId, expected) {
|
|
53
73
|
if (!receipt.sessionId || !receipt.subagent || !isValidVerdict(receipt.verdict)) {
|
|
@@ -62,6 +82,8 @@ export function validateSynthesisConsultReceipt(receipt, todoId, expected) {
|
|
|
62
82
|
if (expected?.subagent && !subagentsAlign(expected.subagent, receipt.subagent)) {
|
|
63
83
|
return false;
|
|
64
84
|
}
|
|
85
|
+
if (expected?.cycleId && receipt.cycleId !== expected.cycleId)
|
|
86
|
+
return false;
|
|
65
87
|
if (receipt.todoId && receipt.todoId !== todoId)
|
|
66
88
|
return false;
|
|
67
89
|
return true;
|
|
@@ -72,52 +94,81 @@ export function hasValidSynthesisConsultReceipt(todoId, projectRoot = process.cw
|
|
|
72
94
|
return false;
|
|
73
95
|
return validateSynthesisConsultReceipt(receipt, todoId, expected);
|
|
74
96
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
const EXPLICIT_VERDICT_LINE = /^Verdict:\s*(PASS|CONDITIONAL|FAIL|UNREVIEWED)\s*$/i;
|
|
98
|
+
const VERDICT_OPTION_ECHO = /\bPASS\s*\|\s*CONDITIONAL\s*\|\s*FAIL\b/i;
|
|
99
|
+
const DECISION_LINE = /^DECISION:\s*(approve|reject|abstain|approved|rejected|pass|fail|needs_revision|conditional|revise)\s*$/i;
|
|
100
|
+
function lineWithoutBullet(rawLine) {
|
|
101
|
+
return rawLine.trim().replace(/^[-*•]\s*/, '');
|
|
102
|
+
}
|
|
103
|
+
function splitAtReasoning(text) {
|
|
104
|
+
const lines = text.split('\n');
|
|
105
|
+
const idx = lines.findIndex((rawLine) => /^REASONING:/i.test(lineWithoutBullet(rawLine)));
|
|
106
|
+
if (idx < 0)
|
|
107
|
+
return { header: text, reasoning: null };
|
|
108
|
+
return {
|
|
109
|
+
header: lines.slice(0, idx).join('\n'),
|
|
110
|
+
reasoning: lines.slice(idx).join('\n'),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/** Abstain because no governance model ran. A bare DECISION: abstain stays CONDITIONAL. */
|
|
114
|
+
function isAbstainWithoutModel(text) {
|
|
115
|
+
return /nested LLM not configured|did not produce a vote|returned no vote/i.test(text);
|
|
116
|
+
}
|
|
117
|
+
/** First exact DECISION line before REASONING. A menu or a line inside the reasoning body is not a vote. */
|
|
118
|
+
function firstHeaderDecision(text) {
|
|
119
|
+
const { header } = splitAtReasoning(text);
|
|
120
|
+
for (const rawLine of header.split('\n')) {
|
|
121
|
+
const match = lineWithoutBullet(rawLine).match(DECISION_LINE);
|
|
122
|
+
const decision = match?.[1]?.toLowerCase();
|
|
123
|
+
if (!decision)
|
|
124
|
+
continue;
|
|
125
|
+
if (decision === 'approve' || decision === 'approved' || decision === 'pass')
|
|
126
|
+
return 'PASS';
|
|
127
|
+
if (decision === 'reject' || decision === 'rejected' || decision === 'fail')
|
|
128
|
+
return 'FAIL';
|
|
129
|
+
if (decision === 'abstain' && isAbstainWithoutModel(text))
|
|
130
|
+
return 'UNREVIEWED';
|
|
85
131
|
return 'CONDITIONAL';
|
|
86
132
|
}
|
|
87
133
|
return null;
|
|
88
134
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const token = match?.[1];
|
|
96
|
-
if (!token || trimmed.includes('|'))
|
|
135
|
+
function hasAmbiguousVerdictLine(text) {
|
|
136
|
+
for (const rawLine of text.split('\n')) {
|
|
137
|
+
const line = lineWithoutBullet(rawLine);
|
|
138
|
+
if (!/^Verdict:/i.test(line))
|
|
139
|
+
continue;
|
|
140
|
+
if (EXPLICIT_VERDICT_LINE.test(line))
|
|
97
141
|
continue;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
function lastExplicitVerdictLine(text) {
|
|
147
|
+
let found = null;
|
|
148
|
+
for (const rawLine of text.split('\n')) {
|
|
149
|
+
const match = lineWithoutBullet(rawLine).match(EXPLICIT_VERDICT_LINE);
|
|
150
|
+
if (match?.[1])
|
|
151
|
+
found = match[1].toUpperCase();
|
|
101
152
|
}
|
|
102
153
|
return found;
|
|
103
154
|
}
|
|
104
155
|
export function parseConsultVerdictFromText(text) {
|
|
105
|
-
const
|
|
156
|
+
const decision = firstHeaderDecision(text);
|
|
157
|
+
if (decision)
|
|
158
|
+
return decision;
|
|
159
|
+
// Verdict lines inside REASONING are model text, not the vote.
|
|
160
|
+
const { header, reasoning } = splitAtReasoning(text);
|
|
161
|
+
const scanTarget = reasoning === null ? text : header;
|
|
162
|
+
const explicit = lastExplicitVerdictLine(scanTarget);
|
|
106
163
|
if (explicit)
|
|
107
164
|
return explicit;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
165
|
+
if (!text.trim())
|
|
166
|
+
return null;
|
|
167
|
+
if (hasAmbiguousVerdictLine(text) || VERDICT_OPTION_ECHO.test(text))
|
|
168
|
+
return 'UNREVIEWED';
|
|
169
|
+
if (/\b(?:PASS|FAIL|CONDITIONAL|UNREVIEWED|SHIP|APPROVE|REJECT)\b/i.test(text)) {
|
|
170
|
+
return 'UNREVIEWED';
|
|
113
171
|
}
|
|
114
|
-
const normalized = text.toUpperCase();
|
|
115
|
-
if (/\bCONDITIONAL(\s+PASS)?\b/.test(normalized))
|
|
116
|
-
return 'CONDITIONAL';
|
|
117
|
-
if (/\b(?:PASS|SHIP|APPROVE)\b/.test(normalized))
|
|
118
|
-
return 'PASS';
|
|
119
|
-
if (/\b(?:FAIL|REJECT)\b/.test(normalized))
|
|
120
|
-
return 'FAIL';
|
|
121
172
|
return null;
|
|
122
173
|
}
|
|
123
174
|
export function extractTopRisksFromText(text, max = 5) {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
|
-
import {
|
|
5
|
-
import { getComprehensiveLogs, filterLogsByConfig, frameworkLogToParsedEntry, } from "./log-parser.js";
|
|
4
|
+
import { getComprehensiveLogs, filterLogsByConfig, frameworkLogToParsedEntry, activityLogPath, } from "./log-parser.js";
|
|
6
5
|
import { calculateTimeRange, calculateMetrics, calculatePeakActivity, calculateHealthScore, generateInsights, generateRecommendations, generateAlerts, } from "./metrics.js";
|
|
7
6
|
import { formatReport } from "./report-formatter.js";
|
|
8
7
|
export class FrameworkReportingSystem {
|
|
@@ -106,9 +105,7 @@ const report = await reportingSystem.generateCustomReport('${template.name}');
|
|
|
106
105
|
}
|
|
107
106
|
// Same activity.log path readCurrentLogFile rebuilds from size and mtime.
|
|
108
107
|
activityLogFile() {
|
|
109
|
-
|
|
110
|
-
const projectRoot = path.resolve(path.dirname(currentFilePath), "../../");
|
|
111
|
-
return path.join(projectRoot, "logs", "framework", "activity.log");
|
|
108
|
+
return activityLogPath();
|
|
112
109
|
}
|
|
113
110
|
currentLogStamp() {
|
|
114
111
|
try {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type ParsedLogEntry, type ReportConfig } from "./types.js";
|
|
2
|
+
/** Consumer activity lives in the working directory, not inside the installed package. */
|
|
3
|
+
export declare function activityLogPath(root?: string): string;
|
|
2
4
|
export declare function levelToStatus(level: string): string;
|
|
3
5
|
export declare function inferAgent(component: string): string;
|
|
4
6
|
export declare function parseLogLine(line: string): ParsedLogEntry | null;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { createGunzip } from "zlib";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
4
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
6
|
-
const LOG_LINE_RE = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[([^\]]+)\]\s+\[([^\]]+)\]\s+(.+?)\s+-\s+(\w+)
|
|
7
|
-
const LOG_LINE_FALLBACK_RE = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[([^\]]+)\]\s+(.+?)\s+-\s+(\w+)
|
|
5
|
+
const LOG_LINE_RE = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[([^\]]+)\]\s+\[([^\]]+)\]\s+(.+?)\s+-\s+(\w+)(?:\s+\|.*)?$/;
|
|
6
|
+
const LOG_LINE_FALLBACK_RE = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z)\s+\[([^\]]+)\]\s+(.+?)\s+-\s+(\w+)(?:\s+\|.*)?$/;
|
|
7
|
+
/** Consumer activity lives in the working directory, not inside the installed package. */
|
|
8
|
+
export function activityLogPath(root = process.cwd()) {
|
|
9
|
+
return path.join(root, "logs", "framework", "activity.log");
|
|
10
|
+
}
|
|
8
11
|
// Parsed rows stay cached while size and mtime stay the same.
|
|
9
12
|
let currentLogCache = null;
|
|
10
13
|
const rotatedLogCache = new Map();
|
|
@@ -160,9 +163,7 @@ function uniqueSorted(logs) {
|
|
|
160
163
|
return unique;
|
|
161
164
|
}
|
|
162
165
|
export async function readCurrentLogFile(timeRange) {
|
|
163
|
-
const
|
|
164
|
-
const projectRoot = path.resolve(path.dirname(currentFilePath), "../../");
|
|
165
|
-
const logFile = path.join(projectRoot, "logs", "framework", "activity.log");
|
|
166
|
+
const logFile = activityLogPath();
|
|
166
167
|
try {
|
|
167
168
|
if (!fs.existsSync(logFile)) {
|
|
168
169
|
currentLogCache = null;
|
|
@@ -72,6 +72,18 @@ The hold lasts for the work that named the plane. A sentence that does not say l
|
|
|
72
72
|
|
|
73
73
|
Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
|
|
74
74
|
|
|
75
|
+
## Confer
|
|
76
|
+
|
|
77
|
+
The TUI that is wearing the suit already spawned the MCP servers. Confer uses those servers. It does not start a private server and it does not run `hermes -z`.
|
|
78
|
+
|
|
79
|
+
When `.xray/state/confer-ask-s.1.json`, `confer-ask-s.2.json`, and `confer-ask-s.3.json` are on disk:
|
|
80
|
+
|
|
81
|
+
1. Call the server and tool named in each ask. Researcher and code-review return evidence. Architect returns the assessment with `Verdict: UNREVIEWED`.
|
|
82
|
+
2. Write one verdict line from this TUI's model: `Verdict: PASS`, `Verdict: CONDITIONAL`, or `Verdict: FAIL`, plus top risks and a hardening note.
|
|
83
|
+
3. Call `record_confer_receipt` on `xray-governance` with `todoId`, `subagent`, `sessionId`, and that text.
|
|
84
|
+
|
|
85
|
+
Only `Verdict: PASS` completes the todo. FAIL, CONDITIONAL, and UNREVIEWED stay open. A session id that does not match the plan does not complete the todo. Grok, OpenCode, Hermes, and OpenClaw use these same three steps. Hermes is a voter only when Hermes is the TUI, and then only as that TUI's own model.
|
|
86
|
+
|
|
75
87
|
## Lead cadence (syncopation)
|
|
76
88
|
|
|
77
89
|
The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`).
|
|
@@ -35,4 +35,4 @@ Today those writers append `logs/framework/activity.log`. The features default s
|
|
|
35
35
|
|
|
36
36
|
When: on the tool hook, on framework logger flush, and on boot when file logging is on. Why: the report and the pulse read one tail, not a pile of copies.
|
|
37
37
|
|
|
38
|
-
stamped · 0xray 4.0.
|
|
38
|
+
stamped · 0xray 4.0.42
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Centrifuge
|
|
3
|
+
sidebar_label: Centrifuge
|
|
4
|
+
plate_type: domain model
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Centrifuge
|
|
8
|
+
|
|
9
|
+
One wake is one turn. Station is the axle. The gap stays open.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
CENTRIFUGE
|
|
13
|
+
┌──── VISOR ────┐
|
|
14
|
+
│ GOGGLES │
|
|
15
|
+
└───────┬───────┘
|
|
16
|
+
│ looks down
|
|
17
|
+
┌──────────────────┴──────────────────┐
|
|
18
|
+
│ DOMAIN │
|
|
19
|
+
│ │
|
|
20
|
+
JUDGEMENT│ LOOP STATE │PAYMENTS
|
|
21
|
+
· off │ STATION │ · off
|
|
22
|
+
· fixed │ FOUNDRY │ · fixed
|
|
23
|
+
│ MEMORY │
|
|
24
|
+
└────────────── ONE TURN ─────────────┘
|
|
25
|
+
the gap stays open
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Loop, domain, state, foundry, and memory ride that turn. Judgement and payments stay off the rotor. Goggles looks on and does not spin. The next turn waits for the next session or compact.
|
|
29
|
+
|
|
30
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ Cursor preCompact writes the station card and cannot block the compact.
|
|
|
32
32
|
|
|
33
33
|
The file is `src/integrations/cursor/hooks/pre-compact.js`. The message tells the seat to read STATION.md. The plates that belong here are payload-heat and station-heat.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -16,3 +16,7 @@ It views one plane.
|
|
|
16
16
|
│ · not every plane at once │
|
|
17
17
|
└────────────────────────────────────────────────────────────┘
|
|
18
18
|
```
|
|
19
|
+
|
|
20
|
+
A checkout named `0xray` records `scripts/mjs/run-goggles-mcp.mjs`. Any other project records `node_modules/0xray/scripts/mjs/run-goggles-mcp.mjs`.
|
|
21
|
+
|
|
22
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ Grok PreCompact runs session-start.js with the pre_compact event.
|
|
|
32
32
|
|
|
33
33
|
The hook is `session-start.js --hook-event=pre_compact`. It calls `buildSessionBootPayload`, writes the station card, and prints nothing. It does not match the conversation. Grok ignores hook stdout. The plates that belong here are payload-heat, cursor-compact, and work-fresh.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -38,4 +38,4 @@ Give your bots a house: shared rules, one board for the work, and memory that st
|
|
|
38
38
|
code links: suit → memory, house → doctor, memory → station. Other lines show reading order only.
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
stamped · 0xray 4.0.
|
|
41
|
+
stamped · 0xray 4.0.42 · @0xray/grok-bot 0.1.8
|
|
@@ -17,7 +17,7 @@ Plates have a type. A domain model plate shows how named parts fit. A state flow
|
|
|
17
17
|
|
|
18
18
|
## Domain model
|
|
19
19
|
|
|
20
|
-
[Goggles](./goggles.md) · [Suit](./suit.md) · [Kits](./kits.md) · [Host Pack](./host-pack.md) · [Glossary](./glossary.md) · [Grok Bot](./grokbot.md)
|
|
20
|
+
[Goggles](./goggles.md) · [Suit](./suit.md) · [Kits](./kits.md) · [Host Pack](./host-pack.md) · [Glossary](./glossary.md) · [Grok Bot](./grokbot.md) · [Centrifuge](./centrifuge.md)
|
|
21
21
|
|
|
22
22
|
## State flow
|
|
23
23
|
|
|
@@ -50,3 +50,5 @@ These eight are the pages the file ref names. Each one is a search lens. Each le
|
|
|
50
50
|
[Work fresh](./work-fresh.md) · [Kept line](./kept-line.md) · [Lens gate](./lens-gate.md) · [Pre tool](./pre-tool.md) · [Lens page](./lens-page.md)
|
|
51
51
|
|
|
52
52
|
These five are the compact path that was opened. Each one is a search lens. Each lens lists one skill and the plates that belong with it.
|
|
53
|
+
|
|
54
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ A station rewrite keeps one Fresh line and drops the copies.
|
|
|
32
32
|
|
|
33
33
|
mergeStationMarkdown in src/integrations/hooks/station-hook-runtime.cjs treats a Fresh line as stock. Copies are not preserved. When the new card has no Fresh line, the latest one is kept. The plates that belong here are station-card and work-fresh.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ A search names one plane or it stops.
|
|
|
32
32
|
|
|
33
33
|
lensBeforeResearch in src/integrations/hooks/goggles-pipeline.mjs returns null when the call is not research, and when the spoken text names exactly one card plane. Zero names, or more than one, deny with Name one plane. A shell that reads a project source file is research. The first open of a source file that no lens lists is allowed and remembered. The next search stops until that file is on a lens and the plate is on disk. The hook does not author the plate. The plate that belongs here is pre-tool.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ The lens page is the card for one plane.
|
|
|
32
32
|
|
|
33
33
|
`formatCardPane` in `src/integrations/hooks/goggles-pipeline.mjs` draws the card. Read the card instead of searching the tree. The plates that belong here are record-map and lens-gate.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -38,3 +38,7 @@ Intent names one plate. Equal top scores recall nothing. A missing worn copy is
|
|
|
38
38
|
│ └────────────────────┘ └────────────────────────┘ │
|
|
39
39
|
└──────────────────────────────────────────────────────────────┘
|
|
40
40
|
```
|
|
41
|
+
|
|
42
|
+
A look returns the named plane, the matched law names, and the current lines from the session-note index. It does not write a law.
|
|
43
|
+
|
|
44
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,5 @@ Notes are the body the station card cannot hold.
|
|
|
32
32
|
|
|
33
33
|
The page is `.xray/state/NOTES.md`. The pickup line equals the station intent. The default depth is the working notes: the point, the coverage, the library, the open pull requests, the rituals, and the next cut. A pickup line alone does not survive a compact. PreCompact calls `stampNotesPickup`, which updates only that line and leaves the body alone. The hook does not check the body. The seat writes it before the compact. Do not commit this file. Do not feed it to Repertoire.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
The station module writes this page. Heat keeps the current lines in `.xray/state/repertoire/session-notes.json` beside the laws. The wake cascade reads that index and does not write a law. A replaced note stays in that index as history. The short index returns the current line.
|
|
36
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ stampNotesPickup writes one pickup line and leaves the rest of NOTES.md alone.
|
|
|
32
32
|
|
|
33
33
|
The comment on the function is one pickup line. There is no check that the working notes are present. The plate that belongs here is notes-page.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ The tool hook is where the lens gate runs.
|
|
|
32
32
|
|
|
33
33
|
pre-tool-use.js joins the command, the written content, and the paths, then calls lensBeforeResearch. A deny ends the hook. The plate that belongs here is lens-gate.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -38,4 +38,5 @@ Trail: state and logs under `.xray`. Codex is already loaded. This plate is the
|
|
|
38
38
|
|
|
39
39
|
The published manual is `docs-site/docs/`. The rule sheet is `grok-bot/OP-PROC.md`. Neither is one of the five pages.
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Goggles plane `record-map` is the lens over this map. Station and the notes page belong to the station module. Repertoire laws stay in the law file. The session-note index sits beside that file.
|
|
42
|
+
stamped · 0xray 4.0.42
|
|
@@ -54,4 +54,4 @@ A state flow plate: one critic pass, one fix, one re-review, then stop.
|
|
|
54
54
|
|
|
55
55
|
A FAIL names the file and a test that fails on the old code. One author fixes that hole. A second session waits while the verdict is open. Re-review that new head. A hole the new test did not lock returns to ONE FIX. A PASS ends the plate. A note stays a note and does not open another lap.
|
|
56
56
|
|
|
57
|
-
stamped · 0xray 4.0.
|
|
57
|
+
stamped · 0xray 4.0.42
|
|
@@ -35,4 +35,4 @@ Today that file is `docs/inference/latest-session.json`. The home is `.xray/infe
|
|
|
35
35
|
|
|
36
36
|
Station reads the file for heat. The inference accumulator reads `session-*.json` beside it. Do not mint a `session-<date>-<sha>` file for the station note.
|
|
37
37
|
|
|
38
|
-
stamped · 0xray 4.0.
|
|
38
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,7 @@ The station card is the one-line ticket at .xray/state/STATION.md.
|
|
|
32
32
|
|
|
33
33
|
Read it after a compact. Leave Intent alone. The plan is the next cut. The long body belongs in notes.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
The station module writes this card. Heat adds `Cascade: record-map · notes N current`. The count is the current index. The body stays on the notes page.
|
|
36
|
+
|
|
37
|
+
The card keeps the named plane. `Sleeve: on` means the previous ticket came back, the worn plate matched the package, the previous ticket matched the working record, and inspect passed. Judgement is continue, retry N, stop, or start. The same miss keeps its retry. A different ticket stops. Payments is on only when the ticket is a payment.
|
|
38
|
+
stamped · 0xray 4.0.42
|
|
@@ -32,4 +32,4 @@ On a compact event applyStationHeat stamps the notes pickup line.
|
|
|
32
32
|
|
|
33
33
|
`isCompactHook` is true when the hook name contains compact. The body of NOTES.md is left alone. The plates that belong here are pickup-stamp and notes-page.
|
|
34
34
|
|
|
35
|
-
stamped · 0xray 4.0.
|
|
35
|
+
stamped · 0xray 4.0.42
|
|
@@ -35,4 +35,4 @@ Reporting reads the activity log and may write a report. Station reads `latest-s
|
|
|
35
35
|
|
|
36
36
|
Repertoire already keeps `inference-state.json` and the day log under `.xray/state/repertoire/`. Goggles does not write these files. It reads a plate when one plane is named.
|
|
37
37
|
|
|
38
|
-
stamped · 0xray 4.0.
|
|
38
|
+
stamped · 0xray 4.0.42
|