0xray 4.0.22 → 4.0.24
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/skills/orchestrator/SKILL.md +7 -7
- package/.xray/features.json +11 -1
- package/.xray/features.schema.json +17 -0
- package/AGENTS-consumer.md +1 -1
- package/AGENTS.md +1 -1
- package/README.md +2 -2
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +1 -1
- package/dist/CHANGELOG.md +44 -1
- package/dist/README.md +2 -2
- package/dist/SKILLS.md +1 -1
- package/dist/cli/index.js +131 -100
- package/dist/core/features-config.d.ts +4 -0
- package/dist/core/features-config.js +10 -0
- package/dist/inference/inference-accumulator.d.ts +2 -0
- package/dist/inference/inference-accumulator.js +110 -6
- package/dist/inference/inference-cycle.d.ts +12 -0
- package/dist/inference/inference-cycle.js +159 -16
- package/dist/inference/inference-proposal-generator.js +206 -5
- package/dist/inference/inference-run-gate.d.ts +8 -0
- package/dist/inference/inference-run-gate.js +10 -0
- package/dist/inference/session-capture.d.ts +31 -0
- package/dist/inference/session-capture.js +277 -1
- package/dist/integrations/cursor/hooks/pre-compact.js +89 -1
- package/dist/integrations/governance/index.d.ts +5 -0
- package/dist/integrations/governance/index.js +22 -2
- package/dist/integrations/governance/types.d.ts +11 -0
- package/dist/integrations/governance/types.js +16 -0
- package/dist/integrations/hooks/plates.cjs +165 -0
- package/dist/integrations/hooks/station-hook-runtime.cjs +29 -11
- package/dist/integrations/hooks/station-memory-ingest.mjs +109 -42
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/dist/mcps/governance.server.d.ts +2 -0
- package/dist/mcps/governance.server.js +12 -1
- package/dist/mcps/researcher-confidence.d.ts +5 -1
- package/dist/mcps/researcher-confidence.js +37 -0
- package/dist/mcps/researcher.server.js +2 -2
- package/dist/memory-routing/index.d.ts +1 -1
- package/dist/memory-routing/index.js +1 -1
- package/dist/memory-routing/lesson-pickup.d.ts +2 -0
- package/dist/memory-routing/lesson-pickup.js +57 -0
- package/dist/memory-routing/plates.d.ts +16 -0
- package/dist/memory-routing/plates.js +71 -0
- package/dist/memory-routing/provider-loader.d.ts +5 -0
- package/dist/memory-routing/provider-loader.js +46 -0
- package/dist/memory-routing/provider-registry.d.ts +7 -2
- package/dist/memory-routing/provider-registry.js +26 -6
- package/dist/memory-routing/record-lesson.d.ts +16 -0
- package/dist/memory-routing/record-lesson.js +26 -0
- package/dist/memory-routing/types.d.ts +17 -0
- package/dist/memory-routing/types.js +2 -1
- package/dist/nucleus/thin-dispatch.d.ts +2 -0
- package/dist/nucleus/thin-dispatch.js +3 -2
- package/dist/processors/implementations/inference-improvement-processor.d.ts +5 -0
- package/dist/processors/implementations/inference-improvement-processor.js +101 -2
- package/dist/processors/implementations/storytelling-trigger-processor.js +1 -11
- package/dist/processors/processor-manager.d.ts +1 -1
- package/dist/processors/processor-manager.js +52 -20
- package/dist/skills/orchestrator/SKILL.md +7 -7
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/scripts/foundry/plant/skills/mill/SKILL.md +1 -1
- package/scripts/foundry/reconcile-version.mjs +23 -1
- package/scripts/foundry/release.mjs +1 -1
- package/scripts/foundry/version-manager.mjs +53 -0
- package/scripts/node/consumer-install-smoke.mjs +3 -3
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
- package/src/mcps/governance.server.ts +12 -1
- package/src/mcps/researcher-confidence.ts +56 -3
- package/src/mcps/researcher.server.ts +4 -5
- package/src/skills/orchestrator/SKILL.md +7 -7
- package/vendor/@0xray/repertoire/README.md +3 -1
- package/vendor/@0xray/repertoire/data/stack-overlay.json +4 -4
- package/vendor/@0xray/repertoire/data/subject-overlay.json +3 -3
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +4 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/RepertoireService.js +4 -4
- package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +5 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +16 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/paths.d.ts +3 -3
- package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/paths.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +11 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +2 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +74 -4
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +431 -13
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -1
- package/vendor/@0xray/repertoire/dist/types.d.ts +21 -0
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -1
- package/vendor/@0xray/repertoire/package.json +1 -1
- package/xray/features.json +11 -1
- package/xray/features.schema.json +17 -0
|
@@ -13,6 +13,9 @@ import { PostProcessor } from "../processor-interfaces.js";
|
|
|
13
13
|
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
14
14
|
import { getConfigDir } from "../../core/config-paths.js";
|
|
15
15
|
import { featuresConfigLoader } from "../../core/features-config.js";
|
|
16
|
+
import { captureCompletedInferenceOperation, saveReflectionSession } from "../../inference/session-capture.js";
|
|
17
|
+
import { loadReflectionInferences } from "../../inference/inference-accumulator.js";
|
|
18
|
+
import { InferenceCycle } from "../../inference/inference-cycle.js";
|
|
16
19
|
export class InferenceImprovementProcessor extends PostProcessor {
|
|
17
20
|
name = "inferenceImprovement";
|
|
18
21
|
priority = 5;
|
|
@@ -55,7 +58,8 @@ export class InferenceImprovementProcessor extends PostProcessor {
|
|
|
55
58
|
try {
|
|
56
59
|
const workflowContext = await this.prepareWorkflowContext(directory);
|
|
57
60
|
await this.saveWorkflowContext(directory, workflowContext);
|
|
58
|
-
await this.triggerAgentWorkflow(workflowContext);
|
|
61
|
+
const workflowId = await this.triggerAgentWorkflow(workflowContext);
|
|
62
|
+
await this.captureFinishedOperationSpeech(directory, workflowId);
|
|
59
63
|
await frameworkLogger.log("inference-improvement", "workflow_triggered", "info", {
|
|
60
64
|
dataFiles: workflowContext.dataLocations.reflections.length +
|
|
61
65
|
workflowContext.dataLocations.logs.length +
|
|
@@ -251,12 +255,107 @@ Final validation and application of approved changes:
|
|
|
251
255
|
});
|
|
252
256
|
const workflowBase = path.isAbsolute(this.workflowDir) ? this.workflowDir : path.join(process.cwd(), this.workflowDir);
|
|
253
257
|
const outputPath = path.join(workflowBase, "workflow-status.json");
|
|
258
|
+
const workflowId = `inference-${Date.now()}`;
|
|
254
259
|
fs.writeFileSync(outputPath, JSON.stringify({
|
|
255
260
|
status: "in_progress",
|
|
256
261
|
phase: "data_gathering",
|
|
257
262
|
nextAgent: "researcher",
|
|
258
263
|
message: "Invoke @researcher to begin data gathering phase",
|
|
259
|
-
workflowId
|
|
264
|
+
workflowId
|
|
260
265
|
}, null, 2));
|
|
266
|
+
return workflowId;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* The operation is finished once its prompt result text is on disk.
|
|
270
|
+
* One session per operation id. Empty speech writes nothing.
|
|
271
|
+
*/
|
|
272
|
+
async captureFinishedOperationSpeech(directory, currentOperationId) {
|
|
273
|
+
const workflowBase = path.isAbsolute(this.workflowDir)
|
|
274
|
+
? this.workflowDir
|
|
275
|
+
: path.join(directory, this.workflowDir);
|
|
276
|
+
const promptsDir = path.join(workflowBase, "prompts");
|
|
277
|
+
const inferenceDir = path.join(directory, "docs", "inference");
|
|
278
|
+
const signalNames = readStoredSignalNames(directory);
|
|
279
|
+
const ids = operationIdsToCapture(promptsDir, currentOperationId);
|
|
280
|
+
let captured = 0;
|
|
281
|
+
for (const operationId of ids) {
|
|
282
|
+
const saved = captureCompletedInferenceOperation({
|
|
283
|
+
operationId,
|
|
284
|
+
promptsDir,
|
|
285
|
+
inferenceDir,
|
|
286
|
+
signalNames,
|
|
287
|
+
});
|
|
288
|
+
if (!saved)
|
|
289
|
+
continue;
|
|
290
|
+
captured += 1;
|
|
291
|
+
await frameworkLogger.log("inference-improvement", "operation_session_captured", "info", { operationId, saved });
|
|
292
|
+
}
|
|
293
|
+
let reflectionSaved = 0;
|
|
294
|
+
for (const session of loadReflectionInferences(inferenceDir)) {
|
|
295
|
+
const saved = saveReflectionSession(session, inferenceDir);
|
|
296
|
+
if (!saved)
|
|
297
|
+
continue;
|
|
298
|
+
reflectionSaved += 1;
|
|
299
|
+
await frameworkLogger.log("inference-improvement", "reflection_session_written", "info", {
|
|
300
|
+
sessionId: session.sessionId,
|
|
301
|
+
saved,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (captured === 0 && reflectionSaved === 0)
|
|
305
|
+
return;
|
|
306
|
+
const cycle = new InferenceCycle(directory, undefined, {
|
|
307
|
+
force: true,
|
|
308
|
+
skipApply: true,
|
|
309
|
+
skipDeployVerify: true,
|
|
310
|
+
});
|
|
311
|
+
await cycle.maybeRunCycle();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function operationIdsToCapture(promptsDir, currentOperationId) {
|
|
315
|
+
const ids = new Set();
|
|
316
|
+
if (currentOperationId.trim().length > 0)
|
|
317
|
+
ids.add(currentOperationId);
|
|
318
|
+
if (!fs.existsSync(promptsDir))
|
|
319
|
+
return [...ids];
|
|
320
|
+
for (const name of fs.readdirSync(promptsDir)) {
|
|
321
|
+
const stem = /^(inference-\d+)\.result\.(md|txt)$/i.exec(name);
|
|
322
|
+
if (stem?.[1])
|
|
323
|
+
ids.add(stem[1]);
|
|
324
|
+
const full = path.join(promptsDir, name);
|
|
325
|
+
if (!name.endsWith(".md") && !name.endsWith(".txt"))
|
|
326
|
+
continue;
|
|
327
|
+
let text = "";
|
|
328
|
+
try {
|
|
329
|
+
text = fs.readFileSync(full, "utf8");
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
const declared = /^operation:\s*(\S+)\s*$/im.exec(text);
|
|
335
|
+
if (declared?.[1])
|
|
336
|
+
ids.add(declared[1]);
|
|
337
|
+
}
|
|
338
|
+
return [...ids];
|
|
339
|
+
}
|
|
340
|
+
function readStoredSignalNames(directory) {
|
|
341
|
+
const dest = path.join(directory, ".xray", "state", "repertoire", "curated_signals.json");
|
|
342
|
+
if (!fs.existsSync(dest))
|
|
343
|
+
return [];
|
|
344
|
+
try {
|
|
345
|
+
const parsed = JSON.parse(fs.readFileSync(dest, "utf8"));
|
|
346
|
+
if (!Array.isArray(parsed.signals))
|
|
347
|
+
return [];
|
|
348
|
+
const names = [];
|
|
349
|
+
for (const signal of parsed.signals) {
|
|
350
|
+
if (!signal || typeof signal !== "object")
|
|
351
|
+
continue;
|
|
352
|
+
const name = signal.name;
|
|
353
|
+
if (typeof name === "string" && name.trim().length > 0)
|
|
354
|
+
names.push(name.trim());
|
|
355
|
+
}
|
|
356
|
+
return names;
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return [];
|
|
261
360
|
}
|
|
262
361
|
}
|
|
@@ -5,7 +5,6 @@ import { PostProcessor } from "../processor-interfaces.js";
|
|
|
5
5
|
import { frameworkLogger } from "../../core/framework-logger.js";
|
|
6
6
|
import { featuresConfigLoader } from "../../core/features-config.js";
|
|
7
7
|
import { analyzeStructuralPatterns, } from "../../inference/semantic-patterns.js";
|
|
8
|
-
import { captureSessionInference, saveSessionInference, } from "../../inference/session-capture.js";
|
|
9
8
|
export class StorytellingTriggerProcessor extends PostProcessor {
|
|
10
9
|
name = "storytelling-trigger";
|
|
11
10
|
priority = 5;
|
|
@@ -327,16 +326,7 @@ export class StorytellingTriggerProcessor extends PostProcessor {
|
|
|
327
326
|
inferences.push(`${p.name} pattern detected [${Math.round(p.confidence * 100)}%]: ${p.description}${evidence}`);
|
|
328
327
|
}
|
|
329
328
|
if (semanticPatterns.length > 0) {
|
|
330
|
-
|
|
331
|
-
const session = captureSessionInference(sinceRef, untilRef);
|
|
332
|
-
if (session) {
|
|
333
|
-
const savedPath = saveSessionInference(session);
|
|
334
|
-
inferences.push(`Structured inference captured → ${path.basename(savedPath)}`);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
catch {
|
|
338
|
-
// session capture is best-effort
|
|
339
|
-
}
|
|
329
|
+
inferences.push("Semantic patterns stay on the reflection. A graded session comes from finished operation speech, not from commit subjects.");
|
|
340
330
|
}
|
|
341
331
|
}
|
|
342
332
|
if (diff.filesAdded.some(f => f.includes("implementations/") && f.endsWith(".ts"))) {
|
|
@@ -68,7 +68,7 @@ export declare class ProcessorManager {
|
|
|
68
68
|
success: boolean;
|
|
69
69
|
results: ProcessorResult[];
|
|
70
70
|
}>;
|
|
71
|
-
executePostProcessors(operation: string, data:
|
|
71
|
+
executePostProcessors(operation: string, data: unknown, preResults: ProcessorResult[]): Promise<ProcessorResult[]>;
|
|
72
72
|
private executeProcessor;
|
|
73
73
|
private updateMetrics;
|
|
74
74
|
getProcessorHealth(): ProcessorHealth[];
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { frameworkLogger } from "../core/framework-logger.js";
|
|
2
2
|
import { readdir } from "fs/promises";
|
|
3
|
-
import { join, basename } from "path";
|
|
3
|
+
import { join, basename, dirname } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
function asProcessorContext(ctx) {
|
|
7
|
+
return ctx;
|
|
8
|
+
}
|
|
9
|
+
function readContextString(ctx, key) {
|
|
10
|
+
const direct = ctx[key];
|
|
11
|
+
if (typeof direct === "string" && direct.length > 0)
|
|
12
|
+
return direct;
|
|
13
|
+
const toolInput = ctx.toolInput;
|
|
14
|
+
if (!toolInput || typeof toolInput !== "object")
|
|
15
|
+
return undefined;
|
|
16
|
+
const args = toolInput.args;
|
|
17
|
+
if (!args || typeof args !== "object")
|
|
18
|
+
return undefined;
|
|
19
|
+
const value = args[key];
|
|
20
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
21
|
+
}
|
|
4
22
|
export class ProcessorManager {
|
|
5
23
|
processors = new Map();
|
|
6
24
|
metrics = new Map();
|
|
@@ -13,24 +31,34 @@ export class ProcessorManager {
|
|
|
13
31
|
this.registerBuiltInFactories();
|
|
14
32
|
}
|
|
15
33
|
registerProcessorInstance(processor) {
|
|
16
|
-
|
|
17
|
-
|
|
34
|
+
const factoryExisted = this.factories.has(processor.name);
|
|
35
|
+
if (!factoryExisted) {
|
|
36
|
+
this.factories.set(processor.name, {
|
|
37
|
+
execute: async (ctx) => {
|
|
38
|
+
const result = await processor.execute(asProcessorContext(ctx));
|
|
39
|
+
return result.data;
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const processorExisted = this.processors.has(processor.name);
|
|
44
|
+
if (!processorExisted) {
|
|
45
|
+
this.registerProcessor({
|
|
46
|
+
name: processor.name,
|
|
47
|
+
type: processor.type,
|
|
48
|
+
priority: processor.priority,
|
|
49
|
+
enabled: processor.enabled,
|
|
50
|
+
});
|
|
18
51
|
}
|
|
19
|
-
this.factories.set(processor.name, {
|
|
20
|
-
execute: async (ctx) => {
|
|
21
|
-
const result = await processor.execute(ctx);
|
|
22
|
-
return result.data;
|
|
23
|
-
},
|
|
24
|
-
});
|
|
25
52
|
frameworkLogger.log("processor-manager", "auto-discovered-processor", "info", {
|
|
26
53
|
name: processor.name,
|
|
27
54
|
type: processor.type,
|
|
28
55
|
priority: processor.priority,
|
|
56
|
+
registered: !processorExisted,
|
|
29
57
|
});
|
|
30
|
-
return
|
|
58
|
+
return !factoryExisted || !processorExisted;
|
|
31
59
|
}
|
|
32
60
|
async discoverProcessors(directory) {
|
|
33
|
-
const dir = directory || join(
|
|
61
|
+
const dir = directory || join(moduleDir, "implementations");
|
|
34
62
|
const discovered = [];
|
|
35
63
|
let files;
|
|
36
64
|
try {
|
|
@@ -130,8 +158,8 @@ export class ProcessorManager {
|
|
|
130
158
|
execute: async (ctx) => {
|
|
131
159
|
const { LogProtectionProcessor } = await import("./implementations/log-protection-processor.js");
|
|
132
160
|
const p = new LogProtectionProcessor();
|
|
133
|
-
const filePath = ctx
|
|
134
|
-
const operation = ctx
|
|
161
|
+
const filePath = readContextString(ctx, "filePath");
|
|
162
|
+
const operation = readContextString(ctx, "operation");
|
|
135
163
|
const result = await p.execute({ filePath, operation });
|
|
136
164
|
return result.data;
|
|
137
165
|
},
|
|
@@ -229,7 +257,7 @@ export class ProcessorManager {
|
|
|
229
257
|
f.set("testAutoCreation", {
|
|
230
258
|
execute: async (ctx) => {
|
|
231
259
|
const { testAutoCreationProcessor } = await import("./implementations/test-auto-creation-processor.js");
|
|
232
|
-
const result = await testAutoCreationProcessor.execute(ctx);
|
|
260
|
+
const result = await testAutoCreationProcessor.execute(asProcessorContext(ctx));
|
|
233
261
|
return { success: result.success, message: result.message, data: result.data };
|
|
234
262
|
},
|
|
235
263
|
init: async () => {
|
|
@@ -249,8 +277,8 @@ export class ProcessorManager {
|
|
|
249
277
|
const { AgentsMdValidationProcessor } = await import("./implementations/agents-md-validation-processor.js");
|
|
250
278
|
const p = new AgentsMdValidationProcessor(process.cwd());
|
|
251
279
|
const result = await p.execute({
|
|
252
|
-
tool: ctx
|
|
253
|
-
operation: ctx
|
|
280
|
+
tool: readContextString(ctx, "tool") ?? "validate",
|
|
281
|
+
operation: readContextString(ctx, "operation") ?? "pre-commit",
|
|
254
282
|
});
|
|
255
283
|
return {
|
|
256
284
|
success: result.success,
|
|
@@ -283,7 +311,7 @@ export class ProcessorManager {
|
|
|
283
311
|
f.set("typescriptCompilation", {
|
|
284
312
|
execute: async (ctx) => {
|
|
285
313
|
const { runTypeScriptCompilation } = await import("./implementations/typescript-compilation-processor.js");
|
|
286
|
-
const cwd = ctx
|
|
314
|
+
const cwd = readContextString(ctx, "directory") ?? process.cwd();
|
|
287
315
|
return runTypeScriptCompilation(cwd);
|
|
288
316
|
},
|
|
289
317
|
init: async () => {
|
|
@@ -762,10 +790,14 @@ export class ProcessorManager {
|
|
|
762
790
|
if (Array.isArray(context)) {
|
|
763
791
|
return { valid: true, errors: [] };
|
|
764
792
|
}
|
|
765
|
-
const
|
|
793
|
+
const record = context;
|
|
794
|
+
const contextData = record.data;
|
|
766
795
|
if (contextData && typeof contextData !== "object") {
|
|
767
796
|
return { valid: true, errors: [] };
|
|
768
797
|
}
|
|
798
|
+
const dataRecord = contextData && typeof contextData === "object"
|
|
799
|
+
? contextData
|
|
800
|
+
: {};
|
|
769
801
|
const requiredFields = {
|
|
770
802
|
preValidate: ["operation"],
|
|
771
803
|
codexCompliance: ["operation"],
|
|
@@ -779,7 +811,7 @@ export class ProcessorManager {
|
|
|
779
811
|
};
|
|
780
812
|
const required = requiredFields[processorName] || [];
|
|
781
813
|
for (const field of required) {
|
|
782
|
-
if (!(field in
|
|
814
|
+
if (!(field in record) && !(field in dataRecord)) {
|
|
783
815
|
errors.push(`Missing required field: ${field}`);
|
|
784
816
|
}
|
|
785
817
|
}
|
|
@@ -787,7 +819,7 @@ export class ProcessorManager {
|
|
|
787
819
|
frameworkLogger.log("processor-manager", "context-validation-warnings", "info", {
|
|
788
820
|
processor: processorName,
|
|
789
821
|
errors,
|
|
790
|
-
contextKeys: Object.keys(
|
|
822
|
+
contextKeys: Object.keys(record),
|
|
791
823
|
});
|
|
792
824
|
}
|
|
793
825
|
return { valid: errors.length === 0, errors };
|
|
@@ -7,15 +7,15 @@ version: 1.0.0
|
|
|
7
7
|
schema_version: "1.0"
|
|
8
8
|
tags: [orchestration, orchestrator, lead-dev]
|
|
9
9
|
capabilities:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
- coordinate_agents
|
|
11
|
+
- delegate_tasks
|
|
12
|
+
- manage_workflow
|
|
13
13
|
dependencies: []
|
|
14
14
|
|
|
15
15
|
mcp:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
orchestrator:
|
|
17
|
+
command: node
|
|
18
|
+
args: [node_modules/0xray/dist/mcps/orchestrator.server.js]
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
# Orchestrator Skill — includes lead-dev operating model
|
|
@@ -77,7 +77,7 @@ Jargon is not the job. Review and cadence ask whether the change works. Do not s
|
|
|
77
77
|
- **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
|
|
78
78
|
- **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
|
|
79
79
|
- **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
|
|
80
|
-
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Capture priority: a law is an invariant you would otherwise re-read the source to relearn. One law per subsystem bone. Heat touches last_seen and does not append a confidence sample, so more hits do not raise conviction. Heat touches last_seen
|
|
80
|
+
- **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Capture priority: a law is an invariant you would otherwise re-read the source to relearn. One law per subsystem bone. Heat touches last_seen and does not append a confidence sample, so more hits do not raise conviction. Heat touches last_seen when the diary contains that signal's name or a local clause of four definition content words; two definition words are not a hit; the same words scattered through a long diary are not a hit; a weak session score is not lifted to 0.55 and a sample below 0.55 is not recorded. Constructing the organ does not append workspace samples. Hero names: `heat-is-not-conviction`, `inference-cycle-invariant`, `governance-vote-invariant`, `thin-dispatch-invariant`. Repertoire mergeStackOverlay refreshes a changed stack definition and keeps observation stats. A floor observation count does not change a route. Feedback moves conviction by a tenth, and a failure can leave 0.55. learned-conviction.json beside dest restores that average when a wake flattens it to 0.55. It does not store the observation count.
|
|
81
81
|
- **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
|
|
82
82
|
- **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
|
|
83
83
|
|
package/llms.txt
CHANGED
|
@@ -35,7 +35,7 @@ Registered in `.mcp.json` as `npx -y 0xray mcp <cmd>`:
|
|
|
35
35
|
| `xray-code-review` | Proposal quality |
|
|
36
36
|
| `xray-architect-tools` | System design |
|
|
37
37
|
|
|
38
|
-
Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.
|
|
38
|
+
Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.8 ships on (`npx @0xray/repertoire mcp`). Dest is named laws, not hangar `repo-*` or git slugs. Survive compact is **Station** (Read `.xray/state/STATION.md`). Station is the ticket, not a substitute for Repertoire. Do not pin 0.1.8.
|
|
39
39
|
|
|
40
40
|
## Codex 69 (always on)
|
|
41
41
|
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ The mill **fastens** a suit. Default mill plant is **inspect** (inspecting AI wo
|
|
|
11
11
|
|
|
12
12
|
**Mill-fill:** their keys/files win. Mill plant names they did not overlay stay. JSON always merges.
|
|
13
13
|
|
|
14
|
-
**Factory:** **Repertoire is preferred** (vendored 0.2.
|
|
14
|
+
**Factory:** **Repertoire is preferred** (vendored 0.2.8 ships on; dest = named laws). Seven generated MCP. Constitution (PPE) stays worn. Not a fifth MCP. Not 5.0.
|
|
15
15
|
|
|
16
16
|
**Costume:** `foundry.json` `"costume": true` copies the 45/42 mill costume.
|
|
17
17
|
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* npx @0xray/foundry reconcile --check
|
|
10
10
|
* npx @0xray/foundry reconcile patch
|
|
11
11
|
* npx @0xray/foundry reconcile patch --apply
|
|
12
|
+
*
|
|
13
|
+
* --apply writes package.json and the package-lock.json version fields.
|
|
14
|
+
* --check fails when the lock does not match package.json.
|
|
12
15
|
*/
|
|
13
16
|
|
|
14
17
|
import { execSync } from "child_process";
|
|
@@ -16,6 +19,7 @@ import fs from "fs";
|
|
|
16
19
|
import path from "path";
|
|
17
20
|
import { fileURLToPath } from "url";
|
|
18
21
|
import { readRootPackage, resolveMillRoot } from "./mill-root.mjs";
|
|
22
|
+
import { packageLockVersions, syncPackageLockVersion } from "./version-manager.mjs";
|
|
19
23
|
|
|
20
24
|
const rootDir = resolveMillRoot();
|
|
21
25
|
const pkgPath = path.join(rootDir, "package.json");
|
|
@@ -101,8 +105,12 @@ function main() {
|
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
console.log("\n=== Version Reconcile ===\n");
|
|
108
|
+
const lockBefore = packageLockVersions(rootDir);
|
|
104
109
|
console.log(` npm registry : ${npm}`);
|
|
105
110
|
console.log(` package.json : ${local}`);
|
|
111
|
+
console.log(
|
|
112
|
+
` package-lock : ${lockBefore ? `${lockBefore.root} / ${lockBefore.pkg}` : "(none)"}`,
|
|
113
|
+
);
|
|
106
114
|
console.log(` latest tag : ${tag ? `v${tag}` : "(none)"}`);
|
|
107
115
|
if (bumpType) {
|
|
108
116
|
console.log(` bump ${bumpType} : ${target} (from baseline ${baseline})`);
|
|
@@ -112,7 +120,13 @@ function main() {
|
|
|
112
120
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
113
121
|
pkg.version = target;
|
|
114
122
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
115
|
-
|
|
123
|
+
const synced = syncPackageLockVersion(rootDir, target);
|
|
124
|
+
if (synced === "unmatched") {
|
|
125
|
+
fail(
|
|
126
|
+
`package-lock.json version fields were not updated to ${target}. Refusing to leave the lock behind package.json.`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
console.log(`\n✅ Updated package.json and package-lock.json → ${target}`);
|
|
116
130
|
}
|
|
117
131
|
|
|
118
132
|
if (!checkMode) {
|
|
@@ -129,6 +143,14 @@ function main() {
|
|
|
129
143
|
fail(`package.json (${local}) must be > npm (${npm}). Run: npx @0xray/foundry reconcile patch --apply`);
|
|
130
144
|
}
|
|
131
145
|
|
|
146
|
+
const pkgVersion = readLocalVersion();
|
|
147
|
+
const lockNow = packageLockVersions(rootDir);
|
|
148
|
+
if (lockNow && (lockNow.root !== pkgVersion || lockNow.pkg !== pkgVersion)) {
|
|
149
|
+
fail(
|
|
150
|
+
`package-lock.json (${lockNow.root} / ${lockNow.pkg}) must match package.json (${pkgVersion}). The bumper writes both: npx @0xray/foundry reconcile patch --apply`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
132
154
|
if (tag && compare(local, tag) < 0) {
|
|
133
155
|
fail(`package.json (${local}) is behind latest tag v${tag}`);
|
|
134
156
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Canonical 0xRay release script.
|
|
5
5
|
*
|
|
6
|
-
* 1. Bump version from npm registry baseline (reconcile-version)
|
|
6
|
+
* 1. Bump version from npm registry baseline (reconcile-version writes package.json and package-lock.json)
|
|
7
7
|
* 2. Release artifacts (CHANGELOG / README / AGENTS / docs) — before gate so docs tests pass
|
|
8
8
|
* 3. Release gate (build + test + consumer smoke)
|
|
9
9
|
* 4. Commit release artifacts → push
|
|
@@ -333,6 +333,57 @@ function updateFeaturesJsonVersion(newVersion) {
|
|
|
333
333
|
updateJsonVersionField('.xray/features.json', newVersion);
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
+
export function packageLockVersions(dir) {
|
|
337
|
+
const full = path.join(dir, 'package-lock.json');
|
|
338
|
+
if (!fs.existsSync(full)) return null;
|
|
339
|
+
const lock = JSON.parse(fs.readFileSync(full, 'utf-8'));
|
|
340
|
+
const root = typeof lock.version === 'string' ? lock.version : '';
|
|
341
|
+
const pkg = typeof lock.packages?.['']?.version === 'string' ? lock.packages[''].version : '';
|
|
342
|
+
return { root, pkg };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Write the root lock version and packages[""].version to match package.json.
|
|
347
|
+
* Returns 'missing' | 'same' | 'updated' | 'unmatched'.
|
|
348
|
+
* Does not rewrite the rest of the lock.
|
|
349
|
+
*/
|
|
350
|
+
export function syncPackageLockVersion(dir, newVersion) {
|
|
351
|
+
const full = path.join(dir, 'package-lock.json');
|
|
352
|
+
if (!fs.existsSync(full)) return 'missing';
|
|
353
|
+
const raw = fs.readFileSync(full, 'utf-8');
|
|
354
|
+
const current = packageLockVersions(dir);
|
|
355
|
+
if (current && current.root === newVersion && current.pkg === newVersion) return 'same';
|
|
356
|
+
const previous = current?.root ?? '';
|
|
357
|
+
const lines = raw.split('\n');
|
|
358
|
+
let rootDone = false;
|
|
359
|
+
let pkgDone = false;
|
|
360
|
+
const next = lines.map((line) => {
|
|
361
|
+
if (!rootDone && line === ` "version": "${previous}",`) {
|
|
362
|
+
rootDone = true;
|
|
363
|
+
return ` "version": "${newVersion}",`;
|
|
364
|
+
}
|
|
365
|
+
if (rootDone && !pkgDone && line === ` "version": "${previous}",`) {
|
|
366
|
+
pkgDone = true;
|
|
367
|
+
return ` "version": "${newVersion}",`;
|
|
368
|
+
}
|
|
369
|
+
return line;
|
|
370
|
+
});
|
|
371
|
+
if (!rootDone || !pkgDone) return 'unmatched';
|
|
372
|
+
fs.writeFileSync(full, next.join('\n'));
|
|
373
|
+
return 'updated';
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function updatePackageLockVersion(newVersion) {
|
|
377
|
+
const synced = syncPackageLockVersion(rootDir, newVersion);
|
|
378
|
+
if (synced === 'updated') {
|
|
379
|
+
console.log(`✅ Updated package-lock.json (version: ${newVersion})`);
|
|
380
|
+
}
|
|
381
|
+
if (synced === 'unmatched') {
|
|
382
|
+
console.error(`\n❌ package-lock.json version fields did not match the expected shape for ${newVersion}\n`);
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
336
387
|
function updateOpenclawPluginVersion(newVersion) {
|
|
337
388
|
updateJsonVersionField('src/integrations/openclaw/plugin/xray-pre-tool/package.json', newVersion);
|
|
338
389
|
}
|
|
@@ -482,6 +533,7 @@ export function getReleaseArtifactPaths(baseDir = resolveMillRoot()) {
|
|
|
482
533
|
'docs-site/sidebars.ts',
|
|
483
534
|
'xray/features.json',
|
|
484
535
|
'.xray/features.json',
|
|
536
|
+
'package-lock.json',
|
|
485
537
|
'docs/PIPELINE-FACET-SNAPSHOT.json',
|
|
486
538
|
'src/integrations/openclaw/plugin/xray-pre-tool/package.json',
|
|
487
539
|
];
|
|
@@ -497,6 +549,7 @@ function updateReleaseArtifactsOnly(changeDescription = '') {
|
|
|
497
549
|
updateChangelog(current, changeDescription);
|
|
498
550
|
updatePluginJsonVersion(current);
|
|
499
551
|
updateFeaturesJsonVersion(current);
|
|
552
|
+
updatePackageLockVersion(current);
|
|
500
553
|
updateOpenclawPluginVersion(current);
|
|
501
554
|
const stripped = stripLivePatchRefs(rootDir, current);
|
|
502
555
|
if (stripped.length > 0) {
|
|
@@ -92,7 +92,7 @@ function assertOrganRequire(tmpRoot) {
|
|
|
92
92
|
if (organPkg.name !== "@0xray/repertoire") {
|
|
93
93
|
throw new Error(`required organ name ${organPkg.name}`);
|
|
94
94
|
}
|
|
95
|
-
if (organPkg.version !== "0.2.
|
|
95
|
+
if (organPkg.version !== "0.2.8") {
|
|
96
96
|
throw new Error(`required organ version ${organPkg.version}`);
|
|
97
97
|
}
|
|
98
98
|
if (fs.existsSync(path.join(tmpRoot, "vendor"))) {
|
|
@@ -165,8 +165,8 @@ function assertFreshInstallDefaults(tmpRoot, version) {
|
|
|
165
165
|
throw new Error("vendored @0xray/repertoire missing from fresh tarball install");
|
|
166
166
|
}
|
|
167
167
|
const organ = JSON.parse(fs.readFileSync(organPkg, "utf-8"));
|
|
168
|
-
if (organ.version !== "0.2.
|
|
169
|
-
throw new Error(`expected organ 0.2.
|
|
168
|
+
if (organ.version !== "0.2.8") {
|
|
169
|
+
throw new Error(`expected organ 0.2.8, got ${organ.version}`);
|
|
170
170
|
}
|
|
171
171
|
console.log(" ✅ .xray/features.json fresh-install defaults (opt-in off)");
|
|
172
172
|
return { consumerFeaturesPath, features };
|
|
@@ -245,8 +245,19 @@ class GovernanceServer extends XrayKnowledgeSkillBase {
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
/** Boot stays flag-gated. A required external call starts the client on demand. */
|
|
249
|
+
private async armRequiredDynamo(requireExternal: boolean): Promise<void> {
|
|
250
|
+
if (!requireExternal) return;
|
|
251
|
+
const integration = await initializeGovernanceIntegration();
|
|
252
|
+
if (!integration.isAvailable()) {
|
|
253
|
+
await integration.ensureDynamoClient();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
248
257
|
private async handleGovernProposals(args: GovernProposalsArgs): Promise<CallToolResult> {
|
|
249
258
|
const service = getGovernanceService();
|
|
259
|
+
const requireExternal = this.resolveRequireExternal(args.options?.require_external);
|
|
260
|
+
await this.armRequiredDynamo(requireExternal);
|
|
250
261
|
|
|
251
262
|
const request: GovernanceRequest = {
|
|
252
263
|
proposals: args.proposals.map((p, i) => ({
|
|
@@ -260,7 +271,7 @@ class GovernanceServer extends XrayKnowledgeSkillBase {
|
|
|
260
271
|
})),
|
|
261
272
|
context: args.context || {},
|
|
262
273
|
options: {
|
|
263
|
-
requireExternalDynamo:
|
|
274
|
+
requireExternalDynamo: requireExternal,
|
|
264
275
|
},
|
|
265
276
|
};
|
|
266
277
|
|