@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.
Files changed (163) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/bin/internal-cli.js +0 -6
  4. package/dist/lib/agent-clients/custom-tool-invocations.js +92 -0
  5. package/dist/lib/agent-clients/next-steps.js +1 -1
  6. package/dist/lib/agent-clients/reconcile.js +3 -3
  7. package/dist/lib/agent-clients/schema.js +18 -10
  8. package/dist/lib/git/workflow.js +1 -1
  9. package/dist/lib/init.js +2 -2
  10. package/dist/lib/internal/agent-client.js +3 -3
  11. package/dist/lib/internal/cli-route-inventory.js +0 -3
  12. package/dist/lib/internal/sandbox-control.js +30 -5
  13. package/dist/lib/internal/task-finalization.js +14 -23
  14. package/dist/lib/internal/task-operation-registry.js +2 -3
  15. package/dist/lib/internal/task-platform-recovery.js +9 -4
  16. package/dist/lib/platform/completion-backfill.js +2 -1
  17. package/dist/lib/platform/context.js +4 -2
  18. package/dist/lib/platform/github-client.js +20 -17
  19. package/dist/lib/platform/github-provider.js +42 -22
  20. package/dist/lib/platform/github-release-notes.js +4 -2
  21. package/dist/lib/platform/in-label-sync.js +2 -1
  22. package/dist/lib/platform/issue-comments.js +13 -9
  23. package/dist/lib/platform/operation-coordinator.js +1 -1
  24. package/dist/lib/platform/pr-review.js +2 -1
  25. package/dist/lib/platform/provider-bridge.js +4 -5
  26. package/dist/lib/platform/provider-contract.d.ts +3 -6
  27. package/dist/lib/platform/provider-contract.js +3 -15
  28. package/dist/lib/platform/provider-validation.js +9 -4
  29. package/dist/lib/platform/pull-requests.js +4 -2
  30. package/dist/lib/sandbox/control/client.js +54 -6
  31. package/dist/lib/sandbox/control/executor.js +8 -3
  32. package/dist/lib/sandbox/recovery.js +1 -22
  33. package/dist/lib/sandbox/removal.js +0 -1
  34. package/dist/lib/sandbox/tools.js +2 -0
  35. package/dist/lib/task/artifact-command.js +11 -1
  36. package/dist/lib/task/artifact-lifecycle.js +119 -62
  37. package/dist/lib/task/artifact-selection.js +1 -1
  38. package/dist/lib/task/capabilities.js +55 -21
  39. package/dist/lib/task/commands/status.js +0 -27
  40. package/dist/lib/task/commit-identity.js +22 -7
  41. package/dist/lib/task/commit-intent.js +67 -26
  42. package/dist/lib/task/commit-operation.js +19 -8
  43. package/dist/lib/task/completion-facts.js +32 -10
  44. package/dist/lib/task/control-authority.js +2 -4
  45. package/dist/lib/task/current-contract.js +1 -5
  46. package/dist/lib/task/events.js +8 -274
  47. package/dist/lib/task/execution-inputs.js +14 -0
  48. package/dist/lib/task/finalization-envelope.js +4 -0
  49. package/dist/lib/task/finalization.js +100 -129
  50. package/dist/lib/task/frontmatter.js +1 -1
  51. package/dist/lib/task/ledger-intents.js +4 -7
  52. package/dist/lib/task/orchestration.js +11 -10
  53. package/dist/lib/task/platform-operation-journal.js +17 -10
  54. package/dist/lib/task/platform-operation-recovery.js +95 -28
  55. package/dist/lib/task/review-fingerprint.js +4 -26
  56. package/dist/lib/task/verification-engine.js +95 -6
  57. package/dist/lib/task/verification.js +0 -1
  58. package/dist/lib/task/write.js +0 -11
  59. package/dist/lib/update.js +2 -2
  60. package/dist/lifecycle-build-manifest.json +3 -3
  61. package/lib/agent-clients/custom-tool-invocations.ts +129 -0
  62. package/lib/agent-clients/next-steps.ts +3 -3
  63. package/lib/agent-clients/reconcile.ts +3 -3
  64. package/lib/agent-clients/schema.ts +18 -10
  65. package/lib/git/workflow.ts +1 -1
  66. package/lib/init.ts +2 -2
  67. package/lib/internal/agent-client.ts +3 -3
  68. package/lib/internal/cli-route-inventory.ts +0 -2
  69. package/lib/internal/sandbox-control.ts +39 -6
  70. package/lib/internal/task-finalization.ts +16 -24
  71. package/lib/internal/task-operation-registry.ts +2 -3
  72. package/lib/internal/task-platform-recovery.ts +9 -4
  73. package/lib/platform/completion-backfill.ts +2 -1
  74. package/lib/platform/context.ts +8 -4
  75. package/lib/platform/github-client.ts +24 -20
  76. package/lib/platform/github-provider.ts +47 -26
  77. package/lib/platform/github-release-notes.ts +5 -3
  78. package/lib/platform/in-label-sync.ts +2 -1
  79. package/lib/platform/issue-comments.ts +14 -9
  80. package/lib/platform/operation-coordinator.ts +1 -1
  81. package/lib/platform/pr-review.ts +2 -1
  82. package/lib/platform/provider-bridge.ts +10 -9
  83. package/lib/platform/provider-contract.ts +6 -21
  84. package/lib/platform/provider-loader.ts +7 -6
  85. package/lib/platform/provider-validation.ts +30 -8
  86. package/lib/platform/pull-requests.ts +4 -2
  87. package/lib/platform/repository-metadata.ts +3 -2
  88. package/lib/platform/security-alerts.ts +1 -1
  89. package/lib/platform/types.ts +2 -0
  90. package/lib/sandbox/control/client.ts +57 -6
  91. package/lib/sandbox/control/executor.ts +8 -3
  92. package/lib/sandbox/recovery.ts +0 -25
  93. package/lib/sandbox/removal.ts +2 -10
  94. package/lib/sandbox/tool-types.ts +1 -0
  95. package/lib/sandbox/tools.ts +2 -0
  96. package/lib/task/artifact-command.ts +10 -1
  97. package/lib/task/artifact-lifecycle.ts +100 -52
  98. package/lib/task/artifact-selection.ts +1 -1
  99. package/lib/task/capabilities.ts +47 -24
  100. package/lib/task/commands/status.ts +0 -31
  101. package/lib/task/commit-identity.ts +24 -7
  102. package/lib/task/commit-intent.ts +58 -24
  103. package/lib/task/commit-operation.ts +17 -8
  104. package/lib/task/completion-facts.ts +31 -9
  105. package/lib/task/control-authority.ts +1 -4
  106. package/lib/task/current-contract.ts +1 -6
  107. package/lib/task/events.ts +8 -247
  108. package/lib/task/execution-inputs.ts +25 -0
  109. package/lib/task/finalization-envelope.ts +21 -0
  110. package/lib/task/finalization.ts +101 -123
  111. package/lib/task/frontmatter.ts +1 -1
  112. package/lib/task/ledger-intents.ts +4 -7
  113. package/lib/task/orchestration.ts +11 -17
  114. package/lib/task/platform-operation-journal.ts +18 -11
  115. package/lib/task/platform-operation-recovery.ts +90 -31
  116. package/lib/task/review-fingerprint.ts +4 -26
  117. package/lib/task/verification-engine.ts +103 -9
  118. package/lib/task/verification.ts +1 -2
  119. package/lib/task/write.ts +0 -19
  120. package/lib/update.ts +2 -3
  121. package/package.json +1 -1
  122. package/templates/.agents/README.en.md +2 -50
  123. package/templates/.agents/README.zh-CN.md +2 -50
  124. package/templates/.agents/rules/commit-and-pr.en.md +5 -5
  125. package/templates/.agents/rules/commit-and-pr.zh-CN.md +5 -5
  126. package/templates/.agents/rules/decision-qualification.en.md +1 -1
  127. package/templates/.agents/rules/decision-qualification.zh-CN.md +1 -1
  128. package/templates/.agents/rules/next-step-output.en.md +1 -1
  129. package/templates/.agents/rules/next-step-output.zh-CN.md +1 -1
  130. package/templates/.agents/scripts/lib/agent-infra-package.js +0 -7
  131. package/templates/.agents/skills/code-task/SKILL.en.md +25 -9
  132. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +26 -9
  133. package/templates/.agents/skills/code-task/reference/code-rules.en.md +1 -1
  134. package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +1 -1
  135. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +5 -16
  136. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +5 -16
  137. package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
  138. package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
  139. package/templates/.agents/skills/commit/SKILL.en.md +1 -1
  140. package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
  141. package/templates/.agents/skills/complete-task/SKILL.en.md +15 -12
  142. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -10
  143. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +1 -1
  144. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +1 -1
  145. package/templates/.agents/skills/review-code/SKILL.en.md +1 -1
  146. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +1 -1
  147. package/templates/.agents/skills/review-code/reference/output-templates.en.md +15 -6
  148. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +15 -6
  149. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +2 -2
  150. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +2 -2
  151. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +2 -268
  152. package/templates/.agents/templates/task.zh-CN.md +0 -12
  153. package/templates/.github/workflows/pr-label.yml +1 -2
  154. package/dist/lib/agent-clients/custom-tuis.js +0 -99
  155. package/dist/lib/internal/task-invalidation.js +0 -63
  156. package/dist/lib/task/intermediate-cleanup.js +0 -327
  157. package/dist/lib/task/invalidation-command.js +0 -88
  158. package/dist/lib/task/invalidation.js +0 -242
  159. package/lib/agent-clients/custom-tuis.ts +0 -149
  160. package/lib/internal/task-invalidation.ts +0 -41
  161. package/lib/task/intermediate-cleanup.ts +0 -393
  162. package/lib/task/invalidation-command.ts +0 -88
  163. package/lib/task/invalidation.ts +0 -313
@@ -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 { ARTIFACT_FAMILIES, parseQualificationAudit, parseTaskQualification } from './qualification-audit.js';
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(fs.readdirSync(taskDir).flatMap((name) => {
610
- if (!/^review-(?:analysis|plan|code)(?:-r\d+)?\.md$/.test(name))
611
- return [];
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 = fs.readdirSync(taskDir)
623
- .map((name) => parseArtifactName(name))
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
- const code = capability.reasonCode === 'INVALIDATION_INCOMPLETE' ? 'TASK_INVALIDATION_BLOCKED' : 'EVENT_TRANSITION_INVALID';
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 sourceCompletion = eventIdentity.phase === 'completed'
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
@@ -0,0 +1,4 @@
1
+ export function serializeTaskFinalizationEnvelope(envelope) {
2
+ return `${JSON.stringify({ version: 2, ...envelope })}\n`;
3
+ }
4
+ //# sourceMappingURL=finalization-envelope.js.map