@fitlab-ai/agent-infra 0.11.8 → 0.11.10
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/bin/internal-cli.js +0 -6
- package/dist/lib/agent-clients/custom-tool-invocations.js +92 -0
- package/dist/lib/agent-clients/next-steps.js +1 -1
- package/dist/lib/agent-clients/reconcile.js +3 -3
- package/dist/lib/agent-clients/schema.js +18 -10
- package/dist/lib/git/workflow.js +1 -1
- package/dist/lib/init.js +2 -2
- package/dist/lib/internal/agent-client.js +3 -3
- package/dist/lib/internal/cli-route-inventory.js +0 -3
- package/dist/lib/internal/sandbox-control.js +30 -5
- package/dist/lib/internal/task-finalization.js +14 -23
- package/dist/lib/internal/task-operation-registry.js +2 -3
- package/dist/lib/internal/task-platform-recovery.js +9 -4
- package/dist/lib/platform/completion-backfill.js +2 -1
- package/dist/lib/platform/context.js +4 -2
- package/dist/lib/platform/github-client.js +20 -17
- package/dist/lib/platform/github-provider.js +42 -22
- package/dist/lib/platform/github-release-notes.js +4 -2
- package/dist/lib/platform/in-label-sync.js +2 -1
- package/dist/lib/platform/issue-comments.js +13 -9
- package/dist/lib/platform/operation-coordinator.js +1 -1
- package/dist/lib/platform/pr-review.js +2 -1
- package/dist/lib/platform/provider-bridge.js +4 -5
- package/dist/lib/platform/provider-contract.d.ts +3 -6
- package/dist/lib/platform/provider-contract.js +3 -15
- package/dist/lib/platform/provider-validation.js +9 -4
- package/dist/lib/platform/pull-requests.js +4 -2
- package/dist/lib/sandbox/control/client.js +54 -6
- package/dist/lib/sandbox/control/executor.js +8 -3
- package/dist/lib/sandbox/recovery.js +1 -22
- package/dist/lib/sandbox/removal.js +0 -1
- package/dist/lib/sandbox/tools.js +2 -0
- package/dist/lib/task/artifact-command.js +11 -1
- package/dist/lib/task/artifact-lifecycle.js +119 -62
- package/dist/lib/task/artifact-selection.js +1 -1
- package/dist/lib/task/capabilities.js +55 -21
- package/dist/lib/task/commands/status.js +0 -27
- package/dist/lib/task/commit-identity.js +22 -7
- package/dist/lib/task/commit-intent.js +67 -26
- package/dist/lib/task/commit-operation.js +19 -8
- package/dist/lib/task/completion-facts.js +32 -10
- package/dist/lib/task/control-authority.js +2 -4
- package/dist/lib/task/current-contract.js +1 -5
- package/dist/lib/task/events.js +8 -274
- package/dist/lib/task/execution-inputs.js +14 -0
- package/dist/lib/task/finalization-envelope.js +4 -0
- package/dist/lib/task/finalization.js +100 -129
- package/dist/lib/task/frontmatter.js +1 -1
- package/dist/lib/task/ledger-intents.js +4 -7
- package/dist/lib/task/orchestration.js +11 -10
- package/dist/lib/task/platform-operation-journal.js +17 -10
- package/dist/lib/task/platform-operation-recovery.js +95 -28
- package/dist/lib/task/review-fingerprint.js +4 -26
- package/dist/lib/task/verification-engine.js +95 -6
- package/dist/lib/task/verification.js +0 -1
- package/dist/lib/task/write.js +0 -11
- package/dist/lib/update.js +2 -2
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/custom-tool-invocations.ts +129 -0
- package/lib/agent-clients/next-steps.ts +3 -3
- package/lib/agent-clients/reconcile.ts +3 -3
- package/lib/agent-clients/schema.ts +18 -10
- package/lib/git/workflow.ts +1 -1
- package/lib/init.ts +2 -2
- package/lib/internal/agent-client.ts +3 -3
- package/lib/internal/cli-route-inventory.ts +0 -2
- package/lib/internal/sandbox-control.ts +39 -6
- package/lib/internal/task-finalization.ts +16 -24
- package/lib/internal/task-operation-registry.ts +2 -3
- package/lib/internal/task-platform-recovery.ts +9 -4
- package/lib/platform/completion-backfill.ts +2 -1
- package/lib/platform/context.ts +8 -4
- package/lib/platform/github-client.ts +24 -20
- package/lib/platform/github-provider.ts +47 -26
- package/lib/platform/github-release-notes.ts +5 -3
- package/lib/platform/in-label-sync.ts +2 -1
- package/lib/platform/issue-comments.ts +14 -9
- package/lib/platform/operation-coordinator.ts +1 -1
- package/lib/platform/pr-review.ts +2 -1
- package/lib/platform/provider-bridge.ts +10 -9
- package/lib/platform/provider-contract.ts +6 -21
- package/lib/platform/provider-loader.ts +7 -6
- package/lib/platform/provider-validation.ts +30 -8
- package/lib/platform/pull-requests.ts +4 -2
- package/lib/platform/repository-metadata.ts +3 -2
- package/lib/platform/security-alerts.ts +1 -1
- package/lib/platform/types.ts +2 -0
- package/lib/sandbox/control/client.ts +57 -6
- package/lib/sandbox/control/executor.ts +8 -3
- package/lib/sandbox/recovery.ts +0 -25
- package/lib/sandbox/removal.ts +2 -10
- package/lib/sandbox/tool-types.ts +1 -0
- package/lib/sandbox/tools.ts +2 -0
- package/lib/task/artifact-command.ts +10 -1
- package/lib/task/artifact-lifecycle.ts +100 -52
- package/lib/task/artifact-selection.ts +1 -1
- package/lib/task/capabilities.ts +47 -24
- package/lib/task/commands/status.ts +0 -31
- package/lib/task/commit-identity.ts +24 -7
- package/lib/task/commit-intent.ts +58 -24
- package/lib/task/commit-operation.ts +17 -8
- package/lib/task/completion-facts.ts +31 -9
- package/lib/task/control-authority.ts +1 -4
- package/lib/task/current-contract.ts +1 -6
- package/lib/task/events.ts +8 -247
- package/lib/task/execution-inputs.ts +25 -0
- package/lib/task/finalization-envelope.ts +21 -0
- package/lib/task/finalization.ts +101 -123
- package/lib/task/frontmatter.ts +1 -1
- package/lib/task/ledger-intents.ts +4 -7
- package/lib/task/orchestration.ts +11 -17
- package/lib/task/platform-operation-journal.ts +18 -11
- package/lib/task/platform-operation-recovery.ts +90 -31
- package/lib/task/review-fingerprint.ts +4 -26
- package/lib/task/verification-engine.ts +103 -9
- package/lib/task/verification.ts +1 -2
- package/lib/task/write.ts +0 -19
- package/lib/update.ts +2 -3
- package/package.json +1 -1
- package/templates/.agents/README.en.md +2 -50
- package/templates/.agents/README.zh-CN.md +2 -50
- package/templates/.agents/rules/commit-and-pr.en.md +5 -5
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +5 -5
- package/templates/.agents/rules/decision-qualification.en.md +1 -1
- package/templates/.agents/rules/decision-qualification.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +1 -1
- package/templates/.agents/rules/next-step-output.zh-CN.md +1 -1
- package/templates/.agents/scripts/lib/agent-infra-package.js +0 -7
- package/templates/.agents/skills/code-task/SKILL.en.md +25 -9
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +26 -9
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +5 -16
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +5 -16
- package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/SKILL.en.md +1 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +15 -12
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -10
- package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +15 -6
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +15 -6
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -2
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +2 -268
- package/templates/.agents/templates/task.zh-CN.md +0 -12
- package/templates/.github/workflows/pr-label.yml +1 -2
- package/dist/lib/agent-clients/custom-tuis.js +0 -99
- package/dist/lib/internal/task-invalidation.js +0 -63
- package/dist/lib/task/intermediate-cleanup.js +0 -327
- package/dist/lib/task/invalidation-command.js +0 -88
- package/dist/lib/task/invalidation.js +0 -242
- package/lib/agent-clients/custom-tuis.ts +0 -149
- package/lib/internal/task-invalidation.ts +0 -41
- package/lib/task/intermediate-cleanup.ts +0 -393
- package/lib/task/invalidation-command.ts +0 -88
- package/lib/task/invalidation.ts +0 -313
package/dist/lib/task/events.js
CHANGED
|
@@ -19,10 +19,8 @@ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-
|
|
|
19
19
|
import { captureTaskWriteMetadata, writeTask } from './write.js';
|
|
20
20
|
import { validateLocalArtifact } from './local-artifact-finalization.js';
|
|
21
21
|
import { buildLifecycleFacts, canStart, effectiveReworkTarget } from './capabilities.js';
|
|
22
|
-
import { createInvalidationOperation, invalidationMutation, parseInvalidationDocument, targetIdFor, upsertInvalidation } from './invalidation.js';
|
|
23
|
-
import { reconcileTaskInvalidation } from './invalidation-command.js';
|
|
24
22
|
import { consumeReworkIntents, parseReworkIntentDocument, reworkIntentMutation, supersedeReworkIntents } from './rework-intent.js';
|
|
25
|
-
import {
|
|
23
|
+
import { parseTaskQualification } from './qualification-audit.js';
|
|
26
24
|
import { getArtifactSchema } from './artifact-schema.js';
|
|
27
25
|
import { canonicalSemanticDigest, inspectArtifactContract } from './artifact-operations.js';
|
|
28
26
|
import { inspectReviewIdentity } from './review-identity.js';
|
|
@@ -370,235 +368,6 @@ function eventTrigger(request, family) {
|
|
|
370
368
|
explicitRequest: request.requestId !== undefined || request.reasonCode !== undefined || request.initiator !== undefined || request.orchestrated === true
|
|
371
369
|
};
|
|
372
370
|
}
|
|
373
|
-
function receiptGraphHasCycle(receipts) {
|
|
374
|
-
const edges = new Map();
|
|
375
|
-
for (const receipt of receipts) {
|
|
376
|
-
const outputs = edges.get(receipt.input) ?? [];
|
|
377
|
-
outputs.push(receipt.output);
|
|
378
|
-
edges.set(receipt.input, outputs);
|
|
379
|
-
}
|
|
380
|
-
const visiting = new Set();
|
|
381
|
-
const visited = new Set();
|
|
382
|
-
const visit = (node) => {
|
|
383
|
-
if (visiting.has(node))
|
|
384
|
-
return true;
|
|
385
|
-
if (visited.has(node))
|
|
386
|
-
return false;
|
|
387
|
-
visiting.add(node);
|
|
388
|
-
for (const output of edges.get(node) ?? [])
|
|
389
|
-
if (visit(output))
|
|
390
|
-
return true;
|
|
391
|
-
visiting.delete(node);
|
|
392
|
-
visited.add(node);
|
|
393
|
-
return false;
|
|
394
|
-
};
|
|
395
|
-
return [...edges.keys()].some(visit);
|
|
396
|
-
}
|
|
397
|
-
function qualificationInvalidationSeeds(content, taskDir, inventory, baselineDigest) {
|
|
398
|
-
const task = parseTaskQualification(content);
|
|
399
|
-
if (!task.ok)
|
|
400
|
-
return { changed: true, safe: false, seeds: [] };
|
|
401
|
-
if (baselineDigest !== undefined) {
|
|
402
|
-
if (!/^[a-f0-9]{64}$/u.test(baselineDigest))
|
|
403
|
-
return { changed: true, safe: false, seeds: [] };
|
|
404
|
-
if (baselineDigest === task.qualification.taskInputDigest)
|
|
405
|
-
return { changed: false, safe: true, seeds: [] };
|
|
406
|
-
}
|
|
407
|
-
const audits = [];
|
|
408
|
-
let observedQualification = false;
|
|
409
|
-
for (const artifact of inventory) {
|
|
410
|
-
let artifactContent;
|
|
411
|
-
try {
|
|
412
|
-
artifactContent = fs.readFileSync(path.join(taskDir, artifact.name), 'utf8');
|
|
413
|
-
}
|
|
414
|
-
catch {
|
|
415
|
-
return { changed: true, safe: false, seeds: [] };
|
|
416
|
-
}
|
|
417
|
-
const parsed = parseQualificationAudit(artifactContent);
|
|
418
|
-
if (!parsed.ok)
|
|
419
|
-
return { changed: true, safe: false, seeds: [] };
|
|
420
|
-
if (!parsed.audit.present)
|
|
421
|
-
continue;
|
|
422
|
-
observedQualification = true;
|
|
423
|
-
const snapshot = parsed.audit.snapshot;
|
|
424
|
-
if (!snapshot)
|
|
425
|
-
return { changed: true, safe: false, seeds: [] };
|
|
426
|
-
audits.push({
|
|
427
|
-
name: artifact.name,
|
|
428
|
-
snapshotTaskDigest: snapshot.taskInputDigest,
|
|
429
|
-
snapshotNonConstraintDigest: snapshot.nonConstraintInputDigest,
|
|
430
|
-
dependencies: parsed.audit.constraintDependencies,
|
|
431
|
-
candidates: parsed.audit.candidateQualifications
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
if (!task.qualification.present)
|
|
435
|
-
return { changed: false, safe: true, seeds: [] };
|
|
436
|
-
const allAuditsPresent = observedQualification && audits.length === inventory.length;
|
|
437
|
-
if (!allAuditsPresent)
|
|
438
|
-
return { changed: true, safe: false, seeds: [] };
|
|
439
|
-
if (baselineDigest === undefined && audits.every((audit) => audit.snapshotTaskDigest === task.qualification.taskInputDigest)) {
|
|
440
|
-
return { changed: false, safe: true, seeds: [] };
|
|
441
|
-
}
|
|
442
|
-
const candidateMap = new Map(task.qualification.candidates.map((candidate) => [candidate.candidateId, candidate]));
|
|
443
|
-
const currentConstraints = new Map(task.qualification.constraints.map((constraint) => [constraint.constraintId, constraint.digest]));
|
|
444
|
-
const snapshotsMatch = audits.every((audit) => audit.snapshotNonConstraintDigest === task.qualification.nonConstraintInputDigest);
|
|
445
|
-
const candidatesMatch = audits.every((audit) => audit.candidates.length === candidateMap.size
|
|
446
|
-
&& audit.candidates.every((row) => {
|
|
447
|
-
const current = candidateMap.get(row.candidateId);
|
|
448
|
-
return Boolean(current && row.status === current.status && row.impact === current.impact
|
|
449
|
-
&& row.evidence === current.evidence && row.constraintIds.join(',') === current.constraintIds.join(','));
|
|
450
|
-
}));
|
|
451
|
-
const changedConstraints = new Set();
|
|
452
|
-
let referencesValid = true;
|
|
453
|
-
for (const audit of audits) {
|
|
454
|
-
for (const dependency of audit.dependencies) {
|
|
455
|
-
const currentDigest = currentConstraints.get(dependency.constraintId);
|
|
456
|
-
if (!currentDigest)
|
|
457
|
-
referencesValid = false;
|
|
458
|
-
else if (currentDigest !== dependency.constraintDigest)
|
|
459
|
-
changedConstraints.add(dependency.constraintId);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
const safe = allAuditsPresent && snapshotsMatch && candidatesMatch && referencesValid && changedConstraints.size > 0;
|
|
463
|
-
if (!safe)
|
|
464
|
-
return { changed: true, safe: false, seeds: [] };
|
|
465
|
-
const seeds = new Set();
|
|
466
|
-
for (const audit of audits) {
|
|
467
|
-
if (audit.dependencies.some((dependency) => changedConstraints.has(dependency.constraintId)))
|
|
468
|
-
seeds.add(audit.name);
|
|
469
|
-
}
|
|
470
|
-
return { changed: true, safe: true, seeds: [...seeds] };
|
|
471
|
-
}
|
|
472
|
-
function invalidationMutationForCompletion(content, taskDir, family, artifact, timestamp, frontmatter) {
|
|
473
|
-
if (!['analyze', 'plan', 'code'].includes(family))
|
|
474
|
-
return { mutation: null };
|
|
475
|
-
const parsed = parseInvalidationDocument(content);
|
|
476
|
-
if (!parsed.ok)
|
|
477
|
-
return { error: parsed.message };
|
|
478
|
-
const downstream = {
|
|
479
|
-
analyze: ['review-analysis', 'plan', 'review-plan', 'code', 'review-code'],
|
|
480
|
-
plan: ['review-plan', 'code', 'review-code'],
|
|
481
|
-
code: ['review-code']
|
|
482
|
-
};
|
|
483
|
-
const qualificationFallback = ['analysis', 'review-analysis', 'plan', 'review-plan', 'code', 'review-code'];
|
|
484
|
-
const sourceFamily = family;
|
|
485
|
-
const sourceArtifactFamily = sourceFamily === 'analyze' ? 'analysis' : sourceFamily;
|
|
486
|
-
let receipts = [];
|
|
487
|
-
try {
|
|
488
|
-
receipts = parseArtifactReceipts(content).rows;
|
|
489
|
-
}
|
|
490
|
-
catch (error) {
|
|
491
|
-
return { error: error instanceof Error ? error.message : String(error) };
|
|
492
|
-
}
|
|
493
|
-
const inventory = fs.readdirSync(taskDir).flatMap((name) => {
|
|
494
|
-
const identity = parseArtifactName(name);
|
|
495
|
-
if (!identity || !ARTIFACT_FAMILIES.includes(identity.family))
|
|
496
|
-
return [];
|
|
497
|
-
try {
|
|
498
|
-
const stat = fs.lstatSync(path.join(taskDir, name));
|
|
499
|
-
if (!stat.isFile() || stat.isSymbolicLink())
|
|
500
|
-
return [];
|
|
501
|
-
return [{ family: identity.family, name, round: identity.round, sha256: sha256File(path.join(taskDir, name)) }];
|
|
502
|
-
}
|
|
503
|
-
catch (error) {
|
|
504
|
-
throw new Error(`cannot inspect invalidation artifact '${name}': ${error instanceof Error ? error.message : String(error)}`);
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
const nodeMap = new Map(inventory.map((node) => [`${node.family}/${node.name}`, node]));
|
|
508
|
-
let graphUsable = receipts.length > 0;
|
|
509
|
-
for (const receipt of receipts) {
|
|
510
|
-
const output = parseArtifactName(receipt.output);
|
|
511
|
-
const input = nodeMap.get(`${parseArtifactName(receipt.input)?.family}/${receipt.input}`);
|
|
512
|
-
if (!output || !nodeMap.has(`${output.family}/${receipt.output}`) || !input || input.sha256 !== receipt.inputSha256) {
|
|
513
|
-
graphUsable = false;
|
|
514
|
-
break;
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
if (graphUsable && receiptGraphHasCycle(receipts))
|
|
518
|
-
graphUsable = false;
|
|
519
|
-
if (inventory.some((node) => node.family !== 'analysis' && node.name !== artifact.name
|
|
520
|
-
&& !receipts.some((receipt) => receipt.output === node.name)))
|
|
521
|
-
graphUsable = false;
|
|
522
|
-
const selected = new Set();
|
|
523
|
-
if (graphUsable) {
|
|
524
|
-
const currentIdentity = parseArtifactName(artifact.name);
|
|
525
|
-
const previousName = currentIdentity && currentIdentity.round > 1 ? artifactName(sourceArtifactFamily, currentIdentity.round - 1) : null;
|
|
526
|
-
const previous = previousName ? inventory.find((node) => node.family === sourceArtifactFamily && node.name === previousName) : null;
|
|
527
|
-
const previousFact = previousName ? parseCompletionFacts(frontmatter.completion_facts).find((fact) => fact.output === previousName && fact.event === `${sourceFamily === 'analyze' ? 'analysis' : sourceFamily}.completed`) : null;
|
|
528
|
-
if (!previous || !previousFact || previousFact.outputSha256 !== previous.sha256)
|
|
529
|
-
graphUsable = false;
|
|
530
|
-
if (graphUsable && previous) {
|
|
531
|
-
selected.add(`${previous.family}/${previous.name}`);
|
|
532
|
-
let changed = true;
|
|
533
|
-
while (changed) {
|
|
534
|
-
changed = false;
|
|
535
|
-
for (const receipt of receipts) {
|
|
536
|
-
const consumer = `${parseArtifactName(receipt.output).family}/${receipt.output}`;
|
|
537
|
-
if (selected.has(`${parseArtifactName(receipt.input).family}/${receipt.input}`) && !selected.has(consumer)) {
|
|
538
|
-
selected.add(consumer);
|
|
539
|
-
changed = true;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
selected.delete(`${previous.family}/${previous.name}`);
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
const qualification = qualificationInvalidationSeeds(content, taskDir, inventory, typeof frontmatter.qualification_input_digest === 'string' ? frontmatter.qualification_input_digest : undefined);
|
|
547
|
-
let qualificationChange = qualification.changed;
|
|
548
|
-
if (qualificationChange && (!graphUsable || !qualification.safe))
|
|
549
|
-
graphUsable = false;
|
|
550
|
-
if (qualificationChange && graphUsable) {
|
|
551
|
-
for (const seed of qualification.seeds)
|
|
552
|
-
selected.add(`${parseArtifactName(seed)?.family}/${seed}`);
|
|
553
|
-
let changed = true;
|
|
554
|
-
while (changed) {
|
|
555
|
-
changed = false;
|
|
556
|
-
for (const receipt of receipts) {
|
|
557
|
-
const consumer = `${parseArtifactName(receipt.output).family}/${receipt.output}`;
|
|
558
|
-
if (selected.has(`${parseArtifactName(receipt.input).family}/${receipt.input}`) && !selected.has(consumer)) {
|
|
559
|
-
selected.add(consumer);
|
|
560
|
-
changed = true;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
const reasonCode = qualificationChange ? 'qualification-changed' : 'upstream-replaced';
|
|
566
|
-
const fallbackFamilies = qualificationChange ? qualificationFallback : downstream[sourceFamily];
|
|
567
|
-
const targetNodes = (graphUsable
|
|
568
|
-
? inventory.filter((node) => selected.has(`${node.family}/${node.name}`))
|
|
569
|
-
: inventory.filter((node) => fallbackFamilies.includes(node.family)))
|
|
570
|
-
.filter((node) => !(node.family === FAMILY[family].artifact && node.name === artifact.name));
|
|
571
|
-
const targets = targetNodes.flatMap((node) => {
|
|
572
|
-
const shapes = [
|
|
573
|
-
{ targetKind: 'artifact', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 }
|
|
574
|
-
];
|
|
575
|
-
for (const receipt of receipts.filter((candidate) => candidate.output === node.name)) {
|
|
576
|
-
shapes.push({ targetKind: 'receipt', targetFamily: node.family, targetArtifact: node.name, targetInput: receipt.input, targetRound: node.round, targetSha256: receipt.inputSha256 });
|
|
577
|
-
}
|
|
578
|
-
if (node.family.startsWith('review-'))
|
|
579
|
-
shapes.push({ targetKind: 'approval', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 });
|
|
580
|
-
if (node.family === 'review-code')
|
|
581
|
-
shapes.push({ targetKind: 'reviewed-snapshot', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 });
|
|
582
|
-
return shapes.map((targetShape) => ({ ...targetShape, targetId: targetIdFor('pending', targetShape), operationId: 'pending', status: 'pending', reasonCode, updatedAt: timestamp }));
|
|
583
|
-
});
|
|
584
|
-
if (targets.length === 0)
|
|
585
|
-
return { mutation: null };
|
|
586
|
-
const source = {
|
|
587
|
-
sourceFamily: lifecycleAction(family), sourceArtifact: artifact.name,
|
|
588
|
-
sourceRound: parseArtifactName(artifact.name)?.round ?? 1, sourceSha256: sha256File(artifact.path),
|
|
589
|
-
createdAt: timestamp, updatedAt: timestamp
|
|
590
|
-
};
|
|
591
|
-
const operation = createInvalidationOperation(source);
|
|
592
|
-
const normalizedTargets = targets.map((target) => ({
|
|
593
|
-
...target, operationId: operation.operationId,
|
|
594
|
-
targetId: targetIdFor(operation.operationId, target)
|
|
595
|
-
}));
|
|
596
|
-
const operationWithTotal = createInvalidationOperation(source, normalizedTargets);
|
|
597
|
-
const next = upsertInvalidation(parsed.document, operationWithTotal, normalizedTargets);
|
|
598
|
-
if (!next.ok)
|
|
599
|
-
return { error: next.message };
|
|
600
|
-
return { mutation: next.changed ? invalidationMutation(content, next.document) : null };
|
|
601
|
-
}
|
|
602
371
|
function reworkIntentMutationForCompletion(content, taskDir, family, artifact, timestamp) {
|
|
603
372
|
const parsed = parseReworkIntentDocument(content);
|
|
604
373
|
if (!parsed.ok)
|
|
@@ -606,23 +375,15 @@ function reworkIntentMutationForCompletion(content, taskDir, family, artifact, t
|
|
|
606
375
|
const hash = sha256File(artifact.path);
|
|
607
376
|
let next = parsed.intents;
|
|
608
377
|
if (family === 'analyze' || family === 'plan' || family === 'code') {
|
|
609
|
-
const hashes = Object.fromEntries(
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
try {
|
|
613
|
-
return [[name, sha256File(path.join(taskDir, name))]];
|
|
614
|
-
}
|
|
615
|
-
catch {
|
|
616
|
-
return [];
|
|
617
|
-
}
|
|
378
|
+
const hashes = Object.fromEntries(['review-analysis', 'review-plan', 'review-code'].flatMap((reviewFamily) => {
|
|
379
|
+
const inventory = inspectArtifactDirectory(taskDir, reviewFamily);
|
|
380
|
+
return inventory.status === 'ready' ? inventory.completed.map((review) => [review.name, sha256File(review.path)]) : [];
|
|
618
381
|
}));
|
|
619
382
|
const action = family === 'analyze' ? 'analysis' : family;
|
|
620
383
|
let target = action;
|
|
621
384
|
if (family === 'analyze') {
|
|
622
|
-
const previousAnalysis =
|
|
623
|
-
.
|
|
624
|
-
.filter((identity) => identity?.family === 'analysis' && identity.name !== artifact.name)
|
|
625
|
-
.sort((left, right) => right.round - left.round || left.name.localeCompare(right.name))[0];
|
|
385
|
+
const previousAnalysis = inspectArtifactDirectory(taskDir, 'analysis').completed
|
|
386
|
+
.filter((identity) => identity.name !== artifact.name).at(-1);
|
|
626
387
|
const pathState = previousAnalysis
|
|
627
388
|
? parseLifecyclePathDecision(fs.readFileSync(path.join(taskDir, previousAnalysis.name), 'utf8'))
|
|
628
389
|
: undefined;
|
|
@@ -764,23 +525,6 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
764
525
|
return failed(request, { code: 'TASK_READ_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
765
526
|
}
|
|
766
527
|
const initialParts = eventParts(request.event);
|
|
767
|
-
if (initialParts.phase === 'started' && !request.dryRun) {
|
|
768
|
-
const reconciled = reconcileTaskInvalidation(request.taskRef, { repoRoot: resolved.repoRoot });
|
|
769
|
-
if (reconciled.status === 'failed') {
|
|
770
|
-
return failed(request, {
|
|
771
|
-
code: 'EVENT_TRANSITION_INVALID',
|
|
772
|
-
message: `INVALIDATION_RECONCILE_FAILED: ${reconciled.error?.code ?? 'UNKNOWN'}: ${reconciled.error?.message ?? ''}`
|
|
773
|
-
}, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
774
|
-
}
|
|
775
|
-
if (reconciled.changed) {
|
|
776
|
-
try {
|
|
777
|
-
content = fs.readFileSync(resolved.taskMdPath, 'utf8');
|
|
778
|
-
}
|
|
779
|
-
catch (error) {
|
|
780
|
-
return failed(request, { code: 'TASK_READ_FAILED', message: String(error) }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath });
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
528
|
let frontmatter;
|
|
785
529
|
try {
|
|
786
530
|
frontmatter = parseTypedTaskFrontmatter(content);
|
|
@@ -946,8 +690,7 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
946
690
|
const safetyFailure = capability.reasonCode === 'TASK_NOT_ACTIVE'
|
|
947
691
|
|| capability.reasonCode === 'LIFECYCLE_EXECUTION_OPEN';
|
|
948
692
|
if (!capability.allowed && (normalized.initiator === 'orchestrator' || safetyFailure)) {
|
|
949
|
-
|
|
950
|
-
return failed(normalized, { code, message: `${capability.reasonCode}: ${capability.evidence.join(', ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
693
|
+
return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${capability.reasonCode}: ${capability.evidence.join(', ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
951
694
|
}
|
|
952
695
|
}
|
|
953
696
|
const findingCountError = validateReviewFindingCounts(normalized, content, eventIdentity.family, completedArtifact?.path ?? null);
|
|
@@ -985,7 +728,6 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
985
728
|
}
|
|
986
729
|
let completionReceipts = [];
|
|
987
730
|
let currentFact = null;
|
|
988
|
-
let completionInvalidation = null;
|
|
989
731
|
let completionRework = null;
|
|
990
732
|
if (eventIdentity.phase === 'completed' && completedArtifact) {
|
|
991
733
|
const receipt = buildCompletionReceipt(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp, frontmatter, normalized);
|
|
@@ -1006,10 +748,6 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
1006
748
|
return successNoOp(normalized, resolved.taskId, resolved.taskMdPath, currentStep, eventIdentity, completionReceipts[0]?.completedAt ?? metadata.timestamp, frontmatter, artifactContext);
|
|
1007
749
|
}
|
|
1008
750
|
try {
|
|
1009
|
-
const invalidation = invalidationMutationForCompletion(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp, frontmatter);
|
|
1010
|
-
if ('error' in invalidation)
|
|
1011
|
-
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: invalidation.error }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
1012
|
-
completionInvalidation = invalidation.mutation;
|
|
1013
751
|
const rework = reworkIntentMutationForCompletion(content, resolved.taskDir, eventIdentity.family, completedArtifact, metadata.timestamp);
|
|
1014
752
|
if ('error' in rework)
|
|
1015
753
|
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: rework.error }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
@@ -1104,8 +842,6 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
1104
842
|
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
1105
843
|
}
|
|
1106
844
|
}
|
|
1107
|
-
if (completionInvalidation)
|
|
1108
|
-
mutations.push(completionInvalidation);
|
|
1109
845
|
if (completionRework)
|
|
1110
846
|
mutations.push(completionRework);
|
|
1111
847
|
if (eventIdentity.phase === 'completed' && normalized.implementationInput) {
|
|
@@ -1123,9 +859,7 @@ function applyTaskEventUnlocked(request, options = {}) {
|
|
|
1123
859
|
});
|
|
1124
860
|
}
|
|
1125
861
|
mutations.push({ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: section.heading, body });
|
|
1126
|
-
const
|
|
1127
|
-
&& ['analyze', 'plan', 'code'].includes(eventIdentity.family);
|
|
1128
|
-
const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, invalidationContext: sourceCompletion ? 'source-completion' : 'standard', metadataProvider: () => metadata });
|
|
862
|
+
const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
|
|
1129
863
|
if (result.status === 'failed')
|
|
1130
864
|
return failed(normalized, result.error, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
|
|
1131
865
|
if (!normalized.dryRun && orchestrationCompletion) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { pathIncludes } from './lifecycle-path.js';
|
|
2
|
+
function expectedExecutionInputFamilies(stage, pathState) {
|
|
3
|
+
if (pathState.status !== 'valid')
|
|
4
|
+
return [];
|
|
5
|
+
const input = stage === 'plan' ? 'analysis' : pathIncludes(pathState, 'plan') ? 'plan' : 'analysis';
|
|
6
|
+
const review = input === 'plan' ? 'review-plan' : 'review-analysis';
|
|
7
|
+
return [input, ...(pathIncludes(pathState, review) ? [review] : [])];
|
|
8
|
+
}
|
|
9
|
+
function executionInputsMatchLatest(stage, pathState, latest, captured) {
|
|
10
|
+
const expected = expectedExecutionInputFamilies(stage, pathState);
|
|
11
|
+
return expected.every((family) => Boolean(latest[family] && captured.includes(latest[family])));
|
|
12
|
+
}
|
|
13
|
+
export { expectedExecutionInputFamilies, executionInputsMatchLatest };
|
|
14
|
+
//# sourceMappingURL=execution-inputs.js.map
|