@fitlab-ai/agent-infra 0.9.13 → 0.9.15
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 +10 -0
- package/README.zh-CN.md +10 -0
- package/bin/cli.ts +26 -9
- package/bin/internal-cli.sh +45 -0
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +126 -42
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +3 -2
- package/dist/lib/defaults.json +103 -103
- package/dist/lib/fs/durable-write.js +37 -0
- package/dist/lib/fs/file-lock.js +111 -0
- package/dist/lib/host-control/audit.js +19 -0
- package/dist/lib/host-control/client.js +142 -0
- package/dist/lib/host-control/command.js +49 -0
- package/dist/lib/host-control/path.js +160 -0
- package/dist/lib/host-control/secure-fs.js +140 -0
- package/dist/lib/host-control/server.js +159 -0
- package/dist/lib/host-control/service.js +112 -0
- package/dist/lib/init.js +11 -2
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +154 -0
- package/dist/lib/internal/codex-lifecycle.js +15 -12
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/demo-promotion.js +322 -0
- package/dist/lib/internal/demo-transcript.js +454 -0
- package/dist/lib/internal/git-workflow.js +10 -6
- package/dist/lib/internal/host-control.js +28 -0
- package/dist/lib/internal/manual-validation.js +322 -0
- package/dist/lib/internal/platform-checks.js +16 -4
- package/dist/lib/internal/platform-comment.js +16 -4
- package/dist/lib/internal/platform-context.js +4 -1
- package/dist/lib/internal/platform-issue.js +12 -4
- package/dist/lib/internal/platform-metadata.js +88 -0
- package/dist/lib/internal/platform-pr-review.js +16 -3
- package/dist/lib/internal/platform-pr.js +42 -14
- package/dist/lib/internal/platform-release-notes.js +6 -3
- package/dist/lib/internal/platform-security.js +93 -0
- package/dist/lib/internal/pr-review-grade.js +14 -3
- package/dist/lib/internal/release-workflow.js +82 -89
- package/dist/lib/internal/sandbox-control.js +171 -7
- package/dist/lib/internal/task-activity.js +13 -4
- package/dist/lib/internal/task-artifact.js +19 -107
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +48 -14
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +38 -35
- package/dist/lib/internal/task-finalization.js +4 -1
- package/dist/lib/internal/task-invalidation.js +4 -1
- package/dist/lib/internal/task-ledger.js +12 -1
- package/dist/lib/internal/task-lifecycle.js +4 -1
- package/dist/lib/internal/task-operation-registry.js +519 -0
- package/dist/lib/internal/task-orchestration.js +12 -0
- package/dist/lib/internal/task-override.js +10 -3
- package/dist/lib/internal/task-qualification.js +90 -0
- package/dist/lib/internal/task-review.js +10 -52
- package/dist/lib/internal/task-short-id.js +11 -1
- package/dist/lib/internal/task-snapshot.js +4 -1
- package/dist/lib/internal/task-validate.js +37 -12
- package/dist/lib/internal/task-verify.js +5 -1
- package/dist/lib/internal/task-warning.js +8 -1
- package/dist/lib/owned-path.js +33 -0
- package/dist/lib/platform/check-status.js +11 -0
- package/dist/lib/platform/comment-safety.js +229 -0
- package/dist/lib/platform/completion-backfill.js +1 -1
- package/dist/lib/platform/github-data.js +241 -0
- package/dist/lib/platform/github-provider.js +248 -26
- package/dist/lib/platform/issue-comments.js +146 -34
- package/dist/lib/platform/issues.js +1 -179
- package/dist/lib/platform/pr-change-report.js +6 -12
- package/dist/lib/platform/pr-checks.js +12 -65
- package/dist/lib/platform/pr-summary.js +83 -10
- package/dist/lib/platform/provider-contract.d.ts +67 -1
- package/dist/lib/platform/provider-contract.js +6 -2
- package/dist/lib/platform/provider-validation.js +76 -3
- package/dist/lib/platform/pull-requests.js +117 -275
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/snapshots.js +2 -0
- package/dist/lib/platform/verification-sync.js +154 -162
- package/dist/lib/process-data/index.js +7 -0
- package/dist/lib/release/workflow.js +1 -1
- package/dist/lib/run/index.js +5 -0
- package/dist/lib/sandbox/commands/control-status.js +22 -0
- package/dist/lib/sandbox/commands/create.js +39 -8
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +3 -807
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/audit.js +203 -0
- package/dist/lib/sandbox/control/client.js +125 -12
- package/dist/lib/sandbox/control/completed-reentry.js +85 -0
- package/dist/lib/sandbox/control/container-identity.js +28 -31
- package/dist/lib/sandbox/control/executor.js +233 -34
- package/dist/lib/sandbox/control/finalization-response.js +27 -0
- package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
- package/dist/lib/sandbox/control/lifecycle.js +656 -128
- package/dist/lib/sandbox/control/native-file-lock.js +85 -0
- package/dist/lib/sandbox/control/protocol.js +55 -4
- package/dist/lib/sandbox/control/server.js +720 -79
- package/dist/lib/sandbox/control/state.js +63 -3
- package/dist/lib/sandbox/control/task-view.js +183 -0
- package/dist/lib/sandbox/control/task-workflow.js +74 -0
- package/dist/lib/sandbox/control/workflow-executor.js +99 -0
- package/dist/lib/sandbox/engines/authority.js +289 -0
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
- package/dist/lib/sandbox/index.js +7 -2
- package/dist/lib/sandbox/recovery.js +49 -5
- package/dist/lib/sandbox/removal.js +1717 -0
- package/dist/lib/sandbox/task-cleanup.js +217 -0
- package/dist/lib/sandbox/workspace-view.js +15 -15
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/task/activity-intent.js +2 -1
- package/dist/lib/task/activity-log.js +30 -24
- package/dist/lib/task/artifact-command.js +101 -0
- package/dist/lib/task/artifact-lifecycle.js +71 -40
- package/dist/lib/task/artifact-name.js +36 -0
- package/dist/lib/task/artifact-operations.js +474 -0
- package/dist/lib/task/artifact-receipts.js +3 -15
- package/dist/lib/task/artifact-repair-intent.js +130 -0
- package/dist/lib/task/artifact-schema.js +127 -0
- package/dist/lib/task/capabilities.js +83 -19
- package/dist/lib/task/codex-orchestration.js +71 -25
- package/dist/lib/task/commit-identity.js +28 -0
- package/dist/lib/task/commit-operation.js +2 -16
- package/dist/lib/task/control-authority.js +375 -5
- package/dist/lib/task/control-recovery.js +128 -0
- package/dist/lib/task/create-service.js +103 -4
- package/dist/lib/task/create.js +80 -2
- package/dist/lib/task/decision-details.js +2 -46
- package/dist/lib/task/events.js +306 -76
- package/dist/lib/task/finalization-state.js +9 -0
- package/dist/lib/task/human-override.js +3 -6
- package/dist/lib/task/implementation-inputs.js +3 -3
- package/dist/lib/task/index.js +11 -3
- package/dist/lib/task/intermediate-cleanup.js +383 -0
- package/dist/lib/task/invalidation.js +18 -65
- package/dist/lib/task/ledger-intents.js +7 -22
- package/dist/lib/task/ledger.js +1 -3
- package/dist/lib/task/lifecycle.js +19 -1
- package/dist/lib/task/local-artifact-finalization.js +190 -290
- package/dist/lib/task/manual-validation-completion.js +26 -0
- package/dist/lib/task/manual-validation-evidence.js +130 -0
- package/dist/lib/task/manual-validation-receipt.js +101 -0
- package/dist/lib/task/manual-validation-shared.js +40 -0
- package/dist/lib/task/manual-validation-transaction.js +243 -0
- package/dist/lib/task/markdown.js +47 -0
- package/dist/lib/task/orchestration.js +206 -69
- package/dist/lib/task/qualification-audit.js +476 -0
- package/dist/lib/task/qualification-confirmation.js +109 -0
- package/dist/lib/task/qualification-intents.js +148 -0
- package/dist/lib/task/review-artifacts.js +23 -40
- package/dist/lib/task/review-command.js +25 -0
- package/dist/lib/task/review-finalization.js +146 -97
- package/dist/lib/task/review-fingerprint.js +2 -2
- package/dist/lib/task/sections.js +34 -54
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +170 -327
- package/dist/lib/task/verification.js +1 -1
- package/dist/lib/task/workflow-command.js +17 -0
- package/dist/lib/task/workflow-warning-intents.js +0 -16
- package/dist/lib/task/workflow-warnings.js +28 -2
- package/dist/lib/update.js +2 -0
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +3 -2
- package/lib/fs/durable-write.ts +29 -0
- package/lib/fs/file-lock.ts +113 -0
- package/lib/host-control/audit.ts +22 -0
- package/lib/host-control/client.ts +172 -0
- package/lib/host-control/command.ts +60 -0
- package/lib/host-control/path.ts +167 -0
- package/lib/host-control/secure-fs.ts +135 -0
- package/lib/host-control/server.ts +180 -0
- package/lib/host-control/service.ts +133 -0
- package/lib/init.ts +15 -2
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +142 -0
- package/lib/internal/codex-lifecycle.ts +14 -12
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/demo-promotion.ts +354 -0
- package/lib/internal/demo-transcript.ts +419 -0
- package/lib/internal/git-workflow.ts +9 -6
- package/lib/internal/host-control.ts +28 -0
- package/lib/internal/manual-validation.ts +306 -0
- package/lib/internal/platform-checks.ts +12 -4
- package/lib/internal/platform-comment.ts +12 -4
- package/lib/internal/platform-context.ts +3 -1
- package/lib/internal/platform-issue.ts +11 -4
- package/lib/internal/platform-metadata.ts +70 -0
- package/lib/internal/platform-pr-review.ts +14 -3
- package/lib/internal/platform-pr.ts +38 -14
- package/lib/internal/platform-release-notes.ts +5 -3
- package/lib/internal/platform-security.ts +83 -0
- package/lib/internal/pr-review-grade.ts +10 -3
- package/lib/internal/release-workflow.ts +91 -87
- package/lib/internal/sandbox-control.ts +181 -6
- package/lib/internal/task-activity.ts +12 -4
- package/lib/internal/task-artifact.ts +15 -79
- package/lib/internal/task-context.ts +3 -1
- package/lib/internal/task-create.ts +76 -15
- package/lib/internal/task-delivery.ts +3 -1
- package/lib/internal/task-event.ts +21 -10
- package/lib/internal/task-finalization.ts +3 -1
- package/lib/internal/task-invalidation.ts +3 -1
- package/lib/internal/task-ledger.ts +11 -1
- package/lib/internal/task-lifecycle.ts +3 -1
- package/lib/internal/task-operation-registry.ts +590 -0
- package/lib/internal/task-orchestration.ts +12 -0
- package/lib/internal/task-override.ts +9 -3
- package/lib/internal/task-qualification.ts +61 -0
- package/lib/internal/task-review.ts +7 -50
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +32 -12
- package/lib/internal/task-verify.ts +4 -1
- package/lib/internal/task-warning.ts +7 -1
- package/lib/owned-path.ts +26 -0
- package/lib/platform/check-status.ts +9 -0
- package/lib/platform/comment-safety.ts +255 -0
- package/lib/platform/completion-backfill.ts +1 -1
- package/lib/platform/github-data.ts +322 -0
- package/lib/platform/github-provider.ts +244 -27
- package/lib/platform/issue-comments.ts +159 -35
- package/lib/platform/issues.ts +4 -245
- package/lib/platform/pr-change-report.ts +6 -12
- package/lib/platform/pr-checks.ts +13 -77
- package/lib/platform/pr-summary.ts +88 -11
- package/lib/platform/provider-contract.ts +78 -3
- package/lib/platform/provider-validation.ts +85 -3
- package/lib/platform/pull-requests.ts +129 -348
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/snapshots.ts +53 -0
- package/lib/platform/verification-sync.ts +171 -177
- package/lib/process-data/index.ts +7 -0
- package/lib/release/workflow.ts +3 -3
- package/lib/run/index.ts +5 -0
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +53 -12
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +3 -996
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/audit.ts +253 -0
- package/lib/sandbox/control/client.ts +150 -13
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +262 -37
- package/lib/sandbox/control/finalization-response.ts +29 -0
- package/lib/sandbox/control/identity-sentinel.ts +137 -0
- package/lib/sandbox/control/lifecycle.ts +672 -18
- package/lib/sandbox/control/native-file-lock.ts +108 -0
- package/lib/sandbox/control/protocol.ts +80 -8
- package/lib/sandbox/control/server.ts +779 -82
- package/lib/sandbox/control/state.ts +84 -3
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/control/task-workflow.ts +95 -0
- package/lib/sandbox/control/workflow-executor.ts +102 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +9 -2
- package/lib/sandbox/recovery.ts +49 -6
- package/lib/sandbox/removal.ts +2144 -0
- package/lib/sandbox/task-cleanup.ts +209 -0
- package/lib/sandbox/workspace-view.ts +26 -18
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/task/activity-intent.ts +2 -2
- package/lib/task/activity-log.ts +27 -19
- package/lib/task/artifact-command.ts +104 -0
- package/lib/task/artifact-lifecycle.ts +66 -39
- package/lib/task/artifact-name.ts +55 -0
- package/lib/task/artifact-operations.ts +580 -0
- package/lib/task/artifact-receipts.ts +3 -14
- package/lib/task/artifact-repair-intent.ts +152 -0
- package/lib/task/artifact-schema.ts +163 -0
- package/lib/task/capabilities.ts +82 -22
- package/lib/task/codex-orchestration.ts +85 -24
- package/lib/task/commit-identity.ts +31 -0
- package/lib/task/commit-operation.ts +2 -16
- package/lib/task/control-authority.ts +513 -6
- package/lib/task/control-recovery.ts +174 -0
- package/lib/task/create-service.ts +131 -6
- package/lib/task/create.ts +83 -1
- package/lib/task/decision-details.ts +3 -71
- package/lib/task/events.ts +292 -75
- package/lib/task/finalization-state.ts +11 -0
- package/lib/task/human-override.ts +3 -8
- package/lib/task/implementation-inputs.ts +3 -3
- package/lib/task/index.ts +16 -3
- package/lib/task/intermediate-cleanup.ts +455 -0
- package/lib/task/invalidation.ts +18 -62
- package/lib/task/ledger-intents.ts +7 -24
- package/lib/task/ledger.ts +1 -3
- package/lib/task/lifecycle.ts +17 -1
- package/lib/task/local-artifact-finalization.ts +223 -388
- package/lib/task/manual-validation-completion.ts +40 -0
- package/lib/task/manual-validation-evidence.ts +209 -0
- package/lib/task/manual-validation-receipt.ts +152 -0
- package/lib/task/manual-validation-shared.ts +50 -0
- package/lib/task/manual-validation-transaction.ts +304 -0
- package/lib/task/markdown.ts +70 -0
- package/lib/task/orchestration.ts +191 -68
- package/lib/task/qualification-audit.ts +588 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -41
- package/lib/task/review-command.ts +23 -0
- package/lib/task/review-finalization.ts +154 -153
- package/lib/task/review-fingerprint.ts +2 -2
- package/lib/task/sections.ts +33 -52
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +165 -370
- package/lib/task/verification-types.ts +17 -0
- package/lib/task/verification.ts +1 -1
- package/lib/task/workflow-command.ts +18 -0
- package/lib/task/workflow-warning-intents.ts +0 -13
- package/lib/task/workflow-warnings.ts +21 -2
- package/lib/update.ts +6 -0
- package/package.json +7 -2
- package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- package/templates/.agents/rules/decision-qualification.en.md +22 -0
- package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
- package/templates/.agents/rules/evidence-reporting.en.md +28 -0
- package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
- package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
- package/templates/.agents/rules/security-alerts.en.md +8 -8
- package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
- package/templates/.agents/rules/testing-discipline.en.md +2 -0
- package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
- package/templates/.agents/scripts/package.json +3 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
- package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +37 -21
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +4 -0
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -23
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -23
- package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
- package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
- package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
- package/templates/.agents/skills/release/SKILL.en.md +7 -3
- package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
- package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +25 -4
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +25 -4
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +5 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +5 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/test/SKILL.en.md +29 -7
- package/templates/.agents/skills/test/SKILL.zh-CN.md +29 -7
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
- package/templates/.agents/templates/task.en.md +6 -0
- package/templates/.agents/templates/task.zh-CN.md +6 -0
- package/templates/.claude/commands/run-manual-validation.en.md +1 -1
- package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
- package/dist/lib/platform/adapters.js +0 -56
- package/lib/platform/adapters.ts +0 -197
- package/templates/.agents/scripts/security-alerts.github.sh +0 -151
- package/templates/.agents/scripts/security-alerts.sh +0 -31
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
|
@@ -7,6 +7,7 @@ import { platformResult } from './types.js';
|
|
|
7
7
|
import { providerError, providerOperationContext, providerStatus, providerResourceToken, unsupportedProviderOperation } from './provider-bridge.js';
|
|
8
8
|
import { resourceIdentityNumber } from './resource-identity.js';
|
|
9
9
|
import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.js';
|
|
10
|
+
import { canonicalizeCommentBody, escapeHtmlText, fenceRanges, renderSafeCodeFence } from './comment-safety.js';
|
|
10
11
|
function providerCommentId(id, provider) {
|
|
11
12
|
return provider.identity?.comment === 'number' && /^\d+$/.test(id) ? Number(id) : id;
|
|
12
13
|
}
|
|
@@ -37,14 +38,21 @@ function splitFrontmatter(content) {
|
|
|
37
38
|
return { frontmatter: null, body: content };
|
|
38
39
|
return { frontmatter: match[1], body: content.slice(match[0].length).replace(/^\r?\n/, '') };
|
|
39
40
|
}
|
|
41
|
+
function sanitizeCommentBody(value, label) {
|
|
42
|
+
const result = canonicalizeCommentBody(value);
|
|
43
|
+
if (!result.ok)
|
|
44
|
+
throw new Error(`${result.error.code}: ${label}: ${result.error.message} at offset ${result.error.offset}`);
|
|
45
|
+
return result.value;
|
|
46
|
+
}
|
|
40
47
|
function footer(agent, taskId) {
|
|
41
48
|
return `---\n*由 ${agent} 自动生成 · 内部追踪:${taskId}*`;
|
|
42
49
|
}
|
|
43
50
|
function renderTaskComment(content, taskId, agent) {
|
|
44
51
|
const split = splitFrontmatter(content);
|
|
52
|
+
const safeBody = sanitizeCommentBody(split.body, 'task body');
|
|
45
53
|
const taskBody = split.frontmatter === null
|
|
46
|
-
?
|
|
47
|
-
: `<details><summary>元数据 (frontmatter)</summary>\n\n
|
|
54
|
+
? safeBody
|
|
55
|
+
: `<details><summary>元数据 (frontmatter)</summary>\n\n${renderSafeCodeFence(`---\n${split.frontmatter}\n---`, 'yaml')}\n\n</details>\n\n${safeBody}`;
|
|
48
56
|
return normalizeCommentContent([
|
|
49
57
|
MARKERS.task(taskId),
|
|
50
58
|
'## 任务文件',
|
|
@@ -69,10 +77,11 @@ function chunkByUtf8(content, maxBytes) {
|
|
|
69
77
|
if (maxBytes <= 0)
|
|
70
78
|
throw new Error('comment byte limit is too small');
|
|
71
79
|
const chunks = [];
|
|
72
|
-
let
|
|
73
|
-
while (
|
|
80
|
+
let start = 0;
|
|
81
|
+
while (start < content.length) {
|
|
82
|
+
const remaining = content.slice(start);
|
|
74
83
|
if (Buffer.byteLength(remaining, 'utf8') <= maxBytes) {
|
|
75
|
-
chunks.push(remaining);
|
|
84
|
+
chunks.push({ content: remaining, start, end: content.length });
|
|
76
85
|
break;
|
|
77
86
|
}
|
|
78
87
|
let bytes = 0;
|
|
@@ -90,12 +99,109 @@ function chunkByUtf8(content, maxBytes) {
|
|
|
90
99
|
const cut = newlineIndex > 0 ? newlineIndex : index;
|
|
91
100
|
if (cut === 0)
|
|
92
101
|
throw new Error('comment byte limit cannot fit one Unicode code point');
|
|
93
|
-
chunks.push(remaining.slice(0, cut));
|
|
94
|
-
|
|
102
|
+
chunks.push({ content: remaining.slice(0, cut), start, end: start + cut });
|
|
103
|
+
start += cut;
|
|
104
|
+
}
|
|
105
|
+
return chunks.length > 0 ? chunks : [{ content: '', start: 0, end: 0 }];
|
|
106
|
+
}
|
|
107
|
+
function longestFenceLineRun(content, character) {
|
|
108
|
+
const pattern = new RegExp(`^ {0,3}(${character}+)[ \\t]*(?:\\n|$)`, 'gm');
|
|
109
|
+
let longest = 0;
|
|
110
|
+
for (const match of content.matchAll(pattern))
|
|
111
|
+
longest = Math.max(longest, match[1].length);
|
|
112
|
+
return longest;
|
|
113
|
+
}
|
|
114
|
+
function boundedFence(content, sourceCharacter, maxBytes) {
|
|
115
|
+
const candidates = sourceCharacter === '`' ? ['~', '`'] : ['`', '~'];
|
|
116
|
+
for (const character of candidates) {
|
|
117
|
+
const length = Math.max(3, longestFenceLineRun(content, character) + 1);
|
|
118
|
+
const delimiter = character.repeat(length);
|
|
119
|
+
if (Buffer.byteLength(delimiter, 'utf8') * 2 + 2 <= maxBytes)
|
|
120
|
+
return { opening: `${delimiter}\n`, closing: `${delimiter}\n` };
|
|
95
121
|
}
|
|
96
|
-
return
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
function sourceSlice(piece, start, end) {
|
|
125
|
+
return piece.content.slice(Math.max(0, start - piece.start), Math.max(0, end - piece.start));
|
|
97
126
|
}
|
|
98
|
-
function
|
|
127
|
+
function renderOversizedFenceChunk(piece, fences, maxBytes) {
|
|
128
|
+
const insertions = new Map();
|
|
129
|
+
const omitted = [];
|
|
130
|
+
const insert = (position, value, ensureLineStart = false) => {
|
|
131
|
+
const values = insertions.get(position) || [];
|
|
132
|
+
values.push({ value, ensureLineStart });
|
|
133
|
+
insertions.set(position, values);
|
|
134
|
+
};
|
|
135
|
+
for (const fence of fences) {
|
|
136
|
+
if (piece.end <= fence.start || piece.start >= fence.end)
|
|
137
|
+
continue;
|
|
138
|
+
const oversized = Buffer.byteLength(fence.opening, 'utf8') > maxBytes
|
|
139
|
+
|| Buffer.byteLength(fence.closing, 'utf8') > maxBytes;
|
|
140
|
+
if (!oversized) {
|
|
141
|
+
if (piece.start > fence.start && piece.start < fence.end)
|
|
142
|
+
insert(piece.start, fence.opening);
|
|
143
|
+
if (piece.end > fence.start && piece.end < fence.end)
|
|
144
|
+
insert(piece.end, fence.closing, true);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const code = sourceSlice(piece, Math.max(piece.start, fence.openingEnd), Math.min(piece.end, fence.closingStart));
|
|
148
|
+
const delimiter = boundedFence(code, fence.character, maxBytes);
|
|
149
|
+
if (!delimiter)
|
|
150
|
+
return escapeHtmlText(piece.content);
|
|
151
|
+
insert(Math.max(piece.start, fence.start), delimiter.opening);
|
|
152
|
+
insert(Math.min(piece.end, fence.end), delimiter.closing, true);
|
|
153
|
+
const openingStart = Math.max(piece.start, fence.start);
|
|
154
|
+
const openingEnd = Math.min(piece.end, fence.openingEnd);
|
|
155
|
+
if (openingStart < openingEnd)
|
|
156
|
+
omitted.push({ start: openingStart, end: openingEnd });
|
|
157
|
+
const closingStart = Math.max(piece.start, fence.closingStart);
|
|
158
|
+
const closingEnd = Math.min(piece.end, fence.end);
|
|
159
|
+
if (closingStart < closingEnd)
|
|
160
|
+
omitted.push({ start: closingStart, end: closingEnd });
|
|
161
|
+
}
|
|
162
|
+
const boundaries = new Set([piece.start, piece.end]);
|
|
163
|
+
for (const position of insertions.keys())
|
|
164
|
+
boundaries.add(position);
|
|
165
|
+
for (const range of omitted) {
|
|
166
|
+
boundaries.add(range.start);
|
|
167
|
+
boundaries.add(range.end);
|
|
168
|
+
}
|
|
169
|
+
const points = [...boundaries].sort((left, right) => left - right);
|
|
170
|
+
let content = '';
|
|
171
|
+
for (let index = 0; index < points.length; index += 1) {
|
|
172
|
+
const point = points[index];
|
|
173
|
+
for (const insertion of insertions.get(point) || []) {
|
|
174
|
+
if (insertion.ensureLineStart && content.length > 0 && !content.endsWith('\n'))
|
|
175
|
+
content += '\n';
|
|
176
|
+
content += insertion.value;
|
|
177
|
+
}
|
|
178
|
+
const next = points[index + 1];
|
|
179
|
+
if (next === undefined)
|
|
180
|
+
continue;
|
|
181
|
+
const skipped = omitted.some((range) => range.start <= point && next <= range.end);
|
|
182
|
+
if (!skipped)
|
|
183
|
+
content += sourceSlice(piece, point, next);
|
|
184
|
+
}
|
|
185
|
+
return content;
|
|
186
|
+
}
|
|
187
|
+
function independentChunkContent(piece, fences, maxBytes) {
|
|
188
|
+
const oversizedFence = fences.some((fence) => piece.end > fence.start && piece.start < fence.end
|
|
189
|
+
&& (Buffer.byteLength(fence.opening, 'utf8') > maxBytes || Buffer.byteLength(fence.closing, 'utf8') > maxBytes));
|
|
190
|
+
if (oversizedFence)
|
|
191
|
+
return renderOversizedFenceChunk(piece, fences, maxBytes);
|
|
192
|
+
const openingFence = fences.find((fence) => piece.start > fence.start && piece.start < fence.end);
|
|
193
|
+
const closingFence = fences.find((fence) => piece.end > fence.start && piece.end < fence.end);
|
|
194
|
+
let content = piece.content;
|
|
195
|
+
if (openingFence)
|
|
196
|
+
content = openingFence.opening + content;
|
|
197
|
+
if (closingFence) {
|
|
198
|
+
if (!content.endsWith('\n'))
|
|
199
|
+
content += '\n';
|
|
200
|
+
content += closingFence.closing;
|
|
201
|
+
}
|
|
202
|
+
return content;
|
|
203
|
+
}
|
|
204
|
+
function buildArtifactChunk(taskId, stem, title, agent, content, part, total, chunked, backfill, renderedContent = content) {
|
|
99
205
|
const marker = chunked ? MARKERS.artifactChunk(taskId, stem, part, total) : MARKERS.artifact(taskId, stem);
|
|
100
206
|
const heading = chunked ? `## ${title}(${part}/${total})` : `## ${title}`;
|
|
101
207
|
const timelineHint = backfill ? '> 历史产物补发' : null;
|
|
@@ -106,7 +212,7 @@ function buildArtifactChunk(taskId, stem, title, agent, content, part, total, ch
|
|
|
106
212
|
'',
|
|
107
213
|
`> **${agent}** · ${taskId}`,
|
|
108
214
|
'',
|
|
109
|
-
|
|
215
|
+
renderedContent,
|
|
110
216
|
'',
|
|
111
217
|
footer(agent, taskId)
|
|
112
218
|
].join('\n'));
|
|
@@ -115,25 +221,32 @@ function buildArtifactChunk(taskId, stem, title, agent, content, part, total, ch
|
|
|
115
221
|
function chunkArtifactComment(input) {
|
|
116
222
|
const byteLimit = input.byteLimit || 60_000;
|
|
117
223
|
const identity = artifactIdentity(input.artifact);
|
|
118
|
-
const
|
|
224
|
+
const safeBody = sanitizeCommentBody(input.body, 'artifact body');
|
|
225
|
+
const single = buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, safeBody, 1, 1, false, Boolean(input.backfill));
|
|
119
226
|
if (Buffer.byteLength(single.body, 'utf8') <= byteLimit)
|
|
120
227
|
return [single];
|
|
121
228
|
let total = 2;
|
|
122
|
-
let
|
|
229
|
+
let payloadLimit = Number.POSITIVE_INFINITY;
|
|
230
|
+
const ranges = fenceRanges(safeBody);
|
|
231
|
+
if (!ranges.ok)
|
|
232
|
+
throw new Error(`${ranges.error.code}: artifact body: ${ranges.error.message} at offset ${ranges.error.offset}`);
|
|
123
233
|
for (;;) {
|
|
124
234
|
const probe = buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, '', total, total, true, Boolean(input.backfill));
|
|
125
235
|
const available = byteLimit - Buffer.byteLength(probe.body, 'utf8');
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
236
|
+
const sourceLimit = Math.min(available, payloadLimit);
|
|
237
|
+
if (sourceLimit <= 0)
|
|
238
|
+
throw new Error('comment byte limit is too small for an artifact chunk');
|
|
239
|
+
const pieces = chunkByUtf8(safeBody, sourceLimit);
|
|
240
|
+
if (pieces.length !== total) {
|
|
241
|
+
total = pieces.length;
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
const chunks = pieces.map((piece, index) => buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, piece.content, index + 1, total, true, Boolean(input.backfill), independentChunkContent(piece, ranges.value, sourceLimit)));
|
|
245
|
+
const overflow = Math.max(...chunks.map((chunk) => Buffer.byteLength(chunk.body, 'utf8') - byteLimit));
|
|
246
|
+
if (overflow <= 0)
|
|
247
|
+
return chunks;
|
|
248
|
+
payloadLimit = sourceLimit - overflow;
|
|
130
249
|
}
|
|
131
|
-
return pieces.map((content, index) => {
|
|
132
|
-
const chunk = buildArtifactChunk(input.taskId, identity.stem, identity.title, input.agent, content, index + 1, total, true, Boolean(input.backfill));
|
|
133
|
-
if (Buffer.byteLength(chunk.body, 'utf8') > byteLimit)
|
|
134
|
-
throw new Error('rendered comment exceeds byte limit');
|
|
135
|
-
return chunk;
|
|
136
|
-
});
|
|
137
250
|
}
|
|
138
251
|
function findMarkerComments(comments, marker) {
|
|
139
252
|
return comments.filter((comment) => normalizeCommentContent(String(comment.body || '')).split('\n', 1)[0] === marker);
|
|
@@ -166,7 +279,7 @@ function hasResolvedPlatformContext(context) {
|
|
|
166
279
|
}
|
|
167
280
|
function bodyEnvelope(marker, title, taskId, agent, body) {
|
|
168
281
|
return normalizeCommentContent([
|
|
169
|
-
marker, `## ${title}`, '', `> **${agent}** · ${taskId}`, '', body.replace(/\n+$/, ''), '', footer(agent, taskId)
|
|
282
|
+
marker, `## ${title}`, '', `> **${agent}** · ${taskId}`, '', sanitizeCommentBody(body, `${title} body`).replace(/\n+$/, ''), '', footer(agent, taskId)
|
|
170
283
|
].join('\n'));
|
|
171
284
|
}
|
|
172
285
|
function resolveArtifactBody(taskDir, artifact) {
|
|
@@ -271,6 +384,16 @@ async function syncPlatformComment(taskRef, options) {
|
|
|
271
384
|
error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no valid issue_number', retryable: false }
|
|
272
385
|
});
|
|
273
386
|
}
|
|
387
|
+
let desired;
|
|
388
|
+
try {
|
|
389
|
+
desired = expectedComments(resolved.taskId, taskContent, resolved.taskDir, options);
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
return platformResult('failed', {
|
|
393
|
+
resource: { kind: 'issue', number: resourceIdentityNumber(issueIdentityFromTask) },
|
|
394
|
+
error: { code: 'COMMENT_PAYLOAD_INVALID', message: error instanceof Error ? error.message : String(error), retryable: false }
|
|
395
|
+
});
|
|
396
|
+
}
|
|
274
397
|
const loaded = await resolvePlatformProviderContext({ cwd: resolved.repoRoot, client: options.client });
|
|
275
398
|
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
276
399
|
if (!hasResolvedPlatformContext(context) || !loaded.ok)
|
|
@@ -293,17 +416,6 @@ async function syncPlatformComment(taskRef, options) {
|
|
|
293
416
|
...contextFields(context), resource: { kind: 'issue', number: issue }, error: listed.error
|
|
294
417
|
});
|
|
295
418
|
}
|
|
296
|
-
let desired;
|
|
297
|
-
try {
|
|
298
|
-
desired = expectedComments(resolved.taskId, taskContent, resolved.taskDir, options);
|
|
299
|
-
}
|
|
300
|
-
catch (error) {
|
|
301
|
-
return platformResult('failed', {
|
|
302
|
-
...contextFields(context),
|
|
303
|
-
resource: { kind: 'issue', number: issue },
|
|
304
|
-
error: { code: 'COMMENT_PAYLOAD_INVALID', message: error instanceof Error ? error.message : String(error), retryable: false }
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
419
|
const existing = relatedComments(listed.value, markerPrefix(resolved.taskId, options));
|
|
308
420
|
if (!validateRelatedMarkerSet(existing, markerPrefix(resolved.taskId, options)).ok) {
|
|
309
421
|
return platformResult('failed', {
|
|
@@ -14,8 +14,6 @@ import { labelDelta, planInLabelUpdate, syncLabelDelta, validateInLabelMapping,
|
|
|
14
14
|
import { providerError, providerOperationContext, providerStatus, providerResourceIdentity, providerResourceToken, unsupportedProviderOperation } from './provider-bridge.js';
|
|
15
15
|
import { resourceIdentityEquals, resourceIdentityNumber, resourceIdentityString, serializeResourceIdentity } from './resource-identity.js';
|
|
16
16
|
import { taskIssueIdentity, taskIssueIdentityError } from './task-identities.js';
|
|
17
|
-
const ISSUE_TYPES_QUERY = `query($owner:String!){organization(login:$owner){issueTypes(first:20){nodes{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}}}}}`;
|
|
18
|
-
const ISSUE_FIELDS_QUERY = `query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){issue(number:$number){id issueType{id name pinnedFields{__typename ... on IssueFieldSingleSelect{id name options{id name}} ... on IssueFieldDate{id name} ... on IssueFieldText{id name} ... on IssueFieldNumber{id name}}} issueFieldValues(first:50){nodes{__typename ... on IssueFieldSingleSelectValue{name optionId field{... on IssueFieldSingleSelect{id name}}} ... on IssueFieldDateValue{value field{... on IssueFieldDate{id name}}} ... on IssueFieldTextValue{value field{... on IssueFieldText{id name}}} ... on IssueFieldNumberValue{value field{... on IssueFieldNumber{id name}}}}}}}}`;
|
|
19
17
|
function result(status, taskId, issueNumber, overrides = {}) {
|
|
20
18
|
return {
|
|
21
19
|
...platformResult(status),
|
|
@@ -133,115 +131,6 @@ async function inspectExternalIssue(base, issueIdentity) {
|
|
|
133
131
|
error: null
|
|
134
132
|
});
|
|
135
133
|
}
|
|
136
|
-
function normalizeIssue(remote, repository, fallbackNumber) {
|
|
137
|
-
const number = Number.isInteger(remote.number) && Number(remote.number) > 0
|
|
138
|
-
? Number(remote.number)
|
|
139
|
-
: fallbackNumber;
|
|
140
|
-
if (!number || !Number.isSafeInteger(number) || remote.pull_request)
|
|
141
|
-
return null;
|
|
142
|
-
return {
|
|
143
|
-
repository,
|
|
144
|
-
number,
|
|
145
|
-
databaseId: Number.isInteger(remote.id) ? Number(remote.id) : null,
|
|
146
|
-
nodeId: remote.node_id || `issue-${number}`,
|
|
147
|
-
url: remote.html_url || `https://github.com/${repository}/issues/${number}`,
|
|
148
|
-
state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
|
|
149
|
-
title: remote.title || '',
|
|
150
|
-
body: remote.body || '',
|
|
151
|
-
labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
|
|
152
|
-
assignees: (remote.assignees || []).map((assignee) => assignee.login || '').filter(Boolean).sort(),
|
|
153
|
-
milestone: remote.milestone?.title || null,
|
|
154
|
-
issueType: remote.type?.name || null,
|
|
155
|
-
fields: {}
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
function fieldKind(value) {
|
|
159
|
-
if (value.__typename === 'IssueFieldSingleSelect' || value.__typename === 'IssueFieldSingleSelectValue')
|
|
160
|
-
return 'single-select';
|
|
161
|
-
if (value.__typename === 'IssueFieldDate' || value.__typename === 'IssueFieldDateValue')
|
|
162
|
-
return 'date';
|
|
163
|
-
if (value.__typename === 'IssueFieldText' || value.__typename === 'IssueFieldTextValue')
|
|
164
|
-
return 'text';
|
|
165
|
-
if (value.__typename === 'IssueFieldNumber' || value.__typename === 'IssueFieldNumberValue')
|
|
166
|
-
return 'number';
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
function normalizeFieldSchemas(value) {
|
|
170
|
-
if (!Array.isArray(value))
|
|
171
|
-
return [];
|
|
172
|
-
return value.flatMap((raw) => {
|
|
173
|
-
const item = raw;
|
|
174
|
-
const kind = fieldKind(item);
|
|
175
|
-
return item.id && item.name && kind ? [{
|
|
176
|
-
id: item.id,
|
|
177
|
-
name: item.name,
|
|
178
|
-
kind,
|
|
179
|
-
options: (item.options || []).flatMap((option) => option.id && option.name ? [{ id: option.id, name: option.name }] : [])
|
|
180
|
-
}] : [];
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
function normalizeIssueTypes(value) {
|
|
184
|
-
const nodes = value?.data?.organization?.issueTypes?.nodes;
|
|
185
|
-
return (nodes || []).flatMap((raw) => {
|
|
186
|
-
const item = raw;
|
|
187
|
-
return item.id && item.name ? [{ id: item.id, name: item.name, fields: normalizeFieldSchemas(item.pinnedFields) }] : [];
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
function normalizeCurrentFields(value) {
|
|
191
|
-
const issue = value?.data?.repository?.issue;
|
|
192
|
-
const type = issue?.issueType?.name ? {
|
|
193
|
-
id: issue.issueType.id || issue.issueType.name,
|
|
194
|
-
name: issue.issueType.name,
|
|
195
|
-
fields: normalizeFieldSchemas(issue.issueType.pinnedFields)
|
|
196
|
-
} : null;
|
|
197
|
-
const values = (issue?.issueFieldValues?.nodes || []).flatMap((raw) => {
|
|
198
|
-
const item = raw;
|
|
199
|
-
const kind = fieldKind(item);
|
|
200
|
-
const value = kind === 'single-select' ? item.name : item.value;
|
|
201
|
-
return item.field?.name && kind && value !== undefined
|
|
202
|
-
? [{ id: item.field.id || item.field.name, name: item.field.name, kind, value: value ?? null }]
|
|
203
|
-
: [];
|
|
204
|
-
});
|
|
205
|
-
return { issueId: issue?.id || null, type, values };
|
|
206
|
-
}
|
|
207
|
-
function graphState(client, repository, issue, cwd) {
|
|
208
|
-
const [owner, name] = repository.split('/');
|
|
209
|
-
if (!owner || !name)
|
|
210
|
-
return null;
|
|
211
|
-
const current = client.json([
|
|
212
|
-
'api', 'graphql', '-f', `query=${ISSUE_FIELDS_QUERY}`, '-F', `owner=${owner}`, '-F', `name=${name}`, '-F', `number=${issue}`
|
|
213
|
-
], { cwd });
|
|
214
|
-
if (!current.ok)
|
|
215
|
-
return null;
|
|
216
|
-
return normalizeCurrentFields(current.value);
|
|
217
|
-
}
|
|
218
|
-
function fetchIssue(client, repository, issue, cwd) {
|
|
219
|
-
return client.json(['api', `repos/${repository}/issues/${issue}`], { cwd });
|
|
220
|
-
}
|
|
221
|
-
function inspectGitHubIssue(client, repository, issue, cwd) {
|
|
222
|
-
const fetched = fetchIssue(client, repository, issue, cwd);
|
|
223
|
-
if (!fetched.ok)
|
|
224
|
-
return fetched;
|
|
225
|
-
const snapshot = normalizeIssue(fetched.value, repository, issue);
|
|
226
|
-
return snapshot
|
|
227
|
-
? { ok: true, value: snapshot }
|
|
228
|
-
: { ok: false, error: { code: 'ISSUE_IDENTITY_INVALID', message: 'Remote resource is not a valid Issue', retryable: false } };
|
|
229
|
-
}
|
|
230
|
-
function inspectGitHubIssueMetadata(client, repository, issue, cwd) {
|
|
231
|
-
const fetched = fetchIssue(client, repository, issue, cwd);
|
|
232
|
-
if (!fetched.ok)
|
|
233
|
-
return fetched;
|
|
234
|
-
const remote = fetched.value;
|
|
235
|
-
return {
|
|
236
|
-
ok: true,
|
|
237
|
-
value: {
|
|
238
|
-
state: String(remote.state || '').toLowerCase() === 'closed' ? 'closed' : 'open',
|
|
239
|
-
labels: (remote.labels || []).map((label) => typeof label === 'string' ? label : label.name || '').filter(Boolean).sort(),
|
|
240
|
-
body: remote.body || '',
|
|
241
|
-
milestone: remote.milestone?.title || null
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
134
|
async function inspectPlatformIssue(taskRef, options = {}) {
|
|
246
135
|
const base = await resolvedContext(taskRef, options);
|
|
247
136
|
if (!base.ok)
|
|
@@ -450,12 +339,6 @@ function requirementsFromTask(content) {
|
|
|
450
339
|
checked: match[1].toLowerCase() === 'x', text: match[2]
|
|
451
340
|
}));
|
|
452
341
|
}
|
|
453
|
-
function flattenPages(value) {
|
|
454
|
-
return Array.isArray(value) ? value.flatMap((item) => Array.isArray(item) ? item : [item]) : [];
|
|
455
|
-
}
|
|
456
|
-
function listNames(value) {
|
|
457
|
-
return flattenPages(value).map((item) => typeof item === 'string' ? item : String(item.name || '')).filter(Boolean);
|
|
458
|
-
}
|
|
459
342
|
function milestoneBasis(repoRoot, current) {
|
|
460
343
|
if (!current || !/^\d+\.\d+\.x$/.test(current))
|
|
461
344
|
return current;
|
|
@@ -552,67 +435,6 @@ function desiredFieldValues(frontmatter, fields) {
|
|
|
552
435
|
}
|
|
553
436
|
return desired;
|
|
554
437
|
}
|
|
555
|
-
function planGraphMetadata(client, repository, issue, cwd, frontmatter, options, capabilities) {
|
|
556
|
-
if (!options.issueType && !options.fields)
|
|
557
|
-
return { operations: [], issueId: null };
|
|
558
|
-
if (!capabilities.push)
|
|
559
|
-
return {
|
|
560
|
-
operations: [
|
|
561
|
-
...(options.issueType ? [{ name: 'issue-type', status: 'skipped', reasonCode: 'PUSH_REQUIRED' }] : []),
|
|
562
|
-
...(options.fields ? [{ name: 'fields', status: 'skipped', reasonCode: 'PUSH_REQUIRED' }] : [])
|
|
563
|
-
], issueId: null
|
|
564
|
-
};
|
|
565
|
-
const [owner] = repository.split('/');
|
|
566
|
-
const typesResult = client.json(['api', 'graphql', '-f', `query=${ISSUE_TYPES_QUERY}`, '-F', `owner=${owner}`], { cwd });
|
|
567
|
-
if (!typesResult.ok)
|
|
568
|
-
return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: typesResult.error.code }], issueId: null };
|
|
569
|
-
const types = normalizeIssueTypes(typesResult.value);
|
|
570
|
-
if (types.length === 0)
|
|
571
|
-
return {
|
|
572
|
-
operations: [
|
|
573
|
-
...(options.issueType ? [{ name: 'issue-type', status: 'skipped', reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : []),
|
|
574
|
-
...(options.fields ? [{ name: 'fields', status: 'skipped', reasonCode: 'ISSUE_TYPES_UNSUPPORTED' }] : [])
|
|
575
|
-
], issueId: null
|
|
576
|
-
};
|
|
577
|
-
const current = graphState(client, repository, issue, cwd);
|
|
578
|
-
if (!current?.issueId)
|
|
579
|
-
return { operations: [{ name: 'issue-schema', status: 'failed', reasonCode: 'ISSUE_GRAPH_IDENTITY_INVALID' }], issueId: null };
|
|
580
|
-
const target = types.find((type) => type.name === desiredIssueType(frontmatter.type || ''));
|
|
581
|
-
if (!target)
|
|
582
|
-
return { operations: [{ name: 'issue-type', status: 'failed', reasonCode: 'ISSUE_TYPE_NOT_FOUND' }], issueId: current.issueId };
|
|
583
|
-
const operations = [];
|
|
584
|
-
if (options.issueType)
|
|
585
|
-
operations.push(current.type?.id === target.id
|
|
586
|
-
? { name: 'issue-type', status: 'no-op', reasonCode: null }
|
|
587
|
-
: { name: 'issue-type', status: 'planned', reasonCode: null, value: { issueTypeId: target.id } });
|
|
588
|
-
if (options.fields) {
|
|
589
|
-
const desired = desiredFieldValues(frontmatter, target.fields);
|
|
590
|
-
const inputs = desired.filter((field) => current.values.find((value) => value.name === field.name)?.value !== field.value).map((field) => field.input);
|
|
591
|
-
if (current.type?.id !== target.id) {
|
|
592
|
-
const targetNames = new Set(target.fields.map((field) => field.name));
|
|
593
|
-
for (const old of current.values)
|
|
594
|
-
if (!targetNames.has(old.name))
|
|
595
|
-
inputs.push({ fieldId: old.id, delete: true });
|
|
596
|
-
}
|
|
597
|
-
operations.push(inputs.length === 0
|
|
598
|
-
? { name: 'fields', status: 'no-op', reasonCode: null }
|
|
599
|
-
: { name: 'fields', status: 'planned', reasonCode: null, value: inputs });
|
|
600
|
-
}
|
|
601
|
-
return { operations, issueId: current.issueId };
|
|
602
|
-
}
|
|
603
|
-
function executeGraphOperation(client, cwd, issueId, operation) {
|
|
604
|
-
if (operation.name === 'issue-type') {
|
|
605
|
-
const query = 'mutation($issueId:ID!,$issueTypeId:ID){updateIssueIssueType(input:{issueId:$issueId,issueTypeId:$issueTypeId}){issue{id}}}';
|
|
606
|
-
const typeId = operation.value.issueTypeId;
|
|
607
|
-
return client.json(['api', 'graphql', '--input', '-'], {
|
|
608
|
-
cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueTypeId: typeId } })
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
const query = 'mutation($issueId:ID!,$issueFields:[IssueFieldCreateOrUpdateInput!]!){setIssueFieldValue(input:{issueId:$issueId,issueFields:$issueFields}){issue{id}}}';
|
|
612
|
-
return client.json(['api', 'graphql', '--input', '-'], {
|
|
613
|
-
cwd, method: 'POST', input: JSON.stringify({ query, variables: { issueId, issueFields: operation.value } })
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
438
|
async function syncPlatformIssue(taskRef, options) {
|
|
617
439
|
const base = await resolvedContext(taskRef, options);
|
|
618
440
|
if (!base.ok)
|
|
@@ -761,5 +583,5 @@ async function syncPlatformIssue(taskRef, options) {
|
|
|
761
583
|
operations: plan.operations.map((operation) => operation.status === 'planned' ? { ...operation, status: 'applied' } : operation), error: null
|
|
762
584
|
});
|
|
763
585
|
}
|
|
764
|
-
export { bindPlatformIssue, createPlatformIssue,
|
|
586
|
+
export { bindPlatformIssue, createPlatformIssue, inspectPlatformIssue, requirementSectionAnchors, syncPlatformIssue };
|
|
765
587
|
//# sourceMappingURL=issues.js.map
|
|
@@ -2,6 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { escapeHtmlText } from './comment-safety.js';
|
|
5
6
|
const REPORT_FILE_NAME = 'pr-change-report.json';
|
|
6
7
|
const REPORT_VERSION = 1;
|
|
7
8
|
const CANONICAL_REPORT_PLACEHOLDER = '<!-- canonical-pr-change-report -->';
|
|
@@ -429,21 +430,14 @@ const MAX_REPRESENTATIVE_FILES = 3;
|
|
|
429
430
|
function representativePath(file) {
|
|
430
431
|
return file.newPath || file.oldPath || '';
|
|
431
432
|
}
|
|
432
|
-
function
|
|
433
|
-
return value
|
|
434
|
-
.replaceAll('&', '&')
|
|
435
|
-
.replaceAll('<', '<')
|
|
436
|
-
.replaceAll('>', '>')
|
|
437
|
-
.replaceAll('"', '"')
|
|
438
|
-
.replaceAll("'", ''')
|
|
439
|
-
.replaceAll('\r', '\\r')
|
|
440
|
-
.replaceAll('\n', '\\n');
|
|
433
|
+
function escapeReportText(value) {
|
|
434
|
+
return escapeHtmlText(value).replaceAll('\r', '\\r').replaceAll('\n', '\\n');
|
|
441
435
|
}
|
|
442
436
|
function renderRepresentativePath(file) {
|
|
443
437
|
const paths = file.oldPath && file.newPath && file.oldPath !== file.newPath
|
|
444
438
|
? [file.oldPath, file.newPath]
|
|
445
439
|
: [representativePath(file)];
|
|
446
|
-
return paths.map((filePath) => `<code>${
|
|
440
|
+
return paths.map((filePath) => `<code>${escapeReportText(filePath)}</code>`).join(' → ');
|
|
447
441
|
}
|
|
448
442
|
function representativeScore(file, metric) {
|
|
449
443
|
return metric === 'lines' ? file.additions + file.deletions : Math.abs(file.netBytes);
|
|
@@ -492,11 +486,11 @@ function renderEvidence(evidence) {
|
|
|
492
486
|
? `:${evidence.startLine}`
|
|
493
487
|
: `:${evidence.startLine}-${evidence.endLine}`
|
|
494
488
|
: `:${evidence.startLine ?? evidence.endLine}`;
|
|
495
|
-
return ` - 证据:<code>${
|
|
489
|
+
return ` - 证据:<code>${escapeReportText(evidence.path)}</code>${location}:${escapeReportText(evidence.detail)}`;
|
|
496
490
|
}
|
|
497
491
|
function renderPrechecks(checks) {
|
|
498
492
|
return checks.flatMap((check) => [
|
|
499
|
-
`- **${PRECHECK_LABELS[check.id]}(${check.id})**:${check.verdict === 'pass' ? '通过' : '需复核'}。${
|
|
493
|
+
`- **${PRECHECK_LABELS[check.id]}(${check.id})**:${check.verdict === 'pass' ? '通过' : '需复核'}。${escapeReportText(check.rationale)}`,
|
|
500
494
|
...check.evidence.slice(0, 1).map(renderEvidence)
|
|
501
495
|
]);
|
|
502
496
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { parseTypedTaskFrontmatter } from '../task/frontmatter.js';
|
|
3
3
|
import { resolveTaskRef } from '../task/resolve-ref.js';
|
|
4
|
+
import { checkStatusBucket } from './check-status.js';
|
|
4
5
|
import { resolvePlatformProviderContext } from './context.js';
|
|
5
6
|
import { inspectPlatformPullRequest } from './pull-requests.js';
|
|
6
7
|
import { platformResult } from './types.js';
|
|
@@ -26,20 +27,6 @@ function classifyPullRequestReadiness(input) {
|
|
|
26
27
|
return { state: 'pending', headSha: input.headSha };
|
|
27
28
|
return { state: 'ready', headSha: input.headSha };
|
|
28
29
|
}
|
|
29
|
-
function parseRunJobIdentity(detailsUrl) {
|
|
30
|
-
try {
|
|
31
|
-
const url = new URL(detailsUrl);
|
|
32
|
-
if (url.hostname !== 'github.com')
|
|
33
|
-
return null;
|
|
34
|
-
const match = url.pathname.match(/\/actions\/runs\/(\d+)(?:\/job\/(\d+))?/);
|
|
35
|
-
if (!match)
|
|
36
|
-
return null;
|
|
37
|
-
return { runId: Number(match[1]), jobId: match[2] ? Number(match[2]) : null };
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
30
|
function resolveRunCandidate(candidates, headSha, checkName) {
|
|
44
31
|
const matches = candidates.filter((candidate) => candidate.headSha === headSha && candidate.name === checkName);
|
|
45
32
|
if (matches.length === 1)
|
|
@@ -54,42 +41,6 @@ function checksResult(status, overrides = {}) {
|
|
|
54
41
|
...overrides
|
|
55
42
|
};
|
|
56
43
|
}
|
|
57
|
-
function normalizeBucket(value) {
|
|
58
|
-
const raw = String(value.bucket || value.status || value.conclusion || value.state || '').toLowerCase();
|
|
59
|
-
if (['pass', 'success', 'successful', 'neutral'].includes(raw))
|
|
60
|
-
return 'pass';
|
|
61
|
-
if (['fail', 'failure', 'failed', 'error', 'timed_out', 'action_required'].includes(raw))
|
|
62
|
-
return 'fail';
|
|
63
|
-
if (['cancel', 'cancelled', 'canceled', 'skipped', 'stale'].includes(raw))
|
|
64
|
-
return 'cancel';
|
|
65
|
-
return 'pending';
|
|
66
|
-
}
|
|
67
|
-
function normalizeChecks(value) {
|
|
68
|
-
if (!Array.isArray(value))
|
|
69
|
-
return [];
|
|
70
|
-
return value.flatMap((raw) => {
|
|
71
|
-
const item = raw;
|
|
72
|
-
const name = String(item.name || item.context || '');
|
|
73
|
-
return name ? [{
|
|
74
|
-
name,
|
|
75
|
-
bucket: normalizeBucket(item),
|
|
76
|
-
workflow: item.workflow ? String(item.workflow) : null,
|
|
77
|
-
conclusion: item.conclusion ? String(item.conclusion) : item.state ? String(item.state) : null,
|
|
78
|
-
detailsUrl: item.link ? String(item.link) : item.detailsUrl ? String(item.detailsUrl) : null,
|
|
79
|
-
startedAt: item.startedAt ? String(item.startedAt) : null,
|
|
80
|
-
completedAt: item.completedAt ? String(item.completedAt) : null
|
|
81
|
-
}] : [];
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
function inspectGitHubRequiredChecks(client, repository, number, cwd) {
|
|
85
|
-
const inspected = client.json([
|
|
86
|
-
'pr', 'checks', String(number), '--repo', repository,
|
|
87
|
-
'--json', 'name,state,bucket,link,workflow,startedAt,completedAt'
|
|
88
|
-
], { cwd });
|
|
89
|
-
return inspected.ok
|
|
90
|
-
? { ok: true, value: normalizeChecks(inspected.value) }
|
|
91
|
-
: { ok: false, error: inspected.error };
|
|
92
|
-
}
|
|
93
44
|
async function resolvedTask(taskRef, options) {
|
|
94
45
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
95
46
|
if (!resolved.ok)
|
|
@@ -117,10 +68,9 @@ async function inspectRequiredChecks(taskRef, options = {}) {
|
|
|
117
68
|
const base = await resolvedTask(taskRef, options);
|
|
118
69
|
if (!base.ok)
|
|
119
70
|
return base.output;
|
|
120
|
-
return inspectChecksForResolvedTask(base
|
|
71
|
+
return inspectChecksForResolvedTask(base);
|
|
121
72
|
}
|
|
122
|
-
async function inspectChecksForResolvedTask(base
|
|
123
|
-
const repository = base.context.platform.repository;
|
|
73
|
+
async function inspectChecksForResolvedTask(base) {
|
|
124
74
|
{
|
|
125
75
|
const inspected = base.provider.checks?.inspectRequired
|
|
126
76
|
? await base.provider.checks.inspectRequired({
|
|
@@ -137,7 +87,13 @@ async function inspectChecksForResolvedTask(base, options) {
|
|
|
137
87
|
pullRequest: base.pullRequest,
|
|
138
88
|
error: providerError(inspected.error, 'PLATFORM_PROVIDER_OPERATION_FAILED')
|
|
139
89
|
});
|
|
140
|
-
const required =
|
|
90
|
+
const required = inspected.value.map((check) => ({
|
|
91
|
+
name: check.name,
|
|
92
|
+
bucket: checkStatusBucket(check.status),
|
|
93
|
+
conclusion: check.conclusion || null,
|
|
94
|
+
detailsUrl: check.detailsUrl || null,
|
|
95
|
+
workflow: null, startedAt: null, completedAt: null
|
|
96
|
+
}));
|
|
141
97
|
const classified = classifyRequiredChecks(required);
|
|
142
98
|
const status = classified.state === 'passed' || classified.state === 'no-required'
|
|
143
99
|
? 'no-op'
|
|
@@ -157,7 +113,7 @@ async function inspectPullRequestReadiness(taskRef, options = {}) {
|
|
|
157
113
|
const base = await resolvedTask(taskRef, options);
|
|
158
114
|
if (!base.ok)
|
|
159
115
|
return base.output;
|
|
160
|
-
const checked = await inspectChecksForResolvedTask(base
|
|
116
|
+
const checked = await inspectChecksForResolvedTask(base);
|
|
161
117
|
const classifiedCodes = new Set(['REQUIRED_CHECKS_PENDING', 'REQUIRED_CHECKS_FAILED', 'REQUIRED_CHECKS_CANCELLED']);
|
|
162
118
|
if (checked.error && !classifiedCodes.has(checked.error.code))
|
|
163
119
|
return checked;
|
|
@@ -242,15 +198,6 @@ async function resolvePlatformCheckRun(taskRef, options) {
|
|
|
242
198
|
});
|
|
243
199
|
}
|
|
244
200
|
}
|
|
245
|
-
function fetchCheckLogText(client, args, cwd) {
|
|
246
|
-
if (!client.text)
|
|
247
|
-
return { ok: false, error: { code: 'PLATFORM_CLIENT_TEXT_UNAVAILABLE', message: 'Platform client does not support text responses', retryable: false } };
|
|
248
|
-
const fetched = client.text(args, { cwd });
|
|
249
|
-
if (fetched.ok || args[0] !== 'api' || !/response contains terminal escape sequences/i.test(fetched.error.message)) {
|
|
250
|
-
return fetched;
|
|
251
|
-
}
|
|
252
|
-
return client.text([...args, '--allow-escape-sequences'], { cwd });
|
|
253
|
-
}
|
|
254
201
|
async function fetchPlatformCheckLogs(taskRef, options) {
|
|
255
202
|
const base = await resolvedTask(taskRef, options);
|
|
256
203
|
if (!base.ok)
|
|
@@ -281,5 +228,5 @@ async function fetchPlatformCheckLogs(taskRef, options) {
|
|
|
281
228
|
});
|
|
282
229
|
}
|
|
283
230
|
}
|
|
284
|
-
export { classifyPullRequestReadiness, classifyRequiredChecks,
|
|
231
|
+
export { classifyPullRequestReadiness, classifyRequiredChecks, fetchPlatformCheckLogs, inspectRequiredChecks, inspectPullRequestReadiness, resolvePlatformCheckRun, resolveRunCandidate, watchPullRequestReadiness };
|
|
285
232
|
//# sourceMappingURL=pr-checks.js.map
|