@fitlab-ai/agent-infra 0.9.11 → 0.9.12

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 (193) hide show
  1. package/README.md +6 -6
  2. package/README.zh-CN.md +6 -6
  3. package/dist/bin/internal-cli.js +5 -0
  4. package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +71 -10
  5. package/dist/lib/defaults.json +4 -0
  6. package/dist/lib/git/workflow.js +43 -1
  7. package/dist/lib/init.js +1 -0
  8. package/dist/lib/internal/git-workflow.js +8 -1
  9. package/dist/lib/internal/platform-pr.js +8 -2
  10. package/dist/lib/internal/task-delivery.js +59 -0
  11. package/dist/lib/platform/github-client.js +7 -1
  12. package/dist/lib/platform/pr-checks.js +8 -5
  13. package/dist/lib/platform/pr-summary.js +12 -8
  14. package/dist/lib/platform/pull-requests.js +393 -91
  15. package/dist/lib/platform/verification-required.js +13 -2
  16. package/dist/lib/platform/verification-sync.js +9 -4
  17. package/dist/lib/pr-review/evidence-grading.js +12 -4
  18. package/dist/lib/sandbox/config.js +5 -0
  19. package/dist/lib/sandbox/control/lifecycle.js +29 -7
  20. package/dist/lib/server/process-state.js +2 -2
  21. package/dist/lib/task/artifact-lifecycle.js +2 -2
  22. package/dist/lib/task/commit-intent.js +100 -0
  23. package/dist/lib/task/commit-operation.js +195 -101
  24. package/dist/lib/task/create.js +33 -7
  25. package/dist/lib/task/decision-details.js +3 -48
  26. package/dist/lib/task/delivery-target.js +97 -0
  27. package/dist/lib/task/delivery.js +153 -0
  28. package/dist/lib/task/human-override.js +5 -2
  29. package/dist/lib/task/lifecycle.js +106 -9
  30. package/dist/lib/task/orchestration.js +55 -62
  31. package/dist/lib/task/pr-delivery-fact.js +182 -0
  32. package/dist/lib/task/review-finalization.js +4 -8
  33. package/dist/lib/task/review-fingerprint.js +8 -0
  34. package/dist/lib/task/verification-engine.js +48 -24
  35. package/dist/lib/task/verification-review.js +1 -1
  36. package/dist/lib/update.js +9 -0
  37. package/dist/lifecycle-build-manifest.json +3 -3
  38. package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +105 -10
  39. package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +12 -1
  40. package/lib/defaults.json +4 -0
  41. package/lib/git/workflow.ts +38 -1
  42. package/lib/init.ts +3 -0
  43. package/lib/internal/git-workflow.ts +7 -1
  44. package/lib/internal/platform-pr.ts +8 -1
  45. package/lib/internal/task-delivery.ts +53 -0
  46. package/lib/platform/github-client.ts +8 -1
  47. package/lib/platform/pr-checks.ts +7 -5
  48. package/lib/platform/pr-summary.ts +10 -7
  49. package/lib/platform/pull-requests.ts +425 -87
  50. package/lib/platform/verification-required.ts +12 -2
  51. package/lib/platform/verification-sync.ts +9 -4
  52. package/lib/pr-review/evidence-grading.ts +7 -4
  53. package/lib/sandbox/config.ts +7 -0
  54. package/lib/sandbox/control/lifecycle.ts +30 -8
  55. package/lib/server/process-state.ts +2 -2
  56. package/lib/task/artifact-lifecycle.ts +2 -2
  57. package/lib/task/commit-intent.ts +137 -0
  58. package/lib/task/commit-operation.ts +174 -87
  59. package/lib/task/create.ts +34 -9
  60. package/lib/task/decision-details.ts +2 -62
  61. package/lib/task/delivery-target.ts +130 -0
  62. package/lib/task/delivery.ts +160 -0
  63. package/lib/task/human-override.ts +5 -2
  64. package/lib/task/lifecycle.ts +93 -4
  65. package/lib/task/orchestration.ts +62 -65
  66. package/lib/task/pr-delivery-fact.ts +254 -0
  67. package/lib/task/review-finalization.ts +4 -14
  68. package/lib/task/review-fingerprint.ts +10 -0
  69. package/lib/task/verification-engine.ts +45 -28
  70. package/lib/task/verification-review.ts +2 -0
  71. package/lib/update.ts +10 -0
  72. package/package.json +1 -1
  73. package/templates/.agents/rules/README.en.md +4 -2
  74. package/templates/.agents/rules/README.zh-CN.md +4 -2
  75. package/templates/.agents/rules/create-issue.en.md +11 -2
  76. package/templates/.agents/rules/create-issue.zh-CN.md +24 -2
  77. package/templates/.agents/rules/issue-pr-commands.en.md +4 -17
  78. package/templates/.agents/rules/issue-sync.en.md +26 -5
  79. package/templates/.agents/rules/issue-sync.zh-CN.md +62 -5
  80. package/templates/.agents/rules/label-milestone-setup.en.md +15 -2
  81. package/templates/.agents/rules/label-milestone-setup.zh-CN.md +15 -2
  82. package/templates/.agents/rules/local-artifact-repair.en.md +46 -0
  83. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +46 -0
  84. package/templates/.agents/rules/milestone-inference.en.md +12 -2
  85. package/templates/.agents/rules/milestone-inference.zh-CN.md +25 -3
  86. package/templates/.agents/rules/pr-sync.en.md +22 -13
  87. package/templates/.agents/rules/pr-sync.zh-CN.md +22 -1
  88. package/templates/.agents/rules/release-commands.en.md +42 -3
  89. package/templates/.agents/rules/release-commands.zh-CN.md +42 -3
  90. package/templates/.agents/rules/security-alerts.en.md +17 -2
  91. package/templates/.agents/rules/security-alerts.zh-CN.md +17 -2
  92. package/templates/.agents/rules/sync-content-generation.en.md +8 -0
  93. package/templates/.agents/rules/sync-content-generation.zh-CN.md +8 -0
  94. package/templates/.agents/rules/task-management.en.md +1 -1
  95. package/templates/.agents/rules/task-management.zh-CN.md +1 -1
  96. package/templates/.agents/scripts/security-alerts.github.sh +151 -0
  97. package/templates/.agents/scripts/security-alerts.sh +31 -0
  98. package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -0
  99. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -0
  100. package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
  101. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
  102. package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
  103. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
  104. package/templates/.agents/skills/code-task/SKILL.en.md +5 -2
  105. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +6 -3
  106. package/templates/.agents/skills/commit/SKILL.en.md +3 -3
  107. package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -3
  108. package/templates/.agents/skills/commit/config/verify.json +1 -1
  109. package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +3 -3
  110. package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +3 -3
  111. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  112. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  113. package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -2
  114. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -2
  115. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -1
  116. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -1
  117. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  118. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  119. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  120. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  121. package/templates/.agents/skills/complete-task/SKILL.en.md +10 -10
  122. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -10
  123. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +2 -2
  124. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +2 -2
  125. package/templates/.agents/skills/create-pr/SKILL.en.md +4 -4
  126. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +4 -4
  127. package/templates/.agents/skills/create-task/SKILL.en.md +1 -0
  128. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -0
  129. package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
  130. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
  131. package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
  132. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
  133. package/templates/.agents/skills/init-labels/SKILL.en.md +9 -10
  134. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +9 -10
  135. package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +57 -1
  136. package/templates/.agents/skills/init-labels/scripts/init-labels.sh +27 -1
  137. package/templates/.agents/skills/init-milestones/SKILL.en.md +3 -5
  138. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +3 -5
  139. package/templates/.agents/skills/plan-task/SKILL.en.md +1 -0
  140. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +1 -0
  141. package/templates/.agents/skills/review-analysis/SKILL.en.md +4 -3
  142. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +4 -3
  143. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +18 -0
  144. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +18 -0
  145. package/templates/.agents/skills/review-code/SKILL.en.md +7 -6
  146. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +7 -6
  147. package/templates/.agents/skills/review-code/reference/output-templates.en.md +19 -1
  148. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +19 -1
  149. package/templates/.agents/skills/review-code/reference/report-template.en.md +4 -2
  150. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +4 -2
  151. package/templates/.agents/skills/review-plan/SKILL.en.md +4 -3
  152. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +4 -3
  153. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +18 -0
  154. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +18 -0
  155. package/templates/.agents/skills/review-pr/SKILL.en.md +1 -0
  156. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +1 -0
  157. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +2 -2
  158. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +2 -2
  159. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -0
  160. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -0
  161. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  162. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  163. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +4 -0
  164. package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
  165. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
  166. package/templates/.agents/templates/task.en.md +5 -1
  167. package/templates/.agents/templates/task.zh-CN.md +5 -1
  168. package/templates/.agents/workflows/bug-fix.en.yaml +9 -8
  169. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +9 -8
  170. package/templates/.agents/workflows/feature-development.en.yaml +9 -8
  171. package/templates/.agents/workflows/feature-development.zh-CN.yaml +9 -8
  172. package/templates/.agents/workflows/refactoring.en.yaml +9 -8
  173. package/templates/.agents/workflows/refactoring.zh-CN.yaml +9 -8
  174. package/templates/.agents/rules/create-issue.github.en.md +0 -14
  175. package/templates/.agents/rules/create-issue.github.zh-CN.md +0 -27
  176. package/templates/.agents/rules/issue-pr-commands.github.en.md +0 -34
  177. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +0 -49
  178. package/templates/.agents/rules/issue-sync.github.en.md +0 -40
  179. package/templates/.agents/rules/issue-sync.github.zh-CN.md +0 -76
  180. package/templates/.agents/rules/label-milestone-setup.github.en.md +0 -60
  181. package/templates/.agents/rules/label-milestone-setup.github.zh-CN.md +0 -60
  182. package/templates/.agents/rules/milestone-inference.github.en.md +0 -15
  183. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +0 -27
  184. package/templates/.agents/rules/pr-checks-commands.github.en.md +0 -18
  185. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +0 -34
  186. package/templates/.agents/rules/pr-sync.github.en.md +0 -43
  187. package/templates/.agents/rules/pr-sync.github.zh-CN.md +0 -69
  188. package/templates/.agents/rules/release-commands.github.en.md +0 -44
  189. package/templates/.agents/rules/release-commands.github.zh-CN.md +0 -44
  190. package/templates/.agents/rules/security-alerts.github.en.md +0 -43
  191. package/templates/.agents/rules/security-alerts.github.zh-CN.md +0 -43
  192. /package/templates/.agents/rules/{issue-fields.github.en.md → issue-fields.en.md} +0 -0
  193. /package/templates/.agents/rules/{issue-fields.github.zh-CN.md → issue-fields.zh-CN.md} +0 -0
@@ -5,6 +5,7 @@ import { hasPlatformCapability } from "./adapters.js";
5
5
  import { inspectRequiredChecks } from "./pr-checks.js";
6
6
  import { resolvePlatformContext } from "./context.js";
7
7
  import { resolveReviewedHeadRelation } from "./merged-pr-equivalence.js";
8
+ import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
8
9
  const CHECK_TYPE = "required-checks";
9
10
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
10
11
  function validPrNumber(value) {
@@ -30,7 +31,13 @@ function readHead(repoRoot) {
30
31
  }
31
32
  export function evaluateRequiredChecks(context, shared) {
32
33
  const { metadata, localHead, inspection, prFlow } = context;
33
- if (prFlow === "disabled" || metadata.pr_status === "skipped" || !validPrNumber(metadata.pr_number)) {
34
+ const factRead = readPrDeliveryFact(metadata);
35
+ if (factRead.status === "invalid") {
36
+ return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
37
+ }
38
+ const fact = factRead.status === "valid" ? factRead.fact : null;
39
+ const prNumber = fact?.state === "bound" ? fact.identity.number : null;
40
+ if (prFlow === "disabled" || fact?.state === "skipped" || !validPrNumber(prNumber)) {
34
41
  return shared.passResult(CHECK_TYPE, "Skipped: required checks are not applicable to this task");
35
42
  }
36
43
  const reviewedHead = String(metadata.last_reviewed_commit || "");
@@ -78,7 +85,11 @@ export function check({ taskDir }, shared) {
78
85
  if (!task.ok)
79
86
  return shared.failResult(CHECK_TYPE, task.message);
80
87
  const prFlow = readPrFlow(shared.repoRoot);
81
- if (prFlow === "disabled" || task.metadata.pr_status === "skipped" || !validPrNumber(task.metadata.pr_number)) {
88
+ const factRead = readPrDeliveryFact(task.metadata);
89
+ if (factRead.status === "invalid")
90
+ return shared.failResult(CHECK_TYPE, factRead.error.message, "check_failed");
91
+ const bound = factRead.status === "valid" && factRead.fact.state === "bound";
92
+ if (prFlow === "disabled" || (factRead.status === "valid" && factRead.fact.state === "skipped") || !bound) {
82
93
  return evaluateRequiredChecks({ metadata: task.metadata, localHead: null, inspection: null, prFlow }, shared);
83
94
  }
84
95
  const platform = resolvePlatformContext({ cwd: shared.repoRoot });
@@ -9,6 +9,7 @@ import { inspectGitHubIssueMetadata, requirementSectionAnchors } from "./issues.
9
9
  import { listRemoteComments } from "./issue-comments.js";
10
10
  import { taskTypeLabel } from "./metadata-labels.js";
11
11
  import { inspectGitHubPullRequest } from "./pull-requests.js";
12
+ import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
12
13
  const CHECK_TYPE = "platform-sync";
13
14
  const VERSION_LINE_REGEX = /^[0-9]+\.[0-9]+\.x$/;
14
15
  const FRONTMATTER_FIELD_MAP = {
@@ -127,12 +128,16 @@ function buildSyncContext({ taskDir, config, artifactFile }) {
127
128
  return { earlyReturn: failResult(CHECK_TYPE, task.message) };
128
129
  }
129
130
  const issueNumber = parseIssueNumber(task.metadata.issue_number);
130
- const prNumber = parsePrNumber(task.metadata.pr_number);
131
+ const fact = readPrDeliveryFact(task.metadata);
132
+ if (fact.status === "invalid") {
133
+ return { earlyReturn: failResult(CHECK_TYPE, fact.error.message, "check_failed") };
134
+ }
135
+ const prNumber = fact.status === "valid" && fact.fact.state === "bound" ? fact.fact.identity.number : null;
131
136
  if (config.when === "issue_number_exists" && !issueNumber) {
132
137
  return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no issue_number") };
133
138
  }
134
- if (config.when === "pr_number_exists" && !prNumber) {
135
- return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no pr_number") };
139
+ if (config.when === "pr_fact_bound" && !prNumber) {
140
+ return { earlyReturn: passResult(CHECK_TYPE, "Skipped: task has no verified bound pull request") };
136
141
  }
137
142
  if (!issueNumber) {
138
143
  return { earlyReturn: passResult(CHECK_TYPE, "Skipped: platform-sync not required for this task") };
@@ -276,7 +281,7 @@ function fetchRemoteData(context) {
276
281
  if (context.prMarker) {
277
282
  if (!context.prNumber) {
278
283
  return {
279
- earlyReturn: failResult(CHECK_TYPE, "Expected a valid pr_number for PR comment verification", "check_failed")
284
+ earlyReturn: failResult(CHECK_TYPE, "Expected a verified bound pull request for PR comment verification", "check_failed")
280
285
  };
281
286
  }
282
287
  const prCommentsResult = listRemoteComments(githubClient, context.upstreamRepo, context.prNumber, context.taskDir);
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { parseTaskFrontmatter } from '../task/frontmatter.js';
3
+ import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
4
+ import { readPrDeliveryFact } from '../task/pr-delivery-fact.js';
4
5
  export class HostResolutionError extends Error {
5
6
  code;
6
7
  constructor(code, message) {
@@ -38,7 +39,7 @@ export function extractClosingIssueNumbers(body) {
38
39
  /**
39
40
  * Scan `.agents/workspace/active/{task-id}/task.md` files for tasks bound to the
40
41
  * PR number or to one of the PR's closing issues. A task is emitted at most once;
41
- * a direct `pr_number` hit takes priority over the issue-number reverse lookup.
42
+ * a verified fact identity hit takes priority over the issue-number reverse lookup.
42
43
  */
43
44
  export function collectHostCandidates(input) {
44
45
  const activeRoot = path.join(input.workspaceRoot, '.agents', 'workspace', 'active');
@@ -62,9 +63,16 @@ export function collectHostCandidates(input) {
62
63
  catch {
63
64
  continue;
64
65
  }
65
- const frontmatter = parseTaskFrontmatter(content);
66
+ let frontmatter;
67
+ try {
68
+ frontmatter = parseTypedTaskFrontmatter(content);
69
+ }
70
+ catch {
71
+ continue;
72
+ }
66
73
  const issueNumber = toPositiveNumber(frontmatter.issue_number);
67
- const prNumber = toPositiveNumber(frontmatter.pr_number);
74
+ const fact = readPrDeliveryFact(frontmatter);
75
+ const prNumber = fact.status === 'valid' && fact.fact.state === 'bound' ? fact.fact.identity.number : null;
68
76
  if (prNumber === input.prNumber) {
69
77
  candidates.push({ taskId: entry.name, taskDir, issueNumber, prNumber });
70
78
  }
@@ -67,6 +67,7 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
67
67
  const agentClients = normalizeAgentClients(airc);
68
68
  const defaults = cloneDefaults();
69
69
  const sandbox = airc.sandbox ?? {};
70
+ const delivery = airc.delivery ?? {};
70
71
  const engine = validateSandboxEngine(sandbox.engine ?? defaults.engine, { platformFn });
71
72
  const project = airc.project;
72
73
  if (!project || typeof project !== 'string') {
@@ -111,6 +112,10 @@ export function loadConfig({ platformFn = platform, writeStderr = (chunk) => pro
111
112
  tools,
112
113
  customTools,
113
114
  agentClientState: agentClients.state,
115
+ delivery: {
116
+ remote: typeof delivery.remote === 'string' ? delivery.remote : 'origin',
117
+ baseRef: typeof delivery.baseRef === 'string' ? delivery.baseRef : 'main'
118
+ },
114
119
  refreshIntervalDays: asNonNegativeIntegerOrDefault(sandbox.refreshIntervalDays, defaults.refreshIntervalDays),
115
120
  dockerfile,
116
121
  vm: {
@@ -448,25 +448,27 @@ function readSandboxControlManifestValue(manifestPath) {
448
448
  'mode', 'processingDir', 'project', 'publicStatusDir', 'repoRoot', 'runtimeDir',
449
449
  'taskId', 'token', 'worktreeRoot'
450
450
  ];
451
- if ('version' in candidate || typeof candidate.runtimeDir !== 'string'
452
- || Object.keys(manifest).sort().join(',') !== expectedKeys.sort().join(',')) {
453
- throw new Error('SANDBOX_CONTROL_MANIFEST_REBUILD_REQUIRED: container-only recreation/rebuild is required');
451
+ if (Object.keys(manifest).sort().join(',') !== expectedKeys.sort().join(',')) {
452
+ throw new Error('SANDBOX_CONTROL_MANIFEST_INVALID');
454
453
  }
455
454
  if (typeof candidate.containerIdentity !== 'object' || candidate.containerIdentity === null
456
455
  || Array.isArray(candidate.containerIdentity))
457
456
  throw new Error('SANDBOX_CONTROL_MANIFEST_INVALID');
458
457
  const containerIdentity = candidate.containerIdentity;
459
- if (typeof candidate.engine !== 'string' || candidate.engine.length === 0
458
+ if (Object.keys(containerIdentity).sort().join(',') !== 'id,labels'
459
+ || typeof candidate.engine !== 'string' || candidate.engine.length === 0
460
460
  || typeof candidate.repoRoot !== 'string' || typeof candidate.worktreeRoot !== 'string'
461
461
  || typeof candidate.project !== 'string' || typeof candidate.container !== 'string'
462
462
  || typeof containerIdentity.id !== 'string' || containerIdentity.id.length === 0
463
463
  || typeof containerIdentity.labels !== 'object' || containerIdentity.labels === null
464
464
  || Array.isArray(containerIdentity.labels)
465
465
  || Object.values(containerIdentity.labels).some((value) => typeof value !== 'string')
466
- || typeof candidate.branch !== 'string' || !['task-bound', 'branch-only'].includes(candidate.mode ?? '')
466
+ || typeof candidate.branch !== 'string'
467
+ || (candidate.mode !== 'task-bound' && candidate.mode !== 'branch-only')
467
468
  || (candidate.taskId !== null && typeof candidate.taskId !== 'string')
468
469
  || typeof candidate.channelDir !== 'string' || typeof candidate.publicStatusDir !== 'string'
469
- || typeof candidate.processingDir !== 'string' || typeof candidate.token !== 'string'
470
+ || typeof candidate.processingDir !== 'string' || typeof candidate.runtimeDir !== 'string'
471
+ || typeof candidate.token !== 'string'
470
472
  || typeof candidate.generation !== 'string'
471
473
  || (candidate.mode === 'task-bound' && (typeof candidate.taskId !== 'string' || candidate.taskId.length === 0))
472
474
  || (candidate.mode === 'branch-only' && candidate.taskId !== null))
@@ -480,7 +482,27 @@ function readSandboxControlManifestValue(manifestPath) {
480
482
  if (path.resolve(candidate.runtimeDir) !== path.join(root, 'runtime')) {
481
483
  throw new Error('SANDBOX_CONTROL_MANIFEST_INVALID');
482
484
  }
483
- return candidate;
485
+ const normalized = {
486
+ engine: candidate.engine,
487
+ repoRoot: candidate.repoRoot,
488
+ worktreeRoot: candidate.worktreeRoot,
489
+ project: candidate.project,
490
+ container: candidate.container,
491
+ containerIdentity: {
492
+ id: containerIdentity.id,
493
+ labels: { ...containerIdentity.labels }
494
+ },
495
+ branch: candidate.branch,
496
+ mode: candidate.mode,
497
+ taskId: candidate.taskId,
498
+ token: candidate.token,
499
+ generation: candidate.generation,
500
+ channelDir: candidate.channelDir,
501
+ publicStatusDir: candidate.publicStatusDir,
502
+ processingDir: candidate.processingDir,
503
+ runtimeDir: candidate.runtimeDir
504
+ };
505
+ return normalized;
484
506
  }
485
507
  export function readSandboxControlManifest(manifestPath) {
486
508
  return readSandboxControlManifestValue(manifestPath);
@@ -50,8 +50,8 @@ export function isProcessAlive(pid, platform = process.platform) {
50
50
  return error.code === 'EPERM';
51
51
  }
52
52
  }
53
- function parseDarwinStartTime(output) {
54
- const match = output.trim().match(/^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat) ([A-Z][a-z]{2}) (\d{1,2}) (\d{2}):(\d{2}):(\d{2}) (\d{4})$/);
53
+ export function parseDarwinStartTime(output) {
54
+ const match = output.trim().match(/^(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat) ([A-Z][a-z]{2})\s+(\d{1,2}) (\d{2}):(\d{2}):(\d{2}) (\d{4})$/);
55
55
  if (!match)
56
56
  return null;
57
57
  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
@@ -429,9 +429,9 @@ function buildArtifactLinkSection(content, artifact) {
429
429
  const label = english
430
430
  ? `${spec.labels[1]} (Round ${artifact.round})`
431
431
  : `${spec.labels[0]}(Round ${artifact.round})`;
432
- const link = `[${label}](${artifact.name})`;
432
+ const link = `${label}:\`${artifact.name}\``;
433
433
  let body = extractSection(content, aliases);
434
- if (body.includes(`](${artifact.name})`))
434
+ if (body.includes(link))
435
435
  return { aliases, heading, body };
436
436
  const placeholders = new Set([
437
437
  '[分析阶段的发现。哪些文件受影响?范围是什么?]',
@@ -0,0 +1,100 @@
1
+ import { createHash } from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ function intentRoot(repoRoot) {
5
+ return path.join(repoRoot, '.agents', 'workspace', '.task-commit-intents');
6
+ }
7
+ function intentPath(repoRoot, taskId) {
8
+ return path.join(intentRoot(repoRoot), `${taskId}.json`);
9
+ }
10
+ function checkpointIntentDigest(identity) {
11
+ return createHash('sha256').update(JSON.stringify({
12
+ taskId: identity.taskId,
13
+ branch: identity.branch,
14
+ mode: identity.mode,
15
+ expectedHead: identity.expectedHead,
16
+ expectedTree: identity.expectedTree,
17
+ paths: [...identity.paths],
18
+ message: identity.message,
19
+ round: identity.round
20
+ })).digest('hex');
21
+ }
22
+ function isIntent(value) {
23
+ if (!value || typeof value !== 'object' || Array.isArray(value))
24
+ return false;
25
+ const intent = value;
26
+ return intent.version === 1
27
+ && typeof intent.taskId === 'string' && intent.taskId.length > 0
28
+ && typeof intent.branch === 'string' && intent.branch.length > 0
29
+ && intent.mode === 'local'
30
+ && typeof intent.expectedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.expectedHead)
31
+ && typeof intent.expectedTree === 'string' && /^[a-f0-9]{40,64}$/.test(intent.expectedTree)
32
+ && Array.isArray(intent.paths) && intent.paths.every((item) => typeof item === 'string' && item.length > 0)
33
+ && typeof intent.message === 'string' && intent.message.length > 0
34
+ && Number.isSafeInteger(intent.round) && Number(intent.round) > 0
35
+ && typeof intent.digest === 'string' && /^[a-f0-9]{64}$/.test(intent.digest)
36
+ && ['prepared', 'committed', 'synced'].includes(String(intent.state))
37
+ && (intent.committedHead === null || (typeof intent.committedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.committedHead)))
38
+ && typeof intent.createdAt === 'string' && intent.createdAt.length > 0
39
+ && typeof intent.updatedAt === 'string' && intent.updatedAt.length > 0
40
+ && intent.digest === checkpointIntentDigest(intent);
41
+ }
42
+ function readCheckpointIntent(repoRoot, taskId) {
43
+ const target = intentPath(repoRoot, taskId);
44
+ if (!fs.existsSync(target))
45
+ return null;
46
+ const value = JSON.parse(fs.readFileSync(target, 'utf8'));
47
+ if (!isIntent(value))
48
+ throw new Error('COMMIT_INTENT_INVALID: checkpoint intent schema is invalid');
49
+ return value;
50
+ }
51
+ function writeCheckpointIntent(repoRoot, value) {
52
+ if (!isIntent(value))
53
+ throw new Error('COMMIT_INTENT_INVALID: checkpoint intent schema is invalid');
54
+ const directory = intentRoot(repoRoot);
55
+ fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
56
+ const target = intentPath(repoRoot, value.taskId);
57
+ const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
58
+ fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
59
+ try {
60
+ fs.renameSync(temporary, target);
61
+ }
62
+ catch (error) {
63
+ try {
64
+ fs.unlinkSync(temporary);
65
+ }
66
+ catch { /* preserve primary error */ }
67
+ throw error;
68
+ }
69
+ }
70
+ function updateCheckpointIntent(value, patch) {
71
+ const next = { ...value, ...patch };
72
+ if (next.state === 'prepared' && next.committedHead !== null)
73
+ throw new Error('COMMIT_INTENT_INVALID: prepared intent cannot have a committed head');
74
+ if (next.state !== 'prepared' && !next.committedHead)
75
+ throw new Error('COMMIT_INTENT_INVALID: committed intent requires a committed head');
76
+ return next;
77
+ }
78
+ function removeCheckpointIntent(repoRoot, taskId) {
79
+ const target = intentPath(repoRoot, taskId);
80
+ try {
81
+ fs.unlinkSync(target);
82
+ }
83
+ catch (error) {
84
+ if (error.code !== 'ENOENT')
85
+ throw error;
86
+ }
87
+ }
88
+ function sameCheckpointIntent(left, right) {
89
+ return left.digest === checkpointIntentDigest(right)
90
+ && left.taskId === right.taskId
91
+ && left.branch === right.branch
92
+ && left.mode === right.mode
93
+ && left.expectedHead === right.expectedHead
94
+ && left.expectedTree === right.expectedTree
95
+ && left.message === right.message
96
+ && left.round === right.round
97
+ && JSON.stringify(left.paths) === JSON.stringify(right.paths);
98
+ }
99
+ export { checkpointIntentDigest, intentPath, intentRoot, isIntent, readCheckpointIntent, removeCheckpointIntent, sameCheckpointIntent, updateCheckpointIntent, writeCheckpointIntent };
100
+ //# sourceMappingURL=commit-intent.js.map