oxe-cc 1.7.0 → 1.8.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/CHANGELOG.md +106 -0
- package/README.md +37 -37
- package/bin/lib/oxe-agent-install.cjs +24 -8
- package/bin/lib/oxe-manifest.cjs +20 -13
- package/bin/lib/oxe-operational.cjs +234 -41
- package/bin/lib/oxe-project-health.cjs +219 -52
- package/bin/lib/oxe-rationality.cjs +9 -7
- package/bin/oxe-cc.js +443 -236
- package/lib/runtime/compiler/graph-compiler.js +1 -1
- package/lib/runtime/executor/action-tool-map.js +4 -0
- package/lib/runtime/executor/built-in-tools.js +27 -0
- package/lib/runtime/executor/llm-task-executor.d.ts +4 -1
- package/lib/runtime/executor/llm-task-executor.js +41 -5
- package/lib/runtime/executor/node-prompt-builder.d.ts +4 -1
- package/lib/runtime/executor/node-prompt-builder.js +13 -2
- package/lib/runtime/models/failure.d.ts +1 -1
- package/lib/runtime/scheduler/scheduler.d.ts +5 -1
- package/lib/runtime/scheduler/scheduler.js +82 -14
- package/lib/runtime/verification/verification-compiler.js +7 -5
- package/lib/sdk/index.cjs +48 -44
- package/oxe/templates/PLAN.template.md +23 -9
- package/oxe/templates/SPEC.template.md +55 -22
- package/oxe/workflows/plan.md +18 -6
- package/oxe/workflows/spec.md +31 -9
- package/package.json +103 -100
- package/packages/runtime/package.json +14 -14
- package/packages/runtime/src/compiler/graph-compiler.ts +1 -1
- package/packages/runtime/src/evidence/evidence-store.ts +2 -2
- package/packages/runtime/src/executor/action-tool-map.ts +4 -0
- package/packages/runtime/src/executor/built-in-tools.ts +29 -0
- package/packages/runtime/src/executor/llm-task-executor.ts +46 -4
- package/packages/runtime/src/executor/node-prompt-builder.ts +18 -1
- package/packages/runtime/src/models/failure.ts +2 -0
- package/packages/runtime/src/scheduler/scheduler.ts +93 -15
- package/packages/runtime/src/verification/verification-compiler.ts +7 -5
- package/vscode-extension/package.json +184 -184
- package/vscode-extension/oxe-agents-0.9.1.vsix +0 -0
- package/vscode-extension/oxe-agents-0.9.2.vsix +0 -0
- package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
- package/vscode-extension/oxe-agents-1.4.0.vsix +0 -0
- package/vscode-extension/oxe-agents-1.5.0.vsix +0 -0
- package/vscode-extension/oxe-agents-1.5.1.vsix +0 -0
- package/vscode-extension/oxe-agents-1.6.0.vsix +0 -0
- package/vscode-extension/oxe-agents-1.7.0.vsix +0 -0
|
@@ -26,7 +26,7 @@ function compile(plan, spec, options = {}) {
|
|
|
26
26
|
mutation_scope: task.files,
|
|
27
27
|
actions: buildActions(task),
|
|
28
28
|
verify: {
|
|
29
|
-
must_pass: task.verifyCommand ? ['tests'] : [],
|
|
29
|
+
must_pass: task.verifyCommand ? (task.aceite.length > 0 ? task.aceite : ['tests']) : [],
|
|
30
30
|
acceptance_refs: task.aceite,
|
|
31
31
|
command: task.verifyCommand,
|
|
32
32
|
},
|
|
@@ -37,5 +37,9 @@ function selectToolsForActions(actions) {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
// finish_task is always available so the LLM can signal authoritative completion
|
|
41
|
+
if (!seen.has('finish_task') && built_in_tools_1.BUILT_IN_TOOLS.finish_task) {
|
|
42
|
+
result.push(built_in_tools_1.BUILT_IN_TOOLS.finish_task.schema);
|
|
43
|
+
}
|
|
40
44
|
return result;
|
|
41
45
|
}
|
|
@@ -255,6 +255,32 @@ function runShell(command, cwd, timeoutMs) {
|
|
|
255
255
|
proc.on('error', (err) => { clearTimeout(timer); resolve(`[error] ${err}`); });
|
|
256
256
|
});
|
|
257
257
|
}
|
|
258
|
+
// ─── finish_task ──────────────────────────────────────────────────────────────
|
|
259
|
+
const finishTask = {
|
|
260
|
+
idempotent: true,
|
|
261
|
+
schema: {
|
|
262
|
+
type: 'function',
|
|
263
|
+
function: {
|
|
264
|
+
name: 'finish_task',
|
|
265
|
+
description: 'Signal that the task is complete. Call this when ALL required actions have been performed.',
|
|
266
|
+
parameters: {
|
|
267
|
+
type: 'object',
|
|
268
|
+
properties: {
|
|
269
|
+
summary: { type: 'string', description: 'Summary of what was accomplished' },
|
|
270
|
+
evidence_paths: { type: 'array', items: { type: 'string' }, description: 'Paths to files created or modified' },
|
|
271
|
+
},
|
|
272
|
+
required: ['summary'],
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
},
|
|
276
|
+
async execute(args, _cwd) {
|
|
277
|
+
return JSON.stringify({
|
|
278
|
+
__finish_task__: true,
|
|
279
|
+
summary: String(args.summary || ''),
|
|
280
|
+
evidence_paths: Array.isArray(args.evidence_paths) ? args.evidence_paths : [],
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
};
|
|
258
284
|
// ─── Registry ─────────────────────────────────────────────────────────────────
|
|
259
285
|
exports.BUILT_IN_TOOLS = {
|
|
260
286
|
read_file: readFile,
|
|
@@ -263,5 +289,6 @@ exports.BUILT_IN_TOOLS = {
|
|
|
263
289
|
glob,
|
|
264
290
|
grep,
|
|
265
291
|
run_command: runCommand,
|
|
292
|
+
finish_task: finishTask,
|
|
266
293
|
};
|
|
267
294
|
exports.ALL_BUILT_IN_SCHEMAS = Object.values(exports.BUILT_IN_TOOLS).map((t) => t.schema);
|
|
@@ -18,12 +18,15 @@ export interface LlmExecutorEvent {
|
|
|
18
18
|
attempt: number;
|
|
19
19
|
detail?: Record<string, unknown>;
|
|
20
20
|
}
|
|
21
|
+
export interface LlmExecuteOptions {
|
|
22
|
+
previousError?: string | null;
|
|
23
|
+
}
|
|
21
24
|
export declare class LlmTaskExecutor implements TaskExecutor {
|
|
22
25
|
private readonly provider;
|
|
23
26
|
private readonly registry?;
|
|
24
27
|
private readonly onProgress?;
|
|
25
28
|
constructor(provider: LlmProviderConfig, registry?: PluginRegistry | undefined, onProgress?: ((event: LlmExecutorEvent) => void) | undefined);
|
|
26
|
-
execute(node: GraphNode, lease: WorkspaceLease, runId: string, attempt: number): Promise<TaskResult>;
|
|
29
|
+
execute(node: GraphNode, lease: WorkspaceLease, runId: string, attempt: number, options?: LlmExecuteOptions): Promise<TaskResult>;
|
|
27
30
|
private invokeToolCall;
|
|
28
31
|
private emit;
|
|
29
32
|
}
|
|
@@ -6,15 +6,15 @@ const built_in_tools_1 = require("./built-in-tools");
|
|
|
6
6
|
const action_tool_map_1 = require("./action-tool-map");
|
|
7
7
|
const node_prompt_builder_1 = require("./node-prompt-builder");
|
|
8
8
|
const DEFAULT_SYSTEM_PROMPT = 'You are a precise software engineering agent. Use the tools provided to complete the task. ' +
|
|
9
|
-
'When
|
|
9
|
+
'When all actions are done, call finish_task with a summary of what was accomplished.';
|
|
10
10
|
class LlmTaskExecutor {
|
|
11
11
|
constructor(provider, registry, onProgress) {
|
|
12
12
|
this.provider = provider;
|
|
13
13
|
this.registry = registry;
|
|
14
14
|
this.onProgress = onProgress;
|
|
15
15
|
}
|
|
16
|
-
async execute(node, lease, runId, attempt) {
|
|
17
|
-
const prompt = (0, node_prompt_builder_1.buildNodePrompt)(node, lease, runId, attempt);
|
|
16
|
+
async execute(node, lease, runId, attempt, options = {}) {
|
|
17
|
+
const prompt = (0, node_prompt_builder_1.buildNodePrompt)(node, lease, runId, attempt, { previousError: options.previousError ?? null });
|
|
18
18
|
const tools = (0, action_tool_map_1.selectToolsForActions)(node.actions);
|
|
19
19
|
const cwd = lease.root_path;
|
|
20
20
|
const maxTurns = this.provider.maxTurns ?? 10;
|
|
@@ -25,7 +25,10 @@ class LlmTaskExecutor {
|
|
|
25
25
|
];
|
|
26
26
|
let finalOutput = '';
|
|
27
27
|
const evidencePaths = [];
|
|
28
|
-
|
|
28
|
+
let completedByFinishTask = false;
|
|
29
|
+
let finishTaskSummary = '';
|
|
30
|
+
let turn = 0;
|
|
31
|
+
for (; turn < maxTurns; turn++) {
|
|
29
32
|
this.emit({ type: 'turn_start', nodeId: node.id, attempt, detail: { turn } });
|
|
30
33
|
let response;
|
|
31
34
|
try {
|
|
@@ -60,12 +63,45 @@ class LlmTaskExecutor {
|
|
|
60
63
|
serialResults.push(await this.invokeToolCall(tc, cwd, node, evidencePaths));
|
|
61
64
|
}
|
|
62
65
|
messages.push(...concurrentResults, ...serialResults);
|
|
66
|
+
// Detect finish_task call — authoritative completion signal
|
|
67
|
+
const allResults = [...concurrentResults, ...serialResults];
|
|
68
|
+
const finishResult = allResults.find((r) => r.name === 'finish_task');
|
|
69
|
+
if (finishResult) {
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(finishResult.content);
|
|
72
|
+
if (parsed.__finish_task__) {
|
|
73
|
+
completedByFinishTask = true;
|
|
74
|
+
finishTaskSummary = parsed.summary || '';
|
|
75
|
+
if (Array.isArray(parsed.evidence_paths)) {
|
|
76
|
+
evidencePaths.push(...parsed.evidence_paths.filter((p) => typeof p === 'string'));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch { /* ignore parse errors */ }
|
|
81
|
+
if (completedByFinishTask)
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const completedBy = completedByFinishTask
|
|
86
|
+
? 'finish_task'
|
|
87
|
+
: turn < maxTurns
|
|
88
|
+
? 'no_tool_call'
|
|
89
|
+
: 'turn_limit_exhausted';
|
|
90
|
+
if (completedBy === 'turn_limit_exhausted') {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
failure_class: 'llm',
|
|
94
|
+
evidence: evidencePaths,
|
|
95
|
+
output: finalOutput || `Task exhausted ${maxTurns} turns without calling finish_task`,
|
|
96
|
+
completed_by: completedBy,
|
|
97
|
+
};
|
|
63
98
|
}
|
|
64
99
|
return {
|
|
65
100
|
success: true,
|
|
66
101
|
failure_class: null,
|
|
67
102
|
evidence: evidencePaths,
|
|
68
|
-
output: finalOutput,
|
|
103
|
+
output: completedByFinishTask ? (finishTaskSummary || finalOutput) : finalOutput,
|
|
104
|
+
completed_by: completedBy,
|
|
69
105
|
};
|
|
70
106
|
}
|
|
71
107
|
async invokeToolCall(tc, cwd, node, evidencePaths) {
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import type { GraphNode } from '../compiler/graph-compiler';
|
|
2
2
|
import type { WorkspaceLease } from '../models/workspace';
|
|
3
|
-
export
|
|
3
|
+
export interface NodePromptOptions {
|
|
4
|
+
previousError?: string | null;
|
|
5
|
+
}
|
|
6
|
+
export declare function buildNodePrompt(node: GraphNode, lease: WorkspaceLease, runId: string, attempt: number, options?: NodePromptOptions): string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildNodePrompt = buildNodePrompt;
|
|
4
|
-
function buildNodePrompt(node, lease, runId, attempt) {
|
|
4
|
+
function buildNodePrompt(node, lease, runId, attempt, options = {}) {
|
|
5
5
|
const lines = [
|
|
6
6
|
`# Tarefa: ${node.title}`,
|
|
7
7
|
'',
|
|
@@ -11,6 +11,14 @@ function buildNodePrompt(node, lease, runId, attempt) {
|
|
|
11
11
|
if (node.mutation_scope.length > 0) {
|
|
12
12
|
lines.push(`**Escopo de mutação:** ${node.mutation_scope.join(', ')}`);
|
|
13
13
|
}
|
|
14
|
+
if (attempt > 1 && options.previousError) {
|
|
15
|
+
lines.push('', '## Contexto da tentativa anterior');
|
|
16
|
+
lines.push(`Esta é a tentativa **${attempt}**. A tentativa anterior falhou:`);
|
|
17
|
+
lines.push('', '```');
|
|
18
|
+
lines.push(String(options.previousError).slice(0, 2000));
|
|
19
|
+
lines.push('```', '');
|
|
20
|
+
lines.push('Analise o erro e tente uma abordagem diferente.');
|
|
21
|
+
}
|
|
14
22
|
if (node.actions.length > 0) {
|
|
15
23
|
lines.push('', '## Ações requeridas');
|
|
16
24
|
for (const action of node.actions) {
|
|
@@ -31,6 +39,9 @@ function buildNodePrompt(node, lease, runId, attempt) {
|
|
|
31
39
|
if (node.verify.command) {
|
|
32
40
|
lines.push('', `**Verificação:** \`${node.verify.command}\``);
|
|
33
41
|
}
|
|
34
|
-
lines.push('', '
|
|
42
|
+
lines.push('', '## Conclusão da tarefa');
|
|
43
|
+
lines.push('Quando **todas** as ações estiverem concluídas, chame `finish_task` com um resumo do que foi realizado.');
|
|
44
|
+
lines.push('NÃO chame `finish_task` antes de completar todas as ações requeridas.');
|
|
45
|
+
lines.push('', 'Execute as ações acima usando as ferramentas disponíveis.');
|
|
35
46
|
return lines.join('\n');
|
|
36
47
|
}
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* Canonical failure classification used by TaskResult and VerificationManifest.
|
|
3
3
|
* Both must import from this file — never redefine inline.
|
|
4
4
|
*/
|
|
5
|
-
export type FailureClass = 'env' | 'policy' | 'test' | 'timeout' | 'evidence_missing' | null;
|
|
5
|
+
export type FailureClass = 'env' | 'policy' | 'test' | 'timeout' | 'evidence_missing' | 'verify' | 'llm' | null;
|
|
@@ -14,9 +14,12 @@ export interface TaskResult {
|
|
|
14
14
|
failure_class: FailureClass;
|
|
15
15
|
evidence: string[];
|
|
16
16
|
output: string;
|
|
17
|
+
completed_by?: string;
|
|
17
18
|
}
|
|
18
19
|
export interface TaskExecutor {
|
|
19
|
-
execute(node: GraphNode, lease: WorkspaceLease, runId: string, attemptNumber: number
|
|
20
|
+
execute(node: GraphNode, lease: WorkspaceLease, runId: string, attemptNumber: number, options?: {
|
|
21
|
+
previousError?: string | null;
|
|
22
|
+
}): Promise<TaskResult>;
|
|
20
23
|
}
|
|
21
24
|
export interface SchedulerOptions {
|
|
22
25
|
maxRunDurationMs?: number;
|
|
@@ -70,6 +73,7 @@ export declare class Scheduler {
|
|
|
70
73
|
getJournal(): RunJournal | null;
|
|
71
74
|
static loadJournal(projectRoot: string, runId: string): RunJournal | null;
|
|
72
75
|
private executeNode;
|
|
76
|
+
private verifyNode;
|
|
73
77
|
private evaluatePolicyForNode;
|
|
74
78
|
private requestGateForNode;
|
|
75
79
|
private blockNode;
|
|
@@ -12,6 +12,7 @@ const audit_trail_1 = require("../audit/audit-trail");
|
|
|
12
12
|
const run_journal_1 = require("./run-journal");
|
|
13
13
|
const decision_memo_1 = require("../decision/decision-memo");
|
|
14
14
|
const capability_adapter_1 = require("../plugins/capability-adapter");
|
|
15
|
+
const verification_compiler_1 = require("../verification/verification-compiler");
|
|
15
16
|
class Scheduler {
|
|
16
17
|
constructor() {
|
|
17
18
|
this.cancelled = false;
|
|
@@ -350,6 +351,7 @@ class Scheduler {
|
|
|
350
351
|
});
|
|
351
352
|
let lease = null;
|
|
352
353
|
let lastResult = null;
|
|
354
|
+
let lastError = null;
|
|
353
355
|
const maxAttempts = node.policy.max_retries + 1;
|
|
354
356
|
const quotaBlocked = this.consumeQuotaForNode(ctx, node);
|
|
355
357
|
if (quotaBlocked) {
|
|
@@ -408,19 +410,31 @@ class Scheduler {
|
|
|
408
410
|
attempt_id: attemptId,
|
|
409
411
|
payload: { workspace_id: lease.workspace_id, strategy: lease.strategy },
|
|
410
412
|
});
|
|
411
|
-
lastResult = await this.executeNode(node, lease, ctx, attempt, attemptId);
|
|
413
|
+
lastResult = await this.executeNode(node, lease, ctx, attempt, attemptId, { previousError: lastError });
|
|
412
414
|
if (lastResult.success) {
|
|
413
|
-
this.
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
415
|
+
const verifyResult = await this.verifyNode(node, lease, ctx, attemptId, attempt);
|
|
416
|
+
if (verifyResult && verifyResult.status === 'failed') {
|
|
417
|
+
lastResult = {
|
|
418
|
+
success: false,
|
|
419
|
+
failure_class: 'verify',
|
|
420
|
+
evidence: lastResult.evidence,
|
|
421
|
+
output: `Verification failed: ${(verifyResult.gaps || []).join('; ') || 'checks did not pass'}`,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
this.emit(ctx, {
|
|
426
|
+
type: 'WorkItemCompleted',
|
|
427
|
+
work_item_id: nodeId,
|
|
428
|
+
attempt_id: attemptId,
|
|
429
|
+
payload: { attempt_number: attempt, evidence: lastResult.evidence },
|
|
430
|
+
});
|
|
431
|
+
status.set(nodeId, 'completed');
|
|
432
|
+
completed.push(nodeId);
|
|
433
|
+
this.recordProgress();
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
423
436
|
}
|
|
437
|
+
lastError = lastResult.output || (lastResult.failure_class ?? 'unknown error');
|
|
424
438
|
if (lastResult.failure_class === 'policy')
|
|
425
439
|
break;
|
|
426
440
|
if (attempt < maxAttempts) {
|
|
@@ -454,6 +468,7 @@ class Scheduler {
|
|
|
454
468
|
evidence: [],
|
|
455
469
|
output: `[error_boundary] ${message}`,
|
|
456
470
|
};
|
|
471
|
+
lastError = lastResult.output;
|
|
457
472
|
if (attempt < maxAttempts) {
|
|
458
473
|
const backoffMs = Math.min(1000 * Math.pow(2, attempt - 1) + Math.random() * 500, 30000);
|
|
459
474
|
await new Promise(resolve => setTimeout(resolve, backoffMs));
|
|
@@ -509,11 +524,11 @@ class Scheduler {
|
|
|
509
524
|
static loadJournal(projectRoot, runId) {
|
|
510
525
|
return (0, run_journal_1.loadJournal)(projectRoot, runId);
|
|
511
526
|
}
|
|
512
|
-
async executeNode(node, lease, ctx, attempt, attemptId) {
|
|
527
|
+
async executeNode(node, lease, ctx, attempt, attemptId, options = {}) {
|
|
513
528
|
const primaryAction = pickPrimaryAction(node, ctx.pluginRegistry);
|
|
514
529
|
const provider = primaryAction ? ctx.pluginRegistry?.toolProviderFor(primaryAction.type) : null;
|
|
515
530
|
if (!provider || !primaryAction) {
|
|
516
|
-
return ctx.executor.execute(node, lease, ctx.runId, attempt);
|
|
531
|
+
return ctx.executor.execute(node, lease, ctx.runId, attempt, options);
|
|
517
532
|
}
|
|
518
533
|
ctx.auditTrail?.record('plugin_invoked', ctx.policyActor ?? 'runtime', {
|
|
519
534
|
runId: ctx.runId,
|
|
@@ -573,6 +588,57 @@ class Scheduler {
|
|
|
573
588
|
output: result.output,
|
|
574
589
|
};
|
|
575
590
|
}
|
|
591
|
+
async verifyNode(node, lease, ctx, attemptId, attempt) {
|
|
592
|
+
if (!node.verify?.command)
|
|
593
|
+
return null;
|
|
594
|
+
this.emit(ctx, {
|
|
595
|
+
type: 'VerificationStarted',
|
|
596
|
+
work_item_id: node.id,
|
|
597
|
+
payload: { command: node.verify.command, attempt_number: attempt },
|
|
598
|
+
});
|
|
599
|
+
const suite = {
|
|
600
|
+
checks: [{
|
|
601
|
+
id: `inline-${node.id}`,
|
|
602
|
+
type: 'custom',
|
|
603
|
+
command: node.verify.command,
|
|
604
|
+
evidence_type_expected: 'stdout',
|
|
605
|
+
acceptance_ref: null,
|
|
606
|
+
description: `Verify ${node.id}`,
|
|
607
|
+
}],
|
|
608
|
+
compiled_at: new Date().toISOString(),
|
|
609
|
+
spec_hash: '',
|
|
610
|
+
plan_hash: '',
|
|
611
|
+
};
|
|
612
|
+
let result;
|
|
613
|
+
try {
|
|
614
|
+
result = await (0, verification_compiler_1.verifyRun)({
|
|
615
|
+
suite,
|
|
616
|
+
cwd: lease.root_path,
|
|
617
|
+
timeoutMs: ctx.options?.verifyTimeoutMs ?? 60000,
|
|
618
|
+
runId: ctx.runId,
|
|
619
|
+
workItemId: node.id,
|
|
620
|
+
attemptNumber: attempt,
|
|
621
|
+
projectRoot: ctx.projectRoot,
|
|
622
|
+
pluginRegistry: ctx.pluginRegistry,
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
catch (err) {
|
|
626
|
+
this.emit(ctx, {
|
|
627
|
+
type: 'VerificationCompleted',
|
|
628
|
+
work_item_id: node.id,
|
|
629
|
+
attempt_id: attemptId,
|
|
630
|
+
payload: { status: 'error', error: String(err) },
|
|
631
|
+
});
|
|
632
|
+
return null;
|
|
633
|
+
}
|
|
634
|
+
this.emit(ctx, {
|
|
635
|
+
type: 'VerificationCompleted',
|
|
636
|
+
work_item_id: node.id,
|
|
637
|
+
attempt_id: attemptId,
|
|
638
|
+
payload: { status: result.status },
|
|
639
|
+
});
|
|
640
|
+
return result;
|
|
641
|
+
}
|
|
576
642
|
evaluatePolicyForNode(node, ctx) {
|
|
577
643
|
if (!ctx.policyEngine)
|
|
578
644
|
return null;
|
|
@@ -603,8 +669,10 @@ class Scheduler {
|
|
|
603
669
|
return persisted;
|
|
604
670
|
}
|
|
605
671
|
async requestGateForNode(node, ctx, decision) {
|
|
606
|
-
if (!ctx.gateManager)
|
|
672
|
+
if (!ctx.gateManager) {
|
|
673
|
+
console.warn('[scheduler] ctx.gateManager not configured — gates will not be persisted');
|
|
607
674
|
return 'gate-missing-manager';
|
|
675
|
+
}
|
|
608
676
|
const scope = inferGateScope(node);
|
|
609
677
|
const primaryAction = pickPrimaryAction(node, ctx.pluginRegistry);
|
|
610
678
|
const gate = await ctx.gateManager.request(scope, {
|
|
@@ -92,15 +92,17 @@ async function runCheck(check, cwd, timeoutMs = 60000) {
|
|
|
92
92
|
}
|
|
93
93
|
const start = Date.now();
|
|
94
94
|
try {
|
|
95
|
-
//
|
|
96
|
-
const
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
const result = (0, child_process_1.spawnSync)(
|
|
95
|
+
// Use shell so the full command string is interpreted (handles quotes, &&, node -e "...")
|
|
96
|
+
const isWin = process.platform === 'win32';
|
|
97
|
+
const shell = isWin ? 'cmd' : 'sh';
|
|
98
|
+
const shellArgs = isWin ? ['/c', check.command] : ['-c', check.command];
|
|
99
|
+
const result = (0, child_process_1.spawnSync)(shell, shellArgs, {
|
|
100
100
|
cwd,
|
|
101
101
|
encoding: 'utf8',
|
|
102
102
|
timeout: timeoutMs,
|
|
103
103
|
maxBuffer: 2 * 1024 * 1024,
|
|
104
|
+
// On Windows, prevent Node from re-quoting the args (preserves double-quotes inside node -e "...")
|
|
105
|
+
windowsVerbatimArguments: isWin,
|
|
104
106
|
});
|
|
105
107
|
const duration_ms = Date.now() - start;
|
|
106
108
|
const status = result.status === 0 ? 'pass' : 'fail';
|
package/lib/sdk/index.cjs
CHANGED
|
@@ -17,10 +17,10 @@ const plugins = require('../../bin/lib/oxe-plugins.cjs');
|
|
|
17
17
|
const dashboard = require('../../bin/lib/oxe-dashboard.cjs');
|
|
18
18
|
const operational = require('../../bin/lib/oxe-operational.cjs');
|
|
19
19
|
const azure = require('../../bin/lib/oxe-azure.cjs');
|
|
20
|
-
const context = require('../../bin/lib/oxe-context-engine.cjs');
|
|
21
|
-
const runtimeSemantics = require('../../bin/lib/oxe-runtime-semantics.cjs');
|
|
22
|
-
const release = require('../../bin/lib/oxe-release.cjs');
|
|
23
|
-
const rationality = require('../../bin/lib/oxe-rationality.cjs');
|
|
20
|
+
const context = require('../../bin/lib/oxe-context-engine.cjs');
|
|
21
|
+
const runtimeSemantics = require('../../bin/lib/oxe-runtime-semantics.cjs');
|
|
22
|
+
const release = require('../../bin/lib/oxe-release.cjs');
|
|
23
|
+
const rationality = require('../../bin/lib/oxe-rationality.cjs');
|
|
24
24
|
|
|
25
25
|
const PACKAGE_ROOT = path.join(__dirname, '..', '..');
|
|
26
26
|
|
|
@@ -94,8 +94,12 @@ function parsePlan(planMd) {
|
|
|
94
94
|
? filesMatch[1].match(/`([^`]+)`/g)?.map((s) => s.replace(/`/g, '')) || []
|
|
95
95
|
: [];
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
// Accept: "Comando: `...`" (PT), "**Verify command:** `...`", "**Verificação:** `...`", "**Verification:** `...`"
|
|
98
|
+
// Use [^`]+ with dotAll so multiline commands inside backticks are captured
|
|
99
|
+
const verifyCmdMatch = rest.match(
|
|
100
|
+
/(?:Comando|Verify\s+command|Verificação|Verification):\s*`([^`]+)`/is
|
|
101
|
+
);
|
|
102
|
+
const verifyCommand = verifyCmdMatch ? verifyCmdMatch[1].trim() : null;
|
|
99
103
|
|
|
100
104
|
const aceiteMatch = rest.match(/\*\*Aceite\s+vinculado:\*\*\s*([^\n]+)/i);
|
|
101
105
|
const aceite = aceiteMatch
|
|
@@ -542,23 +546,23 @@ module.exports = {
|
|
|
542
546
|
/** Parsing de artefatos OXE (PLAN, SPEC, STATE, hypotheses, confidence, lessons). */
|
|
543
547
|
parsePlan,
|
|
544
548
|
parseSpec,
|
|
545
|
-
parseHypotheses: context.parseHypotheses,
|
|
546
|
-
parseConfidenceVector: context.parseConfidenceVector,
|
|
547
|
-
parseExecutionPlanTasks: rationality.parsePlanTasks,
|
|
548
|
-
parseState,
|
|
549
|
+
parseHypotheses: context.parseHypotheses,
|
|
550
|
+
parseConfidenceVector: context.parseConfidenceVector,
|
|
551
|
+
parseExecutionPlanTasks: rationality.parsePlanTasks,
|
|
552
|
+
parseState,
|
|
549
553
|
validateDecisionFidelity,
|
|
550
554
|
parseLessonsMetrics,
|
|
551
555
|
updateLessonMetric,
|
|
552
556
|
deprecateLowEffectiveness,
|
|
553
557
|
|
|
554
558
|
/** Estado do projeto, SPEC/PLAN, fase, config. */
|
|
555
|
-
health: {
|
|
556
|
-
loadOxeConfigMerged: health.loadOxeConfigMerged,
|
|
557
|
-
validateConfigShape: health.validateConfigShape,
|
|
558
|
-
buildHealthReport: health.buildHealthReport,
|
|
559
|
-
detectWorkspaceMode: health.detectWorkspaceMode,
|
|
560
|
-
shouldSuppressExecutionWorkspaceGates: health.shouldSuppressExecutionWorkspaceGates,
|
|
561
|
-
suggestNextStep: health.suggestNextStep,
|
|
559
|
+
health: {
|
|
560
|
+
loadOxeConfigMerged: health.loadOxeConfigMerged,
|
|
561
|
+
validateConfigShape: health.validateConfigShape,
|
|
562
|
+
buildHealthReport: health.buildHealthReport,
|
|
563
|
+
detectWorkspaceMode: health.detectWorkspaceMode,
|
|
564
|
+
shouldSuppressExecutionWorkspaceGates: health.shouldSuppressExecutionWorkspaceGates,
|
|
565
|
+
suggestNextStep: health.suggestNextStep,
|
|
562
566
|
oxePaths: health.oxePaths,
|
|
563
567
|
parseStatePhase: health.parseStatePhase,
|
|
564
568
|
parseLastScanDate: health.parseLastScanDate,
|
|
@@ -572,11 +576,11 @@ module.exports = {
|
|
|
572
576
|
planAgentsWarnings: health.planAgentsWarnings,
|
|
573
577
|
phaseCoherenceWarnings: health.phaseCoherenceWarnings,
|
|
574
578
|
specSectionWarnings: health.specSectionWarnings,
|
|
575
|
-
planWaveWarningsFixed: health.planWaveWarningsFixed,
|
|
576
|
-
planTaskAceiteWarnings: health.planTaskAceiteWarnings,
|
|
577
|
-
buildExecutionRationality: health.buildExecutionRationality,
|
|
578
|
-
executionRationalityWarningsFromSummary: health.executionRationalityWarningsFromSummary,
|
|
579
|
-
verifyGapsWithoutSummaryWarning: health.verifyGapsWithoutSummaryWarning,
|
|
579
|
+
planWaveWarningsFixed: health.planWaveWarningsFixed,
|
|
580
|
+
planTaskAceiteWarnings: health.planTaskAceiteWarnings,
|
|
581
|
+
buildExecutionRationality: health.buildExecutionRationality,
|
|
582
|
+
executionRationalityWarningsFromSummary: health.executionRationalityWarningsFromSummary,
|
|
583
|
+
verifyGapsWithoutSummaryWarning: health.verifyGapsWithoutSummaryWarning,
|
|
580
584
|
expandExecutionProfile: health.expandExecutionProfile,
|
|
581
585
|
ALLOWED_CONFIG_KEYS: health.ALLOWED_CONFIG_KEYS,
|
|
582
586
|
EXECUTION_PROFILES: health.EXECUTION_PROFILES,
|
|
@@ -643,28 +647,28 @@ module.exports = {
|
|
|
643
647
|
},
|
|
644
648
|
|
|
645
649
|
/** Dashboard local: contexto consolidado e persistência de revisão do plano. */
|
|
646
|
-
dashboard: {
|
|
647
|
-
loadDashboardContext: dashboard.loadDashboardContext,
|
|
648
|
-
savePlanReviewStatus: dashboard.savePlanReviewStatus,
|
|
649
|
-
addPlanReviewComment: dashboard.addPlanReviewComment,
|
|
650
|
-
updatePlanReviewCommentStatus: dashboard.updatePlanReviewCommentStatus,
|
|
651
|
-
},
|
|
652
|
-
|
|
653
|
-
/** Release readiness: manifest, smoke matrix e checks de consistência antes de publicar. */
|
|
654
|
-
release: {
|
|
655
|
-
REQUIRED_RUNTIMES: release.REQUIRED_RUNTIMES,
|
|
656
|
-
WRAPPER_TARGETS: release.WRAPPER_TARGETS,
|
|
657
|
-
releasePaths: release.releasePaths,
|
|
658
|
-
collectWrapperHashes: release.collectWrapperHashes,
|
|
659
|
-
loadRuntimeSmokeReport: release.loadRuntimeSmokeReport,
|
|
660
|
-
loadRecoveryFixtureReport: release.loadRecoveryFixtureReport,
|
|
661
|
-
loadMultiAgentSoakReport: release.loadMultiAgentSoakReport,
|
|
662
|
-
buildReleaseManifest: release.buildReleaseManifest,
|
|
663
|
-
inspectCanonicalSource: release.inspectCanonicalSource,
|
|
664
|
-
evaluateReleaseManifest: release.evaluateReleaseManifest,
|
|
665
|
-
inspectReleaseReadiness: release.inspectReleaseReadiness,
|
|
666
|
-
checkReleaseConsistency: release.checkReleaseConsistency,
|
|
667
|
-
},
|
|
650
|
+
dashboard: {
|
|
651
|
+
loadDashboardContext: dashboard.loadDashboardContext,
|
|
652
|
+
savePlanReviewStatus: dashboard.savePlanReviewStatus,
|
|
653
|
+
addPlanReviewComment: dashboard.addPlanReviewComment,
|
|
654
|
+
updatePlanReviewCommentStatus: dashboard.updatePlanReviewCommentStatus,
|
|
655
|
+
},
|
|
656
|
+
|
|
657
|
+
/** Release readiness: manifest, smoke matrix e checks de consistência antes de publicar. */
|
|
658
|
+
release: {
|
|
659
|
+
REQUIRED_RUNTIMES: release.REQUIRED_RUNTIMES,
|
|
660
|
+
WRAPPER_TARGETS: release.WRAPPER_TARGETS,
|
|
661
|
+
releasePaths: release.releasePaths,
|
|
662
|
+
collectWrapperHashes: release.collectWrapperHashes,
|
|
663
|
+
loadRuntimeSmokeReport: release.loadRuntimeSmokeReport,
|
|
664
|
+
loadRecoveryFixtureReport: release.loadRecoveryFixtureReport,
|
|
665
|
+
loadMultiAgentSoakReport: release.loadMultiAgentSoakReport,
|
|
666
|
+
buildReleaseManifest: release.buildReleaseManifest,
|
|
667
|
+
inspectCanonicalSource: release.inspectCanonicalSource,
|
|
668
|
+
evaluateReleaseManifest: release.evaluateReleaseManifest,
|
|
669
|
+
inspectReleaseReadiness: release.inspectReleaseReadiness,
|
|
670
|
+
checkReleaseConsistency: release.checkReleaseConsistency,
|
|
671
|
+
},
|
|
668
672
|
|
|
669
673
|
/** Runtime operacional: tracing, active run, catálogo de capabilities e memória em camadas. */
|
|
670
674
|
operational: {
|
|
@@ -24,12 +24,14 @@ evidence_expectation: manifest | command | manual | mixed
|
|
|
24
24
|
|
|
25
25
|
> Gerado a partir de `.oxe/SPEC.md`. Cada tarefa deve ter bloco **Verificar**.
|
|
26
26
|
|
|
27
|
-
## Resumo
|
|
28
|
-
|
|
29
|
-
- **Spec vinculada:** (data ou versão informal)
|
|
30
|
-
- **Ondas:** (número)
|
|
31
|
-
- **Tarefas:** (número)
|
|
32
|
-
- **Artefatos racionais:** `IMPLEMENTATION-PACK`, `REFERENCE-ANCHORS`, `FIXTURE-PACK`
|
|
27
|
+
## Resumo
|
|
28
|
+
|
|
29
|
+
- **Spec vinculada:** (data ou versão informal)
|
|
30
|
+
- **Ondas:** (número)
|
|
31
|
+
- **Tarefas:** (número)
|
|
32
|
+
- **Artefatos racionais:** `IMPLEMENTATION-PACK`, `REFERENCE-ANCHORS`, `FIXTURE-PACK`
|
|
33
|
+
- **Público / outcome da spec:** …
|
|
34
|
+
- **Padrão de validação dominante:** testes | smoke | manual guiado | mixed
|
|
33
35
|
|
|
34
36
|
## Autoavaliação do Plano
|
|
35
37
|
|
|
@@ -48,6 +50,7 @@ evidence_expectation: manifest | command | manual | mixed
|
|
|
48
50
|
- **Alternativas descartadas:** (1–2 linhas)
|
|
49
51
|
- **Condição para replanejar:** (critério objetivo)
|
|
50
52
|
- **Bloqueadores de execução:** nenhum | listar gaps críticos
|
|
53
|
+
- **Densidade operacional mínima confirmada:** paths | symbols | fixtures | anchors | checks
|
|
51
54
|
|
|
52
55
|
<confidence_vector cycle="C-NN" generated_at="YYYY-MM-DDTHH:MM:SSZ">
|
|
53
56
|
<dim name="requirements" score="0.92" weight="25" note="completude dos requisitos" />
|
|
@@ -80,9 +83,17 @@ evidence_expectation: manifest | command | manual | mixed
|
|
|
80
83
|
</hypothesis>
|
|
81
84
|
-->
|
|
82
85
|
|
|
83
|
-
## Dependências globais
|
|
84
|
-
|
|
85
|
-
- (ex.: branch base, feature flags, migrations)
|
|
86
|
+
## Dependências globais
|
|
87
|
+
|
|
88
|
+
- (ex.: branch base, feature flags, migrations)
|
|
89
|
+
|
|
90
|
+
## Contrato operacional da solução
|
|
91
|
+
|
|
92
|
+
- **Write-set principal:** módulos/paths que concentram a mutação
|
|
93
|
+
- **Modelo de conteúdo / dados a materializar:** …
|
|
94
|
+
- **Interações ou fluxos obrigatórios:** …
|
|
95
|
+
- **Persistência local/remota:** none | localStorage | API | outro
|
|
96
|
+
- **Responsividade / acessibilidade obrigatória:** …
|
|
86
97
|
|
|
87
98
|
## Artefatos racionais de execução
|
|
88
99
|
|
|
@@ -118,18 +129,21 @@ evidence_expectation: manifest | command | manual | mixed
|
|
|
118
129
|
### T1 — (título)
|
|
119
130
|
|
|
120
131
|
- **Arquivos alvo:** `src/exato.ts`
|
|
132
|
+
- **Símbolos alvo:** `função`, `classe`, `componente`, `builder`, `schema`
|
|
121
133
|
- **Depende de:** —
|
|
122
134
|
- **Onda:** 1
|
|
123
135
|
- **Complexidade:** S
|
|
124
136
|
- **Risco:** low | medium | high | critical
|
|
125
137
|
- **Evidência de entrada:** SPEC A1 | DISCUSS D-01 | RESEARCH RA-01 | codebase path
|
|
126
138
|
- **Checkpoint:** nenhum | CHK-01
|
|
139
|
+
- **Estado/fluxo coberto:** loading | empty | success | error | interação X
|
|
127
140
|
- **Verificar:**
|
|
128
141
|
- Comando: `…`
|
|
129
142
|
- Manual: (opcional) …
|
|
130
143
|
- **Implementar:** o mínimo para fazer a verificação acima passar.
|
|
131
144
|
- **Aceite vinculado:** A1, A2 (IDs da tabela de critérios em SPEC.md)
|
|
132
145
|
- **Contrato racional:** ver `IMPLEMENTATION-PACK.json` (task `T1`)
|
|
146
|
+
- **Fixture/anchor obrigatório:** FX-01 | RA-01 | not_applicable
|
|
133
147
|
- **Rollback/contensão:** obrigatório para risco high/critical; `not_applicable` se low/medium.
|
|
134
148
|
|
|
135
149
|
---
|