0xray 3.5.1 → 3.5.3
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/.gitignore.default +8 -0
- package/.opencode/hooks/post-commit +7 -27
- package/.xray/features.json +6 -0
- package/.xray/features.schema.json +17 -0
- package/AGENTS-consumer.md +1 -1
- package/AGENTS.md +1 -1
- package/README.md +1 -1
- package/SKILLS.md +1 -1
- package/dist/.gitignore.default +8 -0
- package/dist/AGENTS.md +1 -1
- package/dist/CHANGELOG.md +25 -0
- package/dist/README.md +1 -1
- package/dist/SKILLS.md +1 -1
- package/dist/core/bridge.mjs +10 -32
- package/dist/core/features-config.d.ts +16 -0
- package/dist/core/features-config.js +24 -0
- package/dist/integrations/grok/hooks/grok-hook-utils.js +2 -2
- package/dist/integrations/grok/hooks/post-tool-use.js +1 -1
- package/dist/integrations/grok/hooks/pre-tool-use.js +23 -32
- package/dist/integrations/grok/hooks/session-start.js +20 -1
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +2 -1
- package/dist/integrations/hermes-agent/bridge.mjs +22 -50
- package/dist/integrations/hooks/synthesis-hook-runtime.mjs +50 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.d.ts +3 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +25 -10
- package/dist/mcps/orchestrator/server.js +124 -4
- package/dist/memory-routing/types.d.ts +7 -0
- package/dist/nucleus/autonomy-kernel.d.ts +3 -0
- package/dist/nucleus/autonomy-kernel.js +40 -0
- package/dist/nucleus/delegation-gate.d.ts +6 -4
- package/dist/nucleus/delegation-gate.js +77 -5
- package/dist/nucleus/lead-dev-plan-persistence.d.ts +3 -0
- package/dist/nucleus/lead-dev-plan-persistence.js +44 -1
- package/dist/nucleus/synthesis-completion.d.ts +6 -0
- package/dist/nucleus/synthesis-completion.js +29 -0
- package/dist/nucleus/synthesis-context.d.ts +31 -0
- package/dist/nucleus/synthesis-context.js +86 -0
- package/dist/nucleus/synthesis.d.ts +54 -0
- package/dist/nucleus/synthesis.js +196 -0
- package/dist/plugin/xray-codex-injection.js +17 -0
- package/package.json +8 -3
- package/scripts/helpers/find-project-root.mjs +92 -0
- package/scripts/hooks/install-hooks.cjs +136 -36
- package/scripts/hooks/run-hook.js +46 -9
- package/scripts/mjs/delegation-gate-fixture.mjs +37 -0
- package/scripts/mjs/verify-grok-synthesis-gate.mjs +121 -0
- package/scripts/node/auto-reflection-generator.mjs +7 -0
- package/scripts/node/consumer-gitignore.cjs +101 -0
- package/scripts/node/load-reflection-config.mjs +77 -0
- package/scripts/node/postinstall.cjs +9 -6
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +2 -1
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +33 -8
- package/src/mcps/orchestrator/server.ts +181 -5
- package/xray/features.json +6 -0
- package/xray/features.schema.json +17 -0
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
resolveConsumerTargetDir,
|
|
8
8
|
isConsumerInstall,
|
|
9
9
|
} = require("./install-bridges.cjs");
|
|
10
|
+
const { applyConsumerGitignore } = require("./consumer-gitignore.cjs");
|
|
10
11
|
|
|
11
12
|
function structuredLog(component, action, status, details) {
|
|
12
13
|
const ts = new Date().toISOString();
|
|
@@ -39,12 +40,14 @@ if (fs.existsSync(agentsConsumer) && isConsumerInstall(resolvedPackage, resolved
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
// .gitignore: full template when absent; merge suit block when existing
|
|
44
|
+
if (isConsumerInstall(resolvedPackage, resolvedTarget)) {
|
|
45
|
+
const gitignoreResult = applyConsumerGitignore(targetDir, packageRoot);
|
|
46
|
+
if (gitignoreResult === "created") {
|
|
47
|
+
structuredLog("postinstall", "Created .gitignore from template", "info");
|
|
48
|
+
} else if (gitignoreResult === "merged") {
|
|
49
|
+
structuredLog("postinstall", "Merged 0xray suit entries into .gitignore", "info");
|
|
50
|
+
}
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
// Unified 4-platform bridge install (OpenCode, Grok, Hermes, OpenClaw)
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"type": "command",
|
|
37
37
|
"command": "node",
|
|
38
38
|
"args": [
|
|
39
|
-
"${XRAY_AI_PATH:-node_modules/0xray}/dist/integrations/grok/hooks/session-start.js"
|
|
39
|
+
"${XRAY_AI_PATH:-node_modules/0xray}/dist/integrations/grok/hooks/session-start.js",
|
|
40
|
+
"--hook-event=user_prompt_submit"
|
|
40
41
|
],
|
|
41
42
|
"timeout": 15000
|
|
42
43
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { frameworkLogger } from '../../../core/framework-logger.js';
|
|
8
8
|
import {
|
|
9
9
|
buildLeadDevPlan,
|
|
10
|
+
buildSynthesisCheckpointPlan,
|
|
10
11
|
isLeadDevModeActive,
|
|
11
12
|
persistLeadDevPlan,
|
|
12
13
|
} from '../../../nucleus/autonomy-kernel.js';
|
|
@@ -67,9 +68,14 @@ export class ComplexityHandler {
|
|
|
67
68
|
* Handle analyze-complexity request
|
|
68
69
|
*/
|
|
69
70
|
async handleAnalyzeComplexity(
|
|
70
|
-
args: {
|
|
71
|
+
args: {
|
|
72
|
+
tasks: AnalyzeComplexityInput[];
|
|
73
|
+
sessionId?: string;
|
|
74
|
+
synthesisCheckpoint?: boolean;
|
|
75
|
+
synthesisDueReason?: string | null;
|
|
76
|
+
},
|
|
71
77
|
asideId?: string,
|
|
72
|
-
): Promise<{ content: Array<{ type: string; text: string }
|
|
78
|
+
): Promise<{ content: Array<{ type: string; text: string }>; ok: boolean }> {
|
|
73
79
|
const tasks = normalizeAnalyzeTasks(args.tasks ?? []);
|
|
74
80
|
|
|
75
81
|
await frameworkLogger.log(
|
|
@@ -92,8 +98,10 @@ export class ComplexityHandler {
|
|
|
92
98
|
const planTaskInputs = tasks
|
|
93
99
|
.filter((t) => t.description?.trim())
|
|
94
100
|
.map((t) => ({ description: t.description, type: t.type }));
|
|
95
|
-
const
|
|
96
|
-
|
|
101
|
+
const synthesisCheckpoint = args.synthesisCheckpoint === true;
|
|
102
|
+
const leadDevPlan = synthesisCheckpoint
|
|
103
|
+
? buildSynthesisCheckpointPlan(args.synthesisDueReason ?? null)
|
|
104
|
+
: isLeadDevModeActive() && (primaryDescription || planTaskInputs.length > 0)
|
|
97
105
|
? buildLeadDevPlan(
|
|
98
106
|
primaryDescription,
|
|
99
107
|
taskTypes.length ? taskTypes : ['implement'],
|
|
@@ -102,15 +110,20 @@ export class ComplexityHandler {
|
|
|
102
110
|
)
|
|
103
111
|
: null;
|
|
104
112
|
|
|
113
|
+
let planPersisted = synthesisCheckpoint ? leadDevPlan !== null : !leadDevPlan;
|
|
114
|
+
|
|
105
115
|
if (leadDevPlan) {
|
|
106
116
|
try {
|
|
107
117
|
const sessionId = args.sessionId ?? `analyze-${Date.now()}`;
|
|
108
|
-
|
|
118
|
+
if (!synthesisCheckpoint) {
|
|
119
|
+
clearPendingDelegations();
|
|
120
|
+
}
|
|
109
121
|
const planPath = persistLeadDevPlan(leadDevPlan);
|
|
110
122
|
const bound = bindPlanToSession(sessionId);
|
|
123
|
+
planPersisted = true;
|
|
111
124
|
await frameworkLogger.log(
|
|
112
125
|
'orchestrator.server',
|
|
113
|
-
'lead-dev-plan-persisted',
|
|
126
|
+
synthesisCheckpoint ? 'synthesis-plan-persisted' : 'lead-dev-plan-persisted',
|
|
114
127
|
'info',
|
|
115
128
|
{
|
|
116
129
|
planPath,
|
|
@@ -118,19 +131,24 @@ export class ComplexityHandler {
|
|
|
118
131
|
planGeneration: bound?.planGeneration,
|
|
119
132
|
phaseCount: leadDevPlan.phases.length,
|
|
120
133
|
todoCount: leadDevPlan.phases.reduce((n, p) => n + p.todos.length, 0),
|
|
134
|
+
synthesisCheckpoint,
|
|
121
135
|
},
|
|
122
136
|
);
|
|
123
137
|
} catch (err) {
|
|
138
|
+
planPersisted = false;
|
|
124
139
|
await frameworkLogger.log(
|
|
125
140
|
'orchestrator.server',
|
|
126
|
-
'lead-dev-plan-persist-failed',
|
|
141
|
+
synthesisCheckpoint ? 'synthesis-plan-persist-failed' : 'lead-dev-plan-persist-failed',
|
|
127
142
|
'warning',
|
|
128
143
|
{ error: err instanceof Error ? err.message : String(err) },
|
|
129
144
|
);
|
|
130
145
|
}
|
|
131
146
|
}
|
|
132
147
|
|
|
148
|
+
const ok = planPersisted;
|
|
149
|
+
|
|
133
150
|
return {
|
|
151
|
+
ok,
|
|
134
152
|
content: [
|
|
135
153
|
{
|
|
136
154
|
type: 'text',
|
|
@@ -139,12 +157,14 @@ export class ComplexityHandler {
|
|
|
139
157
|
recommendations,
|
|
140
158
|
tasks.length,
|
|
141
159
|
leadDevPlan,
|
|
160
|
+
synthesisCheckpoint,
|
|
142
161
|
),
|
|
143
162
|
},
|
|
144
163
|
],
|
|
145
164
|
};
|
|
146
165
|
} catch (error) {
|
|
147
166
|
return {
|
|
167
|
+
ok: false,
|
|
148
168
|
content: [
|
|
149
169
|
{
|
|
150
170
|
type: 'text',
|
|
@@ -195,6 +215,7 @@ export class ComplexityHandler {
|
|
|
195
215
|
recommendations: string[],
|
|
196
216
|
taskCount: number,
|
|
197
217
|
leadDevPlan: ReturnType<typeof buildLeadDevPlan> = null,
|
|
218
|
+
synthesisCheckpoint = false,
|
|
198
219
|
): string {
|
|
199
220
|
const leadDevSection = leadDevPlan
|
|
200
221
|
? `
|
|
@@ -216,7 +237,11 @@ ${JSON.stringify(leadDevPlan, null, 2)}
|
|
|
216
237
|
\`\`\``
|
|
217
238
|
: '';
|
|
218
239
|
|
|
219
|
-
|
|
240
|
+
const header = synthesisCheckpoint
|
|
241
|
+
? '🔄 Synthesis Checkpoint — Reflect & Realign'
|
|
242
|
+
: '🔍 Complexity Analysis Results';
|
|
243
|
+
|
|
244
|
+
return `${header}
|
|
220
245
|
|
|
221
246
|
**Tasks Analyzed:** ${taskCount}
|
|
222
247
|
**Overall Complexity:** ${analysis.overallComplexity}/100
|
|
@@ -140,10 +140,15 @@ export class OrchestratorServer {
|
|
|
140
140
|
{
|
|
141
141
|
name: 'analyze-complexity',
|
|
142
142
|
description:
|
|
143
|
-
'Analyze task complexity and recommend orchestration strategy. When lead_dev_mode is on (features.json), includes phased plan + todos + subagent routes.',
|
|
143
|
+
'Analyze task complexity and recommend orchestration strategy. When lead_dev_mode is on (features.json), includes phased plan + todos + subagent routes. During synthesis checkpoint, returns collocated context and mandatory-consult realignment plan — pass sessionId from the active session.',
|
|
144
144
|
inputSchema: {
|
|
145
145
|
type: 'object',
|
|
146
146
|
properties: {
|
|
147
|
+
sessionId: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
description:
|
|
150
|
+
'Active session id (required to clear synthesis checkpoint; inferred from checkpoint state when omitted)',
|
|
151
|
+
},
|
|
147
152
|
tasks: {
|
|
148
153
|
type: 'array',
|
|
149
154
|
items: {
|
|
@@ -276,12 +281,140 @@ export class OrchestratorServer {
|
|
|
276
281
|
}
|
|
277
282
|
}
|
|
278
283
|
case 'analyze-complexity': {
|
|
279
|
-
const complexityArgs = args as {
|
|
284
|
+
const complexityArgs = args as {
|
|
285
|
+
tasks: OrchestrationTask[];
|
|
286
|
+
sessionId?: string;
|
|
287
|
+
};
|
|
288
|
+
const projectRoot = process.cwd();
|
|
289
|
+
const {
|
|
290
|
+
isSynthesisCheckpointDue,
|
|
291
|
+
getSynthesisDueReason,
|
|
292
|
+
getSynthesisCheckpointSessionId,
|
|
293
|
+
} = await import('../../nucleus/synthesis.js');
|
|
294
|
+
const { appendSynthesisContextToResponse, prepareSynthesisCollocatedContext } =
|
|
295
|
+
await import('../../nucleus/synthesis-context.js');
|
|
296
|
+
const {
|
|
297
|
+
loadPersistedLeadDevPlan,
|
|
298
|
+
isSynthesisRealignmentPlan,
|
|
299
|
+
areSynthesisConsultTodosComplete,
|
|
300
|
+
getSynthesisConsultTodos,
|
|
301
|
+
getNextRequiredTodo,
|
|
302
|
+
} = await import('../../nucleus/lead-dev-plan-persistence.js');
|
|
303
|
+
|
|
304
|
+
const checkpointSession = getSynthesisCheckpointSessionId(projectRoot);
|
|
305
|
+
if (
|
|
306
|
+
checkpointSession &&
|
|
307
|
+
complexityArgs.sessionId &&
|
|
308
|
+
complexityArgs.sessionId !== checkpointSession
|
|
309
|
+
) {
|
|
310
|
+
return {
|
|
311
|
+
content: [
|
|
312
|
+
{
|
|
313
|
+
type: 'text' as const,
|
|
314
|
+
text:
|
|
315
|
+
`❌ Synthesis sessionId mismatch — expected \`${checkpointSession}\` ` +
|
|
316
|
+
`(from synthesis-checkpoint.json), got \`${complexityArgs.sessionId}\`.`,
|
|
317
|
+
},
|
|
318
|
+
],
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const sessionId = checkpointSession ?? complexityArgs.sessionId ?? null;
|
|
323
|
+
const synthesisDue = checkpointSession
|
|
324
|
+
? isSynthesisCheckpointDue(projectRoot, checkpointSession)
|
|
325
|
+
: false;
|
|
326
|
+
const dueReason = synthesisDue
|
|
327
|
+
? getSynthesisDueReason(projectRoot, sessionId)
|
|
328
|
+
: null;
|
|
329
|
+
|
|
330
|
+
if (synthesisDue && !sessionId) {
|
|
331
|
+
return {
|
|
332
|
+
content: [
|
|
333
|
+
{
|
|
334
|
+
type: 'text' as const,
|
|
335
|
+
text:
|
|
336
|
+
'❌ Synthesis checkpoint due but sessionId could not be resolved. ' +
|
|
337
|
+
'Pass sessionId matching .xray/state/synthesis-checkpoint.json.',
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const existingPlan = loadPersistedLeadDevPlan(projectRoot);
|
|
344
|
+
const realignmentInProgress =
|
|
345
|
+
synthesisDue &&
|
|
346
|
+
existingPlan &&
|
|
347
|
+
isSynthesisRealignmentPlan(existingPlan) &&
|
|
348
|
+
!areSynthesisConsultTodosComplete(existingPlan);
|
|
349
|
+
|
|
350
|
+
if (realignmentInProgress) {
|
|
351
|
+
const collocated = await prepareSynthesisCollocatedContext(projectRoot, dueReason);
|
|
352
|
+
const nextTodo = getNextRequiredTodo(existingPlan);
|
|
353
|
+
const consultTodos = getSynthesisConsultTodos(existingPlan);
|
|
354
|
+
const todoList = consultTodos
|
|
355
|
+
.map(
|
|
356
|
+
(t) =>
|
|
357
|
+
`- [${t.status === 'completed' ? 'x' : ' '}] ${t.id} (${t.subagent}): ${t.task}`,
|
|
358
|
+
)
|
|
359
|
+
.join('\n');
|
|
360
|
+
let text =
|
|
361
|
+
'🔄 Synthesis realignment in progress — consult todos preserved (analyze-complexity no-op).\n\n' +
|
|
362
|
+
`**Next required todo:** ${nextTodo?.id ?? 'none'} (${nextTodo?.subagent ?? ''})\n\n` +
|
|
363
|
+
`${todoList}\n\n` +
|
|
364
|
+
'Complete mandatory consult todos via Task spawns before other gated work.';
|
|
365
|
+
if (collocated.collatedText) {
|
|
366
|
+
text = appendSynthesisContextToResponse(
|
|
367
|
+
[{ type: 'text', text }],
|
|
368
|
+
collocated.collatedText,
|
|
369
|
+
)[0]!.text;
|
|
370
|
+
}
|
|
371
|
+
return { content: [{ type: 'text' as const, text }] };
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const collocated = synthesisDue
|
|
375
|
+
? await prepareSynthesisCollocatedContext(projectRoot, dueReason)
|
|
376
|
+
: null;
|
|
377
|
+
const inheritedContext = synthesisDue && collocated
|
|
378
|
+
? { synthesis: true, ...collocated }
|
|
379
|
+
: { taskCount: complexityArgs.tasks.length };
|
|
380
|
+
|
|
280
381
|
const aside = await spawnAside({
|
|
281
|
-
description:
|
|
382
|
+
description: synthesisDue
|
|
383
|
+
? 'Synthesis checkpoint: reflect & realign'
|
|
384
|
+
: `Complexity analysis: ${complexityArgs.tasks.length} tasks`,
|
|
385
|
+
...(sessionId ? { sessionId } : {}),
|
|
386
|
+
inheritedContext,
|
|
282
387
|
});
|
|
283
388
|
try {
|
|
284
|
-
|
|
389
|
+
const result = await this.complexityHandler.handleAnalyzeComplexity(
|
|
390
|
+
{
|
|
391
|
+
...complexityArgs,
|
|
392
|
+
...(sessionId ? { sessionId } : {}),
|
|
393
|
+
...(synthesisDue
|
|
394
|
+
? { synthesisCheckpoint: true, synthesisDueReason: dueReason }
|
|
395
|
+
: {}),
|
|
396
|
+
},
|
|
397
|
+
aside.asideId,
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
let content = result.content;
|
|
401
|
+
if (synthesisDue && collocated?.collatedText) {
|
|
402
|
+
content = appendSynthesisContextToResponse(content, collocated.collatedText);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (synthesisDue && result.ok) {
|
|
406
|
+
content = content.map((block, index) =>
|
|
407
|
+
index === 0
|
|
408
|
+
? {
|
|
409
|
+
...block,
|
|
410
|
+
text:
|
|
411
|
+
`${block.text}\n\n**Synthesis checkpoint remains active** until mandatory consult todos (s.1–s.3) are completed via Task spawns.`,
|
|
412
|
+
}
|
|
413
|
+
: block,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return { content };
|
|
285
418
|
} finally {
|
|
286
419
|
closeAside(aside.asideId);
|
|
287
420
|
}
|
|
@@ -356,13 +489,51 @@ export class OrchestratorServer {
|
|
|
356
489
|
skipApply?: boolean;
|
|
357
490
|
}): Promise<{ content: Array<{ type: 'text'; text: string }> }> {
|
|
358
491
|
try {
|
|
492
|
+
const projectRoot = process.cwd();
|
|
493
|
+
const {
|
|
494
|
+
isSynthesisCheckpointDue,
|
|
495
|
+
getSynthesisDueReason,
|
|
496
|
+
getSynthesisCheckpointSessionId,
|
|
497
|
+
recordExecutionSlice,
|
|
498
|
+
} = await import('../../nucleus/synthesis.js');
|
|
499
|
+
const {
|
|
500
|
+
loadPersistedLeadDevPlan,
|
|
501
|
+
isSynthesisRealignmentPlan,
|
|
502
|
+
areSynthesisConsultTodosComplete,
|
|
503
|
+
} = await import('../../nucleus/lead-dev-plan-persistence.js');
|
|
504
|
+
|
|
505
|
+
const checkpointSession = getSynthesisCheckpointSessionId(projectRoot);
|
|
506
|
+
const sessionId = checkpointSession ?? null;
|
|
507
|
+
if (sessionId && isSynthesisCheckpointDue(projectRoot, sessionId)) {
|
|
508
|
+
const dueReason = getSynthesisDueReason(projectRoot, sessionId);
|
|
509
|
+
const plan = loadPersistedLeadDevPlan(projectRoot);
|
|
510
|
+
const realignmentPending =
|
|
511
|
+
plan && isSynthesisRealignmentPlan(plan) && !areSynthesisConsultTodosComplete(plan);
|
|
512
|
+
return {
|
|
513
|
+
content: [{
|
|
514
|
+
type: 'text' as const,
|
|
515
|
+
text: JSON.stringify({
|
|
516
|
+
blocked: true,
|
|
517
|
+
gate: 'synthesis-checkpoint',
|
|
518
|
+
dueReason,
|
|
519
|
+
primitive: 'synthesis',
|
|
520
|
+
realignmentPending,
|
|
521
|
+
hint: realignmentPending
|
|
522
|
+
? 'Complete mandatory consult todos (s.1–s.3) before govern-and-apply'
|
|
523
|
+
: 'Run analyze-complexity to reflect and realign before govern-and-apply',
|
|
524
|
+
}, null, 2),
|
|
525
|
+
}],
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
359
529
|
const { InferenceCycle } = await import('../../inference/inference-cycle.js');
|
|
360
|
-
const cycle = InferenceCycle.getInstance(
|
|
530
|
+
const cycle = InferenceCycle.getInstance(projectRoot, {
|
|
361
531
|
skipApply: args.skipApply ?? false,
|
|
362
532
|
});
|
|
363
533
|
|
|
364
534
|
const aside = await spawnAside({
|
|
365
535
|
description: `Governance cycle: ${args.proposals.length} proposals`,
|
|
536
|
+
...(sessionId ? { sessionId } : {}),
|
|
366
537
|
priorVerdictContext: { proposalCount: args.proposals.length },
|
|
367
538
|
});
|
|
368
539
|
|
|
@@ -377,12 +548,17 @@ export class OrchestratorServer {
|
|
|
377
548
|
const approved = result!.votes.filter((v) => v.decision === 'approve').length;
|
|
378
549
|
const rejected = result!.votes.length - approved;
|
|
379
550
|
|
|
551
|
+
if (sessionId) {
|
|
552
|
+
recordExecutionSlice('gate', { projectRoot, sessionId });
|
|
553
|
+
}
|
|
554
|
+
|
|
380
555
|
return {
|
|
381
556
|
content: [{
|
|
382
557
|
type: 'text' as const,
|
|
383
558
|
text: JSON.stringify({
|
|
384
559
|
cycleId: result!.cycleId,
|
|
385
560
|
asideId: aside.asideId,
|
|
561
|
+
synthesisBridged: Boolean(sessionId),
|
|
386
562
|
approved,
|
|
387
563
|
rejected,
|
|
388
564
|
votes: result!.votes,
|
package/xray/features.json
CHANGED
|
@@ -141,6 +141,12 @@
|
|
|
141
141
|
"module_path": "",
|
|
142
142
|
"config": {}
|
|
143
143
|
},
|
|
144
|
+
"synthesis": {
|
|
145
|
+
"enabled": false,
|
|
146
|
+
"every_n_gates": 12,
|
|
147
|
+
"every_n_turns": 0,
|
|
148
|
+
"every_n_todos_completed": 0
|
|
149
|
+
},
|
|
144
150
|
"inference_governance": {
|
|
145
151
|
"enabled": false,
|
|
146
152
|
"request_timeout_ms": 10000,
|
|
@@ -27,6 +27,23 @@
|
|
|
27
27
|
"then": {
|
|
28
28
|
"required": ["module_path"]
|
|
29
29
|
}
|
|
30
|
+
},
|
|
31
|
+
"synthesis": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"properties": {
|
|
34
|
+
"enabled": { "type": "boolean" },
|
|
35
|
+
"every_n_gates": { "type": "integer", "minimum": 0 },
|
|
36
|
+
"every_n_turns": { "type": "integer", "minimum": 0 },
|
|
37
|
+
"every_n_todos_completed": { "type": "integer", "minimum": 0 },
|
|
38
|
+
"reflection": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"properties": {
|
|
41
|
+
"mode": { "type": "string", "enum": ["full", "minimal", "off"] },
|
|
42
|
+
"triggers": { "type": "object" },
|
|
43
|
+
"thresholds": { "type": "object" }
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
30
47
|
}
|
|
31
48
|
},
|
|
32
49
|
"additionalProperties": true
|