jules-orchestrator-kit 0.32.4 → 0.32.6
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/JULES_RULES_TEMPLATE.md +2 -1
- package/README.md +48 -12
- package/bin/agentctl.mjs +122 -13
- package/index.mjs +19 -4
- package/package.json +2 -1
- package/scripts/command-resolver.mjs +15 -1
- package/scripts/doc-sync-check.mjs +234 -0
- package/scripts/release.mjs +23 -2
- package/src/config.mjs +66 -0
- package/src/dag-engine.mjs +118 -0
- package/src/engine.mjs +237 -71
- package/src/evidence.mjs +435 -0
- package/src/mcp.mjs +39 -1
- package/src/ops/evidence-actions.mjs +74 -0
- package/src/provider.mjs +37 -7
- package/src/router.mjs +205 -0
- package/src/security.mjs +66 -13
- package/src/stack-detector.mjs +28 -0
- package/src/wizard-task.mjs +66 -5
package/src/engine.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { loadConfig, parseYaml, normalizeScope } from "./config.mjs";
|
|
|
2
2
|
import { checkScope, scanDiff, redactSecrets } from "./security.mjs";
|
|
3
3
|
import { changedFiles, diffBytes, diffText, showFromOrigin, runCmd } from "./git.mjs";
|
|
4
4
|
import { createProvider, ProviderRateLimitError, ProviderUnavailableError } from "./provider.mjs";
|
|
5
|
+
import { resolveRoutedProvider } from "./router.mjs";
|
|
5
6
|
import { withBudget, appendLedger, getQueueDir, ensureDir, rollbackBudgetReservation, isConcurrencyGroupLocked } from "./state.mjs";
|
|
6
7
|
import { sanitizeUntrustedData, buildAgentEnvelope } from "./prompt-guard.mjs";
|
|
7
8
|
import { recordVerifyRun, readVerifyRuns, flakyVerdict } from "./flaky-ledger.mjs";
|
|
@@ -11,10 +12,41 @@ import { createHash } from "node:crypto";
|
|
|
11
12
|
import { appendTelemetry as appendTelemetryUnsafe } from "./telemetry.mjs";
|
|
12
13
|
|
|
13
14
|
import { spawn } from "node:child_process";
|
|
14
|
-
import { resolveAffectedTests } from "./dag-engine.mjs";
|
|
15
|
+
import { resolveAffectedTests, executeQueueDag } from "./dag-engine.mjs";
|
|
15
16
|
import { recordRemediation, queryRemediations, harvestFailureRecord, hydrateMemory } from "./remediation.mjs";
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
import { hydratePrompt, harvestFailure } from "./memory.mjs";
|
|
18
|
+
import { resolveRolePrompt } from "./wizard-task.mjs";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
computeDirectoryHash,
|
|
22
|
+
generateEvidenceManifest,
|
|
23
|
+
writeEvidenceManifest,
|
|
24
|
+
verifyEvidenceManifest,
|
|
25
|
+
generateEvidenceMarkdown,
|
|
26
|
+
sha256,
|
|
27
|
+
} from "./evidence.mjs";
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
recordVerifyRun,
|
|
31
|
+
readVerifyRuns,
|
|
32
|
+
flakyVerdict,
|
|
33
|
+
sanitizeUntrustedData,
|
|
34
|
+
resolveAffectedTests,
|
|
35
|
+
executeQueueDag,
|
|
36
|
+
recordRemediation,
|
|
37
|
+
queryRemediations,
|
|
38
|
+
harvestFailureRecord,
|
|
39
|
+
hydrateMemory,
|
|
40
|
+
hydratePrompt,
|
|
41
|
+
harvestFailure,
|
|
42
|
+
resolveRolePrompt,
|
|
43
|
+
isConcurrencyGroupLocked,
|
|
44
|
+
computeDirectoryHash,
|
|
45
|
+
generateEvidenceManifest,
|
|
46
|
+
writeEvidenceManifest,
|
|
47
|
+
verifyEvidenceManifest,
|
|
48
|
+
generateEvidenceMarkdown,
|
|
49
|
+
};
|
|
18
50
|
|
|
19
51
|
|
|
20
52
|
function appendTelemetry(root, kind, fields = {}) {
|
|
@@ -146,9 +178,16 @@ export async function gate(opts = {}) {
|
|
|
146
178
|
if (parsed.verify || parsed.test_cmd || parsed.build_cmd) {
|
|
147
179
|
trustedVerify = {
|
|
148
180
|
setup: parsed.verify?.setup || config.verify.setup,
|
|
181
|
+
lint: parsed.verify?.lint || parsed.lint_cmd || config.verify.lint,
|
|
149
182
|
test: parsed.verify?.test || parsed.test_cmd || config.verify.test,
|
|
183
|
+
unit: parsed.verify?.unit || config.verify.unit || parsed.verify?.test || parsed.test_cmd || config.verify.test,
|
|
184
|
+
fuzz: parsed.verify?.fuzz || parsed.fuzz_cmd || config.verify.fuzz,
|
|
185
|
+
invariant: parsed.verify?.invariant || parsed.invariant_cmd || config.verify.invariant,
|
|
186
|
+
e2e: parsed.verify?.e2e || parsed.e2e_cmd || config.verify.e2e,
|
|
150
187
|
teardown: parsed.verify?.teardown || config.verify.teardown,
|
|
151
188
|
build: parsed.verify?.build || parsed.build_cmd || config.verify.build,
|
|
189
|
+
stages: parsed.verify?.stages || config.verify.stages,
|
|
190
|
+
policy: parsed.verify?.policy || config.verify.policy,
|
|
152
191
|
timeoutMs: parsed.verify?.timeoutMs || parsed.verify?.timeout_ms || config.verify.timeoutMs,
|
|
153
192
|
};
|
|
154
193
|
}
|
|
@@ -200,11 +239,16 @@ export async function gate(opts = {}) {
|
|
|
200
239
|
return { ok: false, code: 6, phases };
|
|
201
240
|
}
|
|
202
241
|
|
|
242
|
+
// Pre-verification: compute test directory integrity hash
|
|
243
|
+
const preTestHashResult = computeDirectoryHash(root, { testOnly: true });
|
|
244
|
+
const preTestHash = preTestHashResult.treeHash;
|
|
245
|
+
const executionRecords = [];
|
|
246
|
+
|
|
203
247
|
// Phase 4: Automated Test & Build Verification (Uses trusted verify commands only)
|
|
204
|
-
const testCmd = trustedVerify.test;
|
|
205
|
-
const buildCmd = trustedVerify.build;
|
|
206
248
|
let testResult = { ok: true, status: 0 };
|
|
207
249
|
let buildResult = { ok: true, status: 0 };
|
|
250
|
+
let serverResult = { ok: true, status: 0 };
|
|
251
|
+
let failingCmd = null;
|
|
208
252
|
|
|
209
253
|
const existingNodeOptions = process.env.NODE_OPTIONS || "";
|
|
210
254
|
const netGuardUrl = new URL("./preload-net-guard.mjs", import.meta.url).href;
|
|
@@ -219,100 +263,178 @@ export async function gate(opts = {}) {
|
|
|
219
263
|
};
|
|
220
264
|
|
|
221
265
|
let flakyVerdictResult = null;
|
|
266
|
+
const verifyTimeout = trustedVerify.timeoutMs || 60000;
|
|
222
267
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
stdout: redactSecrets(res.stdout || ""),
|
|
251
|
-
stderr: redactSecrets(res.stderr || ""),
|
|
252
|
-
command: testCmd,
|
|
253
|
-
};
|
|
268
|
+
// Build sequential execution pipeline (Setup -> Lint -> Test/Unit -> Fuzz -> Invariant -> E2E -> Build -> Server -> Teardown)
|
|
269
|
+
const stagesToRun = [];
|
|
270
|
+
if (Array.isArray(trustedVerify.stages) && trustedVerify.stages.length > 0) {
|
|
271
|
+
stagesToRun.push(...trustedVerify.stages);
|
|
272
|
+
} else {
|
|
273
|
+
if (trustedVerify.setup) {
|
|
274
|
+
stagesToRun.push({ id: "setup", kind: "setup", cmd: trustedVerify.setup, required: true, networkAccess: "allow" });
|
|
275
|
+
}
|
|
276
|
+
if (trustedVerify.lint) {
|
|
277
|
+
stagesToRun.push({ id: "lint", kind: "lint", cmd: trustedVerify.lint, required: true, networkAccess: trustedVerify.policy?.networkAccess || "allow" });
|
|
278
|
+
}
|
|
279
|
+
if (trustedVerify.test || trustedVerify.unit) {
|
|
280
|
+
stagesToRun.push({ id: "unit", kind: "test", cmd: trustedVerify.test || trustedVerify.unit, required: true, networkAccess: trustedVerify.policy?.networkAccess || "allow" });
|
|
281
|
+
}
|
|
282
|
+
if (trustedVerify.fuzz) {
|
|
283
|
+
stagesToRun.push({ id: "fuzz", kind: "fuzz", cmd: trustedVerify.fuzz, required: true, networkAccess: trustedVerify.policy?.networkAccess || "allow" });
|
|
284
|
+
}
|
|
285
|
+
if (trustedVerify.invariant) {
|
|
286
|
+
stagesToRun.push({ id: "invariant", kind: "invariant", cmd: trustedVerify.invariant, required: true, networkAccess: trustedVerify.policy?.networkAccess || "allow" });
|
|
287
|
+
}
|
|
288
|
+
if (trustedVerify.e2e) {
|
|
289
|
+
stagesToRun.push({ id: "e2e", kind: "e2e", cmd: trustedVerify.e2e, required: true, networkAccess: "allow" });
|
|
290
|
+
}
|
|
291
|
+
if (trustedVerify.build) {
|
|
292
|
+
stagesToRun.push({ id: "build", kind: "build", cmd: trustedVerify.build, required: true, networkAccess: trustedVerify.policy?.networkAccess || "allow" });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
254
295
|
|
|
255
|
-
|
|
256
|
-
|
|
296
|
+
try {
|
|
297
|
+
for (const stage of stagesToRun) {
|
|
298
|
+
if (!stage.cmd) continue;
|
|
299
|
+
const startTime = Date.now();
|
|
300
|
+
const stageEnv = stage.networkAccess === "forbidden" || trustedVerify.policy?.offline
|
|
301
|
+
? { ...testEnv, JULES_SANDBOX_OFFLINE: "1" }
|
|
302
|
+
: testEnv;
|
|
303
|
+
|
|
304
|
+
const res = runCmd(stage.cmd, { cwd: root, ignoreError: true, env: stageEnv, timeout: stage.timeoutMs || verifyTimeout });
|
|
305
|
+
const durationMs = Date.now() - startTime;
|
|
306
|
+
const stdoutRedacted = redactSecrets(res.stdout || "");
|
|
307
|
+
const stderrRedacted = redactSecrets(res.stderr || "");
|
|
308
|
+
const stageOk = res.status === 0;
|
|
309
|
+
|
|
310
|
+
executionRecords.push({
|
|
311
|
+
id: stage.id || stage.kind,
|
|
312
|
+
kind: stage.kind,
|
|
313
|
+
cmd: stage.cmd,
|
|
314
|
+
exitCode: res.status,
|
|
315
|
+
durationMs,
|
|
316
|
+
networkAccess: stage.networkAccess || "allow",
|
|
317
|
+
stdoutHash: "sha256:" + sha256(stdoutRedacted),
|
|
318
|
+
stderrHash: "sha256:" + sha256(stderrRedacted),
|
|
319
|
+
});
|
|
257
320
|
|
|
258
|
-
|
|
259
|
-
|
|
321
|
+
if (stage.kind === "test" || stage.kind === "unit") {
|
|
322
|
+
testResult = { ok: stageOk, status: res.status, stdout: stdoutRedacted, stderr: stderrRedacted, command: stage.cmd };
|
|
323
|
+
const fingerprint = !stageOk ? fingerprintFailureState(testResult, root) : null;
|
|
324
|
+
recordVerifyRun(root, stage.cmd, stageOk, fingerprint, durationMs);
|
|
325
|
+
if (!stageOk) {
|
|
326
|
+
const runs = readVerifyRuns(root, stage.cmd);
|
|
260
327
|
flakyVerdictResult = flakyVerdict(runs);
|
|
261
328
|
if (flakyVerdictResult.verdict === "QUARANTINED") {
|
|
262
|
-
phases.push({ phase: "verify", ok: false, testResult, buildResult, flakyVerdict: flakyVerdictResult });
|
|
329
|
+
phases.push({ phase: "verify", ok: false, testResult, buildResult, flakyVerdict: flakyVerdictResult, executionRecords });
|
|
263
330
|
appendTelemetry(root, "gate_phase", { phase: "verify", ok: false, quarantined: true });
|
|
264
331
|
appendTelemetry(root, "gate_finished", { ok: false, code: 8 });
|
|
265
332
|
return { ok: false, code: 8, phases, flakyVerdict: flakyVerdictResult };
|
|
266
333
|
}
|
|
267
334
|
}
|
|
335
|
+
} else if (stage.kind === "build") {
|
|
336
|
+
buildResult = { ok: stageOk, status: res.status, stdout: stdoutRedacted, stderr: stderrRedacted, command: stage.cmd };
|
|
268
337
|
}
|
|
269
|
-
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
338
|
+
|
|
339
|
+
if (!stageOk && stage.required !== false) {
|
|
340
|
+
failingCmd = {
|
|
341
|
+
ok: false,
|
|
342
|
+
status: res.status,
|
|
343
|
+
stdout: stdoutRedacted,
|
|
344
|
+
stderr: stderrRedacted,
|
|
345
|
+
command: stage.cmd,
|
|
346
|
+
phase: stage.kind,
|
|
347
|
+
};
|
|
348
|
+
break;
|
|
274
349
|
}
|
|
275
350
|
}
|
|
351
|
+
} finally {
|
|
352
|
+
if (trustedVerify.teardown) {
|
|
353
|
+
try {
|
|
354
|
+
runCmd(trustedVerify.teardown, { cwd: root, ignoreError: true, env: testEnv });
|
|
355
|
+
} catch (_) {}
|
|
356
|
+
}
|
|
276
357
|
}
|
|
277
358
|
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
stdout: redactSecrets(res.stdout || ""),
|
|
284
|
-
stderr: redactSecrets(res.stderr || ""),
|
|
285
|
-
command: buildCmd,
|
|
286
|
-
};
|
|
359
|
+
if (!failingCmd && trustedVerify.server && trustedVerify.server.command) {
|
|
360
|
+
serverResult = await probeDevServer(trustedVerify.server, root);
|
|
361
|
+
if (!serverResult.ok) {
|
|
362
|
+
failingCmd = serverResult;
|
|
363
|
+
}
|
|
287
364
|
}
|
|
288
365
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
366
|
+
// Post-verification test integrity check (No Test Weakening Invariant)
|
|
367
|
+
const postTestHashResult = computeDirectoryHash(root, { testOnly: true });
|
|
368
|
+
const postTestHash = postTestHashResult.treeHash;
|
|
369
|
+
let testTampered = false;
|
|
370
|
+
if (config.evidence?.strictTestLock && !opts.allowTestModifications && preTestHashResult.fileCount > 0) {
|
|
371
|
+
const changedTestFile = files.find((f) => {
|
|
372
|
+
const lower = f.toLowerCase();
|
|
373
|
+
return lower.startsWith("test/") || lower.startsWith("tests/") || lower.includes(".test.") || lower.includes(".spec.");
|
|
374
|
+
});
|
|
375
|
+
if (changedTestFile && preTestHash !== postTestHash) {
|
|
376
|
+
testTampered = true;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Generate & persist Evidence Manifest
|
|
381
|
+
const evidenceManifest = generateEvidenceManifest(root, {
|
|
382
|
+
preTestHash,
|
|
383
|
+
executionRecords,
|
|
384
|
+
secretScanOk: secretResult.ok,
|
|
385
|
+
diffKb: Math.round(bytes / 1024),
|
|
386
|
+
maxDiffKb: config.limits.diffKb || 75,
|
|
387
|
+
protectedScopeOk: scopeResult.ok,
|
|
388
|
+
repository: config.provider || "jules",
|
|
389
|
+
});
|
|
390
|
+
if (testTampered) {
|
|
391
|
+
evidenceManifest.testIntegrity.tamperDetected = true;
|
|
292
392
|
}
|
|
393
|
+
let evidencePath = null;
|
|
394
|
+
try {
|
|
395
|
+
evidencePath = writeEvidenceManifest(root, evidenceManifest);
|
|
396
|
+
} catch (_) {}
|
|
397
|
+
|
|
398
|
+
const verifyOk = !failingCmd && !testTampered;
|
|
399
|
+
phases.push({
|
|
400
|
+
phase: "verify",
|
|
401
|
+
ok: verifyOk,
|
|
402
|
+
testResult,
|
|
403
|
+
buildResult,
|
|
404
|
+
serverResult,
|
|
405
|
+
executionRecords,
|
|
406
|
+
testIntegrity: {
|
|
407
|
+
preTestHash,
|
|
408
|
+
postTestHash,
|
|
409
|
+
tamperDetected: testTampered,
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
phases.push({
|
|
413
|
+
phase: "evidence",
|
|
414
|
+
ok: !testTampered,
|
|
415
|
+
manifestPath: evidencePath,
|
|
416
|
+
evidenceHash: evidenceManifest.evidenceHash,
|
|
417
|
+
});
|
|
293
418
|
|
|
294
|
-
const verifyOk = testResult.ok && buildResult.ok && serverResult.ok;
|
|
295
|
-
const failingCmd = !testResult.ok ? testResult : !buildResult.ok ? buildResult : !serverResult.ok ? serverResult : null;
|
|
296
|
-
phases.push({ phase: "verify", ok: verifyOk, testResult, buildResult, serverResult });
|
|
297
419
|
appendTelemetry(root, "gate_phase", { phase: "verify", ok: verifyOk });
|
|
298
420
|
if (progressBus && progressToken) {
|
|
299
|
-
progressBus.reportProgress(progressToken, 100, 100, "Phase 4/4: Automated
|
|
421
|
+
progressBus.reportProgress(progressToken, 100, 100, "Phase 4/4: Automated Tiered Verification complete");
|
|
300
422
|
}
|
|
301
423
|
|
|
302
|
-
if (!verifyOk && opts.fix) {
|
|
424
|
+
if (!verifyOk && opts.fix && failingCmd) {
|
|
303
425
|
const repairs = await repair(failingCmd, { config, root, signal: opts.signal, progressBus, progressToken });
|
|
304
426
|
const finalOk = repairs.ok;
|
|
305
427
|
const finalCode = repairs.ok ? 0 : 4;
|
|
306
428
|
appendTelemetry(root, "gate_finished", { ok: finalOk, code: finalCode, repaired: true });
|
|
307
429
|
if (repairs.ok) {
|
|
308
|
-
return { ok: true, code: 0, phases, repairs };
|
|
430
|
+
return { ok: true, code: 0, phases, repairs, evidence: evidenceManifest };
|
|
309
431
|
}
|
|
310
|
-
return { ok: false, code: 4, phases, repairs };
|
|
432
|
+
return { ok: false, code: 4, phases, repairs, evidence: evidenceManifest };
|
|
311
433
|
}
|
|
312
434
|
|
|
313
|
-
const code = verifyOk ? 0 : 4;
|
|
435
|
+
const code = verifyOk ? 0 : testTampered ? 3 : 4;
|
|
314
436
|
appendTelemetry(root, "gate_finished", { ok: verifyOk, code });
|
|
315
|
-
return { ok: verifyOk, code, phases };
|
|
437
|
+
return { ok: verifyOk, code, phases, evidence: evidenceManifest };
|
|
316
438
|
}
|
|
317
439
|
|
|
318
440
|
/**
|
|
@@ -483,6 +605,15 @@ export async function repair(failure, opts = {}) {
|
|
|
483
605
|
targetFiles: currentFailure.targetFiles || [],
|
|
484
606
|
});
|
|
485
607
|
|
|
608
|
+
try {
|
|
609
|
+
harvestFailure(root, {
|
|
610
|
+
exitCode: 4,
|
|
611
|
+
diffText: diffText(root) || "",
|
|
612
|
+
taskId: failure?.taskId || "ooda-repair",
|
|
613
|
+
logPath: failure?.logPath,
|
|
614
|
+
});
|
|
615
|
+
} catch (_) {}
|
|
616
|
+
|
|
486
617
|
return { ok: false, attempts, finalStatus: "OODA_EXHAUSTED" };
|
|
487
618
|
|
|
488
619
|
}
|
|
@@ -564,7 +695,15 @@ export async function dispatch(task = {}, opts = {}) {
|
|
|
564
695
|
}
|
|
565
696
|
const root = opts.config?._root || opts.root || process.cwd();
|
|
566
697
|
const config = opts.config || loadConfig(root);
|
|
567
|
-
const provider =
|
|
698
|
+
const { provider, routed, classification } = resolveRoutedProvider(task, config);
|
|
699
|
+
if (routed && classification) {
|
|
700
|
+
appendTelemetry(root, "router_decision", {
|
|
701
|
+
tier: classification.tier,
|
|
702
|
+
forced: classification.forced,
|
|
703
|
+
reason: classification.reason,
|
|
704
|
+
score: classification.score,
|
|
705
|
+
});
|
|
706
|
+
}
|
|
568
707
|
|
|
569
708
|
// Enforce prompt size limit
|
|
570
709
|
const promptKb = (config.limits.promptKb || 50) * 1024;
|
|
@@ -573,7 +712,20 @@ export async function dispatch(task = {}, opts = {}) {
|
|
|
573
712
|
}
|
|
574
713
|
|
|
575
714
|
// Redact secrets in prompt before dispatching
|
|
576
|
-
|
|
715
|
+
let cleanPrompt = redactSecrets(task.prompt || "");
|
|
716
|
+
|
|
717
|
+
// Specialist Role resolution (if role is set and not already present in prompt)
|
|
718
|
+
if (task.role && !cleanPrompt.includes("Protocol - ")) {
|
|
719
|
+
const roleObj = resolveRolePrompt(root, task.role);
|
|
720
|
+
if (roleObj) {
|
|
721
|
+
cleanPrompt = `${roleObj.content}\n\n${cleanPrompt}`.trim();
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// SPORE Memory Hydration (auto-hydrate platform quirks & system learnings)
|
|
726
|
+
if (!cleanPrompt.includes("<ACTIVE_SYSTEM_LEARNINGS>")) {
|
|
727
|
+
cleanPrompt = hydratePrompt(root, cleanPrompt);
|
|
728
|
+
}
|
|
577
729
|
|
|
578
730
|
// Wire Prompt Guard, Memory Hydration & Envelope to wrap raw task arguments
|
|
579
731
|
const taskInstructions = task.taskInstructions || cleanPrompt || task.title || "Autonomous Task Execution";
|
|
@@ -588,11 +740,12 @@ export async function dispatch(task = {}, opts = {}) {
|
|
|
588
740
|
const cleanTask = { ...task, prompt: envelopedPrompt };
|
|
589
741
|
|
|
590
742
|
try {
|
|
591
|
-
|
|
743
|
+
const session = await withBudget(
|
|
592
744
|
() => provider.dispatch(cleanTask, { root, dryRun: opts.dryRun }),
|
|
593
745
|
root,
|
|
594
746
|
config.limits.dailyTasks
|
|
595
747
|
);
|
|
748
|
+
return classification ? { ...session, _routeTier: classification.tier, _routeReason: classification.reason } : session;
|
|
596
749
|
} catch (err) {
|
|
597
750
|
if (err instanceof ProviderRateLimitError || err instanceof ProviderUnavailableError) {
|
|
598
751
|
if (err.reservationId && !err.budgetReservationRolledBack) {
|
|
@@ -629,6 +782,15 @@ export async function run(tasksOrOpts = {}, opts = {}) {
|
|
|
629
782
|
const requestedConcurrency = Number(options.concurrency ?? config.limits.concurrency ?? 1);
|
|
630
783
|
const concurrency = Number.isInteger(requestedConcurrency) && requestedConcurrency > 0 ? requestedConcurrency : 1;
|
|
631
784
|
const isDry = options.dryRun !== undefined ? options.dryRun : (process.env.JULES_DRY_RUN === "true" || process.env.JULES_DRY_RUN === "1");
|
|
785
|
+
|
|
786
|
+
if (options.dag || options.useDag) {
|
|
787
|
+
return await executeQueueDag(root, {
|
|
788
|
+
concurrency,
|
|
789
|
+
dryRun: isDry,
|
|
790
|
+
config,
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
|
|
632
794
|
const queueDir = getQueueDir(root);
|
|
633
795
|
const completedDir = join(queueDir, "completed");
|
|
634
796
|
ensureDir(completedDir);
|
|
@@ -713,6 +875,10 @@ export function synthesizePrDescription(session = {}, gateResult = {}, options =
|
|
|
713
875
|
|
|
714
876
|
const kbDiff = ((payloadPhase.bytes || 0) / 1024).toFixed(1);
|
|
715
877
|
const kbLimit = ((payloadPhase.limitBytes || 76800) / 1024).toFixed(0);
|
|
878
|
+
const evidenceManifest = gateResult.evidence || (options.evidence ? options.evidence : null);
|
|
879
|
+
const evidenceSection = evidenceManifest
|
|
880
|
+
? `\n### 🛡️ Cryptographic Evidence Manifest\n- **Manifest ID:** \`${evidenceManifest.manifestId}\`\n- **Signature:** \`${evidenceManifest.evidenceHash?.slice(0, 16)}...\`\n- **Test Integrity:** ${evidenceManifest.testIntegrity?.tamperDetected ? "❌ Tampered" : "✅ Verified (0 test weakening)"}\n`
|
|
881
|
+
: "";
|
|
716
882
|
|
|
717
883
|
const modifiedFiles = options.modifiedFiles || [];
|
|
718
884
|
const affectedTests = resolveAffectedTests(modifiedFiles, options);
|
|
@@ -724,7 +890,7 @@ export function synthesizePrDescription(session = {}, gateResult = {}, options =
|
|
|
724
890
|
- **OODA Turns:** \`${attemptsCount}/${maxAttempts}\`
|
|
725
891
|
- **Warm Resumption:** ${isWarm ? "✅ Active Context Stream" : "Cold Start"}
|
|
726
892
|
- **Execution Latency:** \`${durationSec}s\`
|
|
727
|
-
|
|
893
|
+
${evidenceSection}
|
|
728
894
|
### 🛡️ Zero-Trust Security Audit Matrix
|
|
729
895
|
- **Scope Guard:** ${scopePhase.ok ? "✅ PASS (0 protected path violations)" : "❌ FAIL"}
|
|
730
896
|
- **Diff Payload Governor:** ${payloadPhase.ok ? `✅ PASS (${kbDiff} KB / ${kbLimit} KB limit)` : "❌ EXCEEDED"}
|