@fitlab-ai/agent-infra 0.9.13 → 0.9.14
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/bin/cli.ts +26 -9
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +42 -21
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +152 -0
- package/dist/lib/internal/codex-lifecycle.js +9 -6
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/git-workflow.js +10 -6
- 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 +24 -10
- 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 +19 -5
- package/dist/lib/internal/sandbox-control.js +22 -5
- package/dist/lib/internal/task-activity.js +13 -4
- package/dist/lib/internal/task-artifact.js +186 -27
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +48 -15
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +4 -1
- 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 +421 -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 +4 -1
- 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 +7 -2
- package/dist/lib/internal/task-verify.js +5 -1
- package/dist/lib/internal/task-warning.js +8 -1
- package/dist/lib/platform/comment-safety.js +226 -0
- package/dist/lib/platform/github-provider.js +233 -6
- package/dist/lib/platform/issue-comments.js +146 -34
- package/dist/lib/platform/pr-change-report.js +6 -12
- package/dist/lib/platform/pr-summary.js +28 -7
- 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 +115 -170
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/verification-sync.js +33 -26
- package/dist/lib/process-data/index.js +7 -0
- 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 +32 -6
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +827 -120
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/client.js +83 -9
- 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 +149 -14
- package/dist/lib/sandbox/control/lifecycle.js +621 -127
- package/dist/lib/sandbox/control/native-file-lock.js +177 -0
- package/dist/lib/sandbox/control/server.js +305 -35
- package/dist/lib/sandbox/control/state.js +5 -3
- package/dist/lib/sandbox/control/task-view.js +183 -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 +5 -0
- package/dist/lib/sandbox/recovery.js +21 -1
- package/dist/lib/sandbox/workspace-view.js +2 -1
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/task/artifact-lifecycle.js +42 -13
- package/dist/lib/task/artifact-operations.js +520 -0
- package/dist/lib/task/artifact-repair-intent.js +59 -0
- package/dist/lib/task/artifact-schema.js +135 -0
- package/dist/lib/task/capabilities.js +72 -1
- package/dist/lib/task/control-authority.js +4 -0
- package/dist/lib/task/create-service.js +103 -4
- package/dist/lib/task/create.js +25 -0
- package/dist/lib/task/events.js +186 -67
- package/dist/lib/task/index.js +11 -3
- package/dist/lib/task/local-artifact-finalization.js +75 -150
- package/dist/lib/task/orchestration.js +192 -52
- package/dist/lib/task/qualification-audit.js +490 -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 +22 -23
- package/dist/lib/task/review-finalization.js +121 -4
- package/dist/lib/task/sections.js +6 -4
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +54 -4
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +140 -0
- package/lib/internal/codex-lifecycle.ts +8 -6
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/git-workflow.ts +9 -6
- 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 +23 -10
- 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 +17 -5
- package/lib/internal/sandbox-control.ts +19 -5
- package/lib/internal/task-activity.ts +12 -4
- package/lib/internal/task-artifact.ts +164 -25
- 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 +3 -1
- 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 +482 -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 +3 -1
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +6 -2
- package/lib/internal/task-verify.ts +4 -1
- package/lib/internal/task-warning.ts +7 -1
- package/lib/platform/comment-safety.ts +250 -0
- package/lib/platform/github-provider.ts +229 -7
- package/lib/platform/issue-comments.ts +160 -35
- package/lib/platform/pr-change-report.ts +6 -12
- package/lib/platform/pr-summary.ts +27 -6
- package/lib/platform/provider-contract.ts +78 -3
- package/lib/platform/provider-validation.ts +85 -3
- package/lib/platform/pull-requests.ts +126 -178
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/verification-sync.ts +32 -28
- package/lib/process-data/index.ts +7 -0
- package/lib/run/index.ts +5 -0
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +46 -6
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +1000 -87
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/client.ts +103 -9
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +177 -12
- package/lib/sandbox/control/lifecycle.ts +629 -17
- package/lib/sandbox/control/native-file-lock.ts +209 -0
- package/lib/sandbox/control/protocol.ts +5 -2
- package/lib/sandbox/control/server.ts +319 -37
- package/lib/sandbox/control/state.ts +6 -3
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +7 -0
- package/lib/sandbox/recovery.ts +21 -1
- package/lib/sandbox/workspace-view.ts +9 -3
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/task/artifact-lifecycle.ts +38 -16
- package/lib/task/artifact-operations.ts +626 -0
- package/lib/task/artifact-repair-intent.ts +71 -0
- package/lib/task/artifact-schema.ts +192 -0
- package/lib/task/capabilities.ts +70 -1
- package/lib/task/control-authority.ts +11 -1
- package/lib/task/create-service.ts +131 -6
- package/lib/task/create.ts +27 -0
- package/lib/task/events.ts +161 -65
- package/lib/task/index.ts +16 -3
- package/lib/task/local-artifact-finalization.ts +87 -218
- package/lib/task/orchestration.ts +172 -49
- package/lib/task/qualification-audit.ts +599 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -22
- package/lib/task/review-finalization.ts +133 -4
- package/lib/task/sections.ts +6 -4
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +55 -4
- package/package.json +6 -1
- 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/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 +5 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/complete-task/SKILL.en.md +9 -22
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +9 -22
- 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/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 +5 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
- package/templates/.agents/skills/test/SKILL.en.md +13 -2
- package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
- 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/.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
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { resolvePlatformProviderContext } from './context.js';
|
|
5
|
+
import { providerError, providerOperationContext, providerStatus } from './provider-bridge.js';
|
|
6
|
+
import { platformResult } from './types.js';
|
|
7
|
+
const COMMON_LABELS = [
|
|
8
|
+
{ name: 'type: bug', color: 'DED6F9', description: 'A general bug' },
|
|
9
|
+
{ name: 'type: enhancement', color: 'DED6F9', description: 'A general enhancement' },
|
|
10
|
+
{ name: 'type: feature', color: 'DED6F9', description: 'A general feature' },
|
|
11
|
+
{ name: 'type: documentation', color: 'DED6F9', description: 'A documentation task' },
|
|
12
|
+
{ name: 'type: dependency-upgrade', color: 'DED6F9', description: 'A dependency upgrade' },
|
|
13
|
+
{ name: 'type: task', color: 'DED6F9', description: 'A general task' },
|
|
14
|
+
{ name: 'status: waiting-for-triage', color: 'FCF1C4', description: "An issue we've not yet triaged or decided on" },
|
|
15
|
+
{ name: 'status: waiting-for-feedback', color: 'FCF1C4', description: 'We need additional information before we can continue' },
|
|
16
|
+
{ name: 'status: feedback-provided', color: 'FCF1C4', description: 'Feedback has been provided' },
|
|
17
|
+
{ name: 'status: feedback-reminder', color: 'FCF1C4', description: "We've sent a reminder that we need additional information before we can continue" },
|
|
18
|
+
{ name: 'status: pending-design-work', color: 'FCF1C4', description: 'Needs design work before any code can be developed' },
|
|
19
|
+
{ name: 'status: in-progress', color: 'FCF1C4', description: 'Work is actively being developed' },
|
|
20
|
+
{ name: 'status: on-hold', color: 'FCF1C4', description: "We can't start working on this issue yet" },
|
|
21
|
+
{ name: 'status: blocked', color: 'FCF1C4', description: "An issue that's blocked on an external project change" },
|
|
22
|
+
{ name: 'status: declined', color: 'FCF1C4', description: "A suggestion or change that we don't feel we should currently apply" },
|
|
23
|
+
{ name: 'status: duplicate', color: 'FCF1C4', description: 'A duplicate of another issue' },
|
|
24
|
+
{ name: 'status: invalid', color: 'FCF1C4', description: "An issue that we don't feel is valid" },
|
|
25
|
+
{ name: 'status: superseded', color: 'FCF1C4', description: 'An issue that has been superseded by another' },
|
|
26
|
+
{ name: 'status: bulk-closed', color: 'FCF1C4', description: "An outdated, unresolved issue that's closed in bulk as part of a cleaning process" },
|
|
27
|
+
{ name: 'status: ideal-for-contribution', color: 'FCF1C4', description: 'An issue that a contributor can help us with' },
|
|
28
|
+
{ name: 'status: backported', color: 'FCF1C4', description: 'An issue that has been backported to maintenance branches' },
|
|
29
|
+
{ name: 'status: waiting-for-internal-feedback', color: 'FCF1C4', description: 'An issue that needs input from a member or another team' },
|
|
30
|
+
{ name: 'good first issue', color: 'F9D9E6', description: 'Good for newcomers' },
|
|
31
|
+
{ name: 'help wanted', color: '008672', description: 'Extra attention is needed' },
|
|
32
|
+
{ name: 'dependencies', color: '0366D6', description: 'Pull requests that update a dependency file' }
|
|
33
|
+
];
|
|
34
|
+
function validIdentifiers(value, prerelease) {
|
|
35
|
+
if (!value)
|
|
36
|
+
return false;
|
|
37
|
+
return value.split('.').every((identifier) => /^[0-9A-Za-z-]+$/.test(identifier)
|
|
38
|
+
&& (!prerelease || !/^\d+$/.test(identifier) || /^(0|[1-9]\d*)$/.test(identifier)));
|
|
39
|
+
}
|
|
40
|
+
function parseVersionTag(tag) {
|
|
41
|
+
if (!tag.startsWith('v'))
|
|
42
|
+
return null;
|
|
43
|
+
let version = tag.slice(1);
|
|
44
|
+
const plusAt = version.indexOf('+');
|
|
45
|
+
if (plusAt >= 0) {
|
|
46
|
+
const build = version.slice(plusAt + 1);
|
|
47
|
+
if (!validIdentifiers(build, false))
|
|
48
|
+
return null;
|
|
49
|
+
version = version.slice(0, plusAt);
|
|
50
|
+
}
|
|
51
|
+
let prerelease = '';
|
|
52
|
+
const dashAt = version.indexOf('-');
|
|
53
|
+
if (dashAt >= 0) {
|
|
54
|
+
prerelease = version.slice(dashAt + 1);
|
|
55
|
+
if (!validIdentifiers(prerelease, true))
|
|
56
|
+
return null;
|
|
57
|
+
version = version.slice(0, dashAt);
|
|
58
|
+
}
|
|
59
|
+
const core = version.split('.');
|
|
60
|
+
if (core.length !== 3 || !core.every((part) => /^(0|[1-9]\d*)$/.test(part)))
|
|
61
|
+
return null;
|
|
62
|
+
return { tag, major: core[0], minor: core[1], patch: core[2], prerelease };
|
|
63
|
+
}
|
|
64
|
+
function compareDecimal(left, right) {
|
|
65
|
+
if (left.length !== right.length)
|
|
66
|
+
return left.length > right.length ? 1 : -1;
|
|
67
|
+
if (left === right)
|
|
68
|
+
return 0;
|
|
69
|
+
return left > right ? 1 : -1;
|
|
70
|
+
}
|
|
71
|
+
function compareAscii(left, right) {
|
|
72
|
+
const alphabet = '+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
73
|
+
const limit = Math.min(left.length, right.length);
|
|
74
|
+
for (let index = 0; index < limit; index += 1) {
|
|
75
|
+
const leftRank = alphabet.indexOf(left[index]);
|
|
76
|
+
const rightRank = alphabet.indexOf(right[index]);
|
|
77
|
+
if (leftRank !== rightRank)
|
|
78
|
+
return leftRank > rightRank ? 1 : -1;
|
|
79
|
+
}
|
|
80
|
+
if (left.length === right.length)
|
|
81
|
+
return 0;
|
|
82
|
+
return left.length > right.length ? 1 : -1;
|
|
83
|
+
}
|
|
84
|
+
function comparePrerelease(left, right) {
|
|
85
|
+
if (!left || !right) {
|
|
86
|
+
if (left === right)
|
|
87
|
+
return 0;
|
|
88
|
+
return left ? -1 : 1;
|
|
89
|
+
}
|
|
90
|
+
const leftIds = left.split('.');
|
|
91
|
+
const rightIds = right.split('.');
|
|
92
|
+
const limit = Math.min(leftIds.length, rightIds.length);
|
|
93
|
+
for (let index = 0; index < limit; index += 1) {
|
|
94
|
+
const leftId = leftIds[index];
|
|
95
|
+
const rightId = rightIds[index];
|
|
96
|
+
const leftNumeric = /^\d+$/.test(leftId);
|
|
97
|
+
const rightNumeric = /^\d+$/.test(rightId);
|
|
98
|
+
const comparison = leftNumeric && rightNumeric
|
|
99
|
+
? compareDecimal(leftId, rightId)
|
|
100
|
+
: leftNumeric !== rightNumeric
|
|
101
|
+
? leftNumeric ? -1 : 1
|
|
102
|
+
: compareAscii(leftId, rightId);
|
|
103
|
+
if (comparison !== 0)
|
|
104
|
+
return comparison;
|
|
105
|
+
}
|
|
106
|
+
if (leftIds.length === rightIds.length)
|
|
107
|
+
return 0;
|
|
108
|
+
return leftIds.length > rightIds.length ? 1 : -1;
|
|
109
|
+
}
|
|
110
|
+
function compareVersions(left, right) {
|
|
111
|
+
for (const [leftPart, rightPart] of [
|
|
112
|
+
[left.major, right.major],
|
|
113
|
+
[left.minor, right.minor],
|
|
114
|
+
[left.patch, right.patch]
|
|
115
|
+
]) {
|
|
116
|
+
const comparison = compareDecimal(leftPart, rightPart);
|
|
117
|
+
if (comparison !== 0)
|
|
118
|
+
return comparison;
|
|
119
|
+
}
|
|
120
|
+
const prerelease = comparePrerelease(left.prerelease, right.prerelease);
|
|
121
|
+
return prerelease !== 0 ? prerelease : compareAscii(left.tag, right.tag);
|
|
122
|
+
}
|
|
123
|
+
function incrementDecimal(value) {
|
|
124
|
+
const digits = value.split('');
|
|
125
|
+
let carry = 1;
|
|
126
|
+
for (let index = digits.length - 1; index >= 0 && carry; index -= 1) {
|
|
127
|
+
const next = Number(digits[index]) + carry;
|
|
128
|
+
digits[index] = String(next % 10);
|
|
129
|
+
carry = next === 10 ? 1 : 0;
|
|
130
|
+
}
|
|
131
|
+
return carry ? `1${digits.join('')}` : digits.join('');
|
|
132
|
+
}
|
|
133
|
+
function buildMilestonePlan(tags, history) {
|
|
134
|
+
const parsed = tags.flatMap((tag) => {
|
|
135
|
+
const version = parseVersionTag(tag);
|
|
136
|
+
return version ? [version] : [];
|
|
137
|
+
});
|
|
138
|
+
const selected = parsed.reduce((best, candidate) => !best || compareVersions(candidate, best) > 0 ? candidate : best, null);
|
|
139
|
+
const baseline = selected
|
|
140
|
+
? { version: `${selected.major}.${selected.minor}.${selected.patch}`, source: `git tag ${selected.tag}` }
|
|
141
|
+
: { version: '0.1.0', source: 'compatibility default' };
|
|
142
|
+
const [major, minor, patch] = baseline.version.split('.');
|
|
143
|
+
const desired = [];
|
|
144
|
+
const titles = new Set();
|
|
145
|
+
const add = (title, description, state) => {
|
|
146
|
+
if (titles.has(title))
|
|
147
|
+
return;
|
|
148
|
+
titles.add(title);
|
|
149
|
+
desired.push({ title, description, state });
|
|
150
|
+
};
|
|
151
|
+
const line = `${major}.${minor}.x`;
|
|
152
|
+
const version = selected
|
|
153
|
+
? `${major}.${minor}.${incrementDecimal(patch)}`
|
|
154
|
+
: baseline.version;
|
|
155
|
+
add('General Backlog', 'All unsorted backlogged tasks may be completed in a future version.', 'open');
|
|
156
|
+
add(line, `Issues that we want to resolve in ${major}.${minor} line.`, 'open');
|
|
157
|
+
add(version, `Issues that we want to release in v${version}.`, 'open');
|
|
158
|
+
if (patch === '0') {
|
|
159
|
+
const nextMinor = `${major}.${incrementDecimal(minor)}.0`;
|
|
160
|
+
const nextLine = `${major}.${incrementDecimal(minor)}.x`;
|
|
161
|
+
add(nextMinor, `Issues that we want to release in v${nextMinor}.`, 'open');
|
|
162
|
+
add(nextLine, `Issues that we want to resolve in ${major}.${incrementDecimal(minor)} line.`, 'open');
|
|
163
|
+
}
|
|
164
|
+
if (history) {
|
|
165
|
+
for (const historical of parsed) {
|
|
166
|
+
const historicalVersion = `${historical.major}.${historical.minor}.${historical.patch}`;
|
|
167
|
+
add(`${historical.major}.${historical.minor}.x`, `Issues that we want to resolve in ${historical.major}.${historical.minor} line.`, 'open');
|
|
168
|
+
add(historicalVersion, `Issues that we want to release in v${historicalVersion}.`, 'closed');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return { baseline, history, desired };
|
|
172
|
+
}
|
|
173
|
+
function buildLabelDefinitions(config) {
|
|
174
|
+
const labels = config && typeof config === 'object' && !Array.isArray(config)
|
|
175
|
+
? config.labels
|
|
176
|
+
: undefined;
|
|
177
|
+
const mapping = labels && typeof labels === 'object' && !Array.isArray(labels)
|
|
178
|
+
? labels.in
|
|
179
|
+
: undefined;
|
|
180
|
+
if (mapping === undefined)
|
|
181
|
+
return [...COMMON_LABELS];
|
|
182
|
+
if (!mapping || typeof mapping !== 'object' || Array.isArray(mapping))
|
|
183
|
+
throw new Error('labels.in must be an object');
|
|
184
|
+
const dynamic = Object.keys(mapping).sort().map((key) => {
|
|
185
|
+
if (!key || /[\r\n\t]/.test(key))
|
|
186
|
+
throw new Error('labels.in keys must be non-empty single-line values');
|
|
187
|
+
return { name: `in: ${key}`, color: 'BFD4F2', description: `Module label for ${key}` };
|
|
188
|
+
});
|
|
189
|
+
return [...COMMON_LABELS, ...dynamic];
|
|
190
|
+
}
|
|
191
|
+
function configAt(root) {
|
|
192
|
+
try {
|
|
193
|
+
return JSON.parse(fs.readFileSync(path.join(root, '.agents', '.airc.json'), 'utf8'));
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return {};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function baseResult(status, context, extra = {}) {
|
|
200
|
+
return {
|
|
201
|
+
...platformResult(status, {
|
|
202
|
+
platform: context.platform,
|
|
203
|
+
capabilities: context.capabilities,
|
|
204
|
+
operations: context.operations,
|
|
205
|
+
error: context.error
|
|
206
|
+
}),
|
|
207
|
+
...extra
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function unsupported(providerType, operation) {
|
|
211
|
+
return {
|
|
212
|
+
code: 'PLATFORM_CAPABILITY_UNSUPPORTED',
|
|
213
|
+
message: `Platform '${providerType}' does not provide ${operation}`,
|
|
214
|
+
retryable: false
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function operationStatus(changed) {
|
|
218
|
+
return changed ? 'applied' : 'no-op';
|
|
219
|
+
}
|
|
220
|
+
function errorStatus(error) {
|
|
221
|
+
return error.code === 'PLATFORM_CAPABILITY_UNSUPPORTED' ? 'degraded' : providerStatus(error);
|
|
222
|
+
}
|
|
223
|
+
function initialLabelsResult(context, labels) {
|
|
224
|
+
return baseResult('degraded', context, {
|
|
225
|
+
operation: 'init-labels',
|
|
226
|
+
labels: {
|
|
227
|
+
commonCount: COMMON_LABELS.length,
|
|
228
|
+
inCount: labels.filter((item) => item.name.startsWith('in:')).length,
|
|
229
|
+
created: [], updated: [], removed: [], skipped: []
|
|
230
|
+
},
|
|
231
|
+
error: context.error || { code: 'PLATFORM_CAPABILITY_UNSUPPORTED', message: 'Label initialization is unavailable', retryable: false }
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function initialMilestonesResult(context, history) {
|
|
235
|
+
return baseResult('degraded', context, {
|
|
236
|
+
operation: 'init-milestones',
|
|
237
|
+
milestones: { baseline: null, history, desired: [], created: [], skipped: [] },
|
|
238
|
+
error: context.error || { code: 'PLATFORM_CAPABILITY_UNSUPPORTED', message: 'Milestone initialization is unavailable', retryable: false }
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function labelsFromReconciliation(initial, value) {
|
|
242
|
+
if (!value)
|
|
243
|
+
return initial.labels;
|
|
244
|
+
return {
|
|
245
|
+
...initial.labels,
|
|
246
|
+
created: value.created,
|
|
247
|
+
updated: value.updated,
|
|
248
|
+
removed: value.removed,
|
|
249
|
+
skipped: value.skipped
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
function milestonesFromInitialization(initial, value) {
|
|
253
|
+
if (!value)
|
|
254
|
+
return initial.milestones;
|
|
255
|
+
return {
|
|
256
|
+
...initial.milestones,
|
|
257
|
+
created: value.created,
|
|
258
|
+
skipped: value.skipped
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function usableContext(loaded) {
|
|
262
|
+
return loaded.ok && Boolean(loaded.value.context.platform.repository);
|
|
263
|
+
}
|
|
264
|
+
async function initializeLabels(input = {}, options = {}) {
|
|
265
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client, platformType: options.platformType });
|
|
266
|
+
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
267
|
+
let definitions;
|
|
268
|
+
try {
|
|
269
|
+
definitions = buildLabelDefinitions(loaded.ok ? configAt(loaded.value.repositoryRoot) : {});
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
return {
|
|
273
|
+
...initialLabelsResult(context, []),
|
|
274
|
+
status: 'failed',
|
|
275
|
+
error: { code: 'LABEL_CONFIG_INVALID', message: error instanceof Error ? error.message : String(error), retryable: false }
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const initial = initialLabelsResult(context, definitions);
|
|
279
|
+
if (!usableContext(loaded))
|
|
280
|
+
return { ...initial, error: initial.error || context.error };
|
|
281
|
+
const operation = loaded.value.provider.repositoryMetadata?.reconcileLabels;
|
|
282
|
+
if (!operation)
|
|
283
|
+
return { ...initial, error: unsupported(loaded.value.provider.type, 'repositoryMetadata.reconcileLabels') };
|
|
284
|
+
const reconciled = await operation({
|
|
285
|
+
context: providerOperationContext(loaded.value),
|
|
286
|
+
desired: definitions,
|
|
287
|
+
cleanupStaleIn: input.cleanupStaleIn === true,
|
|
288
|
+
mutation: { idempotencyKey: 'labels:init' }
|
|
289
|
+
});
|
|
290
|
+
if (!reconciled.ok)
|
|
291
|
+
return {
|
|
292
|
+
...initial,
|
|
293
|
+
status: errorStatus(reconciled.error),
|
|
294
|
+
changed: reconciled.value?.changed || false,
|
|
295
|
+
operations: [{ name: 'reconcile-labels', status: 'failed', reasonCode: reconciled.error.code }],
|
|
296
|
+
labels: labelsFromReconciliation(initial, reconciled.value),
|
|
297
|
+
error: providerError(reconciled.error, 'LABEL_INITIALIZATION_FAILED')
|
|
298
|
+
};
|
|
299
|
+
return {
|
|
300
|
+
...initial,
|
|
301
|
+
status: operationStatus(reconciled.value.changed),
|
|
302
|
+
changed: reconciled.value.changed,
|
|
303
|
+
operations: [{ name: 'reconcile-labels', status: operationStatus(reconciled.value.changed), reasonCode: null }],
|
|
304
|
+
labels: {
|
|
305
|
+
commonCount: COMMON_LABELS.length,
|
|
306
|
+
inCount: definitions.length - COMMON_LABELS.length,
|
|
307
|
+
created: reconciled.value.created,
|
|
308
|
+
updated: reconciled.value.updated,
|
|
309
|
+
removed: reconciled.value.removed,
|
|
310
|
+
skipped: reconciled.value.skipped
|
|
311
|
+
},
|
|
312
|
+
error: null
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function gitTags(cwd) {
|
|
316
|
+
const output = execFileSync('git', ['tag', '--list', 'v*'], { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
|
|
317
|
+
return output ? output.split(/\r?\n/).filter(Boolean) : [];
|
|
318
|
+
}
|
|
319
|
+
async function initializeMilestones(input = {}, options = {}) {
|
|
320
|
+
const history = input.history === true;
|
|
321
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client, platformType: options.platformType });
|
|
322
|
+
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
323
|
+
const initial = initialMilestonesResult(context, history);
|
|
324
|
+
if (!usableContext(loaded))
|
|
325
|
+
return initial;
|
|
326
|
+
let plan;
|
|
327
|
+
try {
|
|
328
|
+
plan = buildMilestonePlan(gitTags(loaded.value.workingDirectory), history);
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
return {
|
|
332
|
+
...initial,
|
|
333
|
+
status: 'failed',
|
|
334
|
+
error: { code: 'MILESTONE_TAG_DISCOVERY_FAILED', message: error instanceof Error ? error.message : String(error), retryable: false }
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const operation = loaded.value.provider.repositoryMetadata?.reconcileMilestones;
|
|
338
|
+
if (!operation)
|
|
339
|
+
return {
|
|
340
|
+
...initial,
|
|
341
|
+
milestones: { ...initial.milestones, baseline: plan.baseline, history, desired: plan.desired.map((item) => item.title) },
|
|
342
|
+
error: unsupported(loaded.value.provider.type, 'repositoryMetadata.reconcileMilestones')
|
|
343
|
+
};
|
|
344
|
+
const reconciled = await operation({
|
|
345
|
+
context: providerOperationContext(loaded.value),
|
|
346
|
+
desired: plan.desired,
|
|
347
|
+
mutation: { idempotencyKey: `milestones:init:${plan.baseline.version}:${history}` }
|
|
348
|
+
});
|
|
349
|
+
if (!reconciled.ok)
|
|
350
|
+
return {
|
|
351
|
+
...initial,
|
|
352
|
+
status: errorStatus(reconciled.error),
|
|
353
|
+
changed: reconciled.value?.changed || false,
|
|
354
|
+
operations: [{ name: 'reconcile-milestones', status: 'failed', reasonCode: reconciled.error.code }],
|
|
355
|
+
milestones: milestonesFromInitialization({
|
|
356
|
+
...initial,
|
|
357
|
+
milestones: { ...initial.milestones, baseline: plan.baseline, history, desired: plan.desired.map((item) => item.title) }
|
|
358
|
+
}, reconciled.value),
|
|
359
|
+
error: providerError(reconciled.error, 'MILESTONE_INITIALIZATION_FAILED')
|
|
360
|
+
};
|
|
361
|
+
return {
|
|
362
|
+
...initial,
|
|
363
|
+
status: operationStatus(reconciled.value.changed),
|
|
364
|
+
changed: reconciled.value.changed,
|
|
365
|
+
operations: [{ name: 'reconcile-milestones', status: operationStatus(reconciled.value.changed), reasonCode: null }],
|
|
366
|
+
milestones: {
|
|
367
|
+
baseline: plan.baseline,
|
|
368
|
+
history,
|
|
369
|
+
desired: plan.desired.map((item) => item.title),
|
|
370
|
+
created: reconciled.value.created,
|
|
371
|
+
skipped: reconciled.value.skipped
|
|
372
|
+
},
|
|
373
|
+
error: null
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
export { buildLabelDefinitions, buildMilestonePlan, initializeLabels, initializeMilestones };
|
|
377
|
+
//# sourceMappingURL=repository-metadata.js.map
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { resolvePlatformProviderContext } from './context.js';
|
|
4
|
+
import { providerError, providerOperationContext, providerStatus } from './provider-bridge.js';
|
|
5
|
+
import { platformResult } from './types.js';
|
|
6
|
+
function baseResult(operation, status, context, overrides = {}) {
|
|
7
|
+
return {
|
|
8
|
+
...platformResult(status, {
|
|
9
|
+
platform: context.platform,
|
|
10
|
+
capabilities: context.capabilities,
|
|
11
|
+
operations: context.operations,
|
|
12
|
+
error: context.error,
|
|
13
|
+
changed: false
|
|
14
|
+
}),
|
|
15
|
+
operation,
|
|
16
|
+
alert: null,
|
|
17
|
+
data: null,
|
|
18
|
+
...overrides
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function unsupported(providerType) {
|
|
22
|
+
return {
|
|
23
|
+
code: 'PLATFORM_CAPABILITY_UNSUPPORTED',
|
|
24
|
+
message: `Platform '${providerType}' does not provide securityAlerts`,
|
|
25
|
+
retryable: false
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function resultStatus(error) {
|
|
29
|
+
return error.code === 'PLATFORM_CAPABILITY_UNSUPPORTED' ? 'degraded' : providerStatus(error);
|
|
30
|
+
}
|
|
31
|
+
function validKind(value) {
|
|
32
|
+
return value === 'dependabot' || value === 'code-scanning';
|
|
33
|
+
}
|
|
34
|
+
function validNumber(value) {
|
|
35
|
+
return Number.isSafeInteger(value) && value > 0;
|
|
36
|
+
}
|
|
37
|
+
function unavailable(operation, context, error) {
|
|
38
|
+
const status = context.status === 'blocked' || context.status === 'failed' ? context.status : 'degraded';
|
|
39
|
+
return baseResult(operation, status, context, {
|
|
40
|
+
error: error || context.error || { code: 'PLATFORM_CAPABILITY_UNSUPPORTED', message: 'Security alert operations are unavailable', retryable: false }
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function readSecurityAlert(input, options = {}) {
|
|
44
|
+
if (!validKind(input.kind))
|
|
45
|
+
return baseResult('read', 'failed', platformResult('failed'), {
|
|
46
|
+
error: { code: 'SECURITY_KIND_INVALID', message: 'Alert kind must be dependabot or code-scanning', retryable: false }
|
|
47
|
+
});
|
|
48
|
+
if (!validNumber(input.number))
|
|
49
|
+
return baseResult('read', 'failed', platformResult('failed'), {
|
|
50
|
+
error: { code: 'SECURITY_NUMBER_INVALID', message: 'Alert number must be a positive integer', retryable: false }
|
|
51
|
+
});
|
|
52
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client, platformType: options.platformType });
|
|
53
|
+
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
54
|
+
if (!loaded.ok || !context.platform.repository)
|
|
55
|
+
return unavailable('read', context);
|
|
56
|
+
const inspect = loaded.value.provider.securityAlerts?.inspect;
|
|
57
|
+
if (!inspect)
|
|
58
|
+
return unavailable('read', context, unsupported(loaded.value.provider.type));
|
|
59
|
+
const result = await inspect({ context: providerOperationContext(loaded.value), kind: input.kind, number: input.number });
|
|
60
|
+
if (!result.ok)
|
|
61
|
+
return {
|
|
62
|
+
...baseResult('read', resultStatus(result.error), context),
|
|
63
|
+
error: providerError(result.error, 'SECURITY_ALERT_READ_FAILED')
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
...baseResult('read', 'applied', context, {
|
|
67
|
+
alert: result.value,
|
|
68
|
+
data: result.value.data,
|
|
69
|
+
operations: [{ name: 'inspect-alert', status: 'applied', reasonCode: null }]
|
|
70
|
+
}),
|
|
71
|
+
changed: false,
|
|
72
|
+
error: null
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async function dismissSecurityAlert(input, options = {}) {
|
|
76
|
+
if (!validKind(input.kind))
|
|
77
|
+
return baseResult('dismiss', 'failed', platformResult('failed'), {
|
|
78
|
+
error: { code: 'SECURITY_KIND_INVALID', message: 'Alert kind must be dependabot or code-scanning', retryable: false }
|
|
79
|
+
});
|
|
80
|
+
if (!validNumber(input.number))
|
|
81
|
+
return baseResult('dismiss', 'failed', platformResult('failed'), {
|
|
82
|
+
error: { code: 'SECURITY_NUMBER_INVALID', message: 'Alert number must be a positive integer', retryable: false }
|
|
83
|
+
});
|
|
84
|
+
if (!input.reason || typeof input.comment !== 'string')
|
|
85
|
+
return baseResult('dismiss', 'failed', platformResult('failed'), {
|
|
86
|
+
error: { code: 'SECURITY_DISMISS_INPUT_INVALID', message: 'Dismissal reason and comment are required', retryable: false }
|
|
87
|
+
});
|
|
88
|
+
const loaded = await resolvePlatformProviderContext({ cwd: options.cwd, client: options.client, platformType: options.platformType });
|
|
89
|
+
const context = loaded.ok ? loaded.value.context : loaded.context;
|
|
90
|
+
if (!loaded.ok || !context.platform.repository)
|
|
91
|
+
return unavailable('dismiss', context);
|
|
92
|
+
const inspect = loaded.value.provider.securityAlerts?.inspect;
|
|
93
|
+
const dismiss = loaded.value.provider.securityAlerts?.dismiss;
|
|
94
|
+
if (!inspect || !dismiss)
|
|
95
|
+
return unavailable('dismiss', context, unsupported(loaded.value.provider.type));
|
|
96
|
+
const current = await inspect({ context: providerOperationContext(loaded.value), kind: input.kind, number: input.number });
|
|
97
|
+
if (!current.ok)
|
|
98
|
+
return {
|
|
99
|
+
...baseResult('dismiss', resultStatus(current.error), context),
|
|
100
|
+
error: providerError(current.error, 'SECURITY_ALERT_READ_FAILED')
|
|
101
|
+
};
|
|
102
|
+
if (current.value.state === 'dismissed' || current.value.state === 'fixed')
|
|
103
|
+
return {
|
|
104
|
+
...baseResult('dismiss', 'no-op', context, {
|
|
105
|
+
alert: current.value,
|
|
106
|
+
data: current.value.data,
|
|
107
|
+
operations: [{ name: 'inspect-alert', status: 'no-op', reasonCode: 'ALREADY_CLOSED' }]
|
|
108
|
+
}),
|
|
109
|
+
error: null
|
|
110
|
+
};
|
|
111
|
+
if (current.value.state !== 'open')
|
|
112
|
+
return {
|
|
113
|
+
...baseResult('dismiss', 'failed', context, {
|
|
114
|
+
alert: current.value,
|
|
115
|
+
data: current.value.data,
|
|
116
|
+
operations: [{ name: 'inspect-alert', status: 'failed', reasonCode: 'INVALID_STATE' }]
|
|
117
|
+
}),
|
|
118
|
+
error: { code: 'SECURITY_RESPONSE_INVALID', message: 'The platform returned an alert without a valid state', retryable: false }
|
|
119
|
+
};
|
|
120
|
+
const changed = await dismiss({
|
|
121
|
+
context: providerOperationContext(loaded.value),
|
|
122
|
+
kind: input.kind,
|
|
123
|
+
number: input.number,
|
|
124
|
+
reason: input.reason,
|
|
125
|
+
comment: input.comment,
|
|
126
|
+
mutation: { idempotencyKey: `security-alert:dismiss:${input.kind}:${input.number}` }
|
|
127
|
+
});
|
|
128
|
+
if (!changed.ok)
|
|
129
|
+
return {
|
|
130
|
+
...baseResult('dismiss', resultStatus(changed.error), context, {
|
|
131
|
+
alert: current.value,
|
|
132
|
+
data: current.value.data,
|
|
133
|
+
operations: [{ name: 'dismiss-alert', status: 'failed', reasonCode: null }]
|
|
134
|
+
}),
|
|
135
|
+
error: providerError(changed.error, 'SECURITY_ALERT_DISMISS_FAILED')
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
...baseResult('dismiss', changed.value.changed ? 'applied' : 'no-op', context, {
|
|
139
|
+
operations: [{ name: 'dismiss-alert', status: changed.value.changed ? 'applied' : 'no-op', reasonCode: null }]
|
|
140
|
+
}),
|
|
141
|
+
changed: changed.value.changed,
|
|
142
|
+
error: null
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function readCommentFile(commentFile, cwd = process.cwd()) {
|
|
146
|
+
try {
|
|
147
|
+
const requested = path.resolve(cwd, commentFile);
|
|
148
|
+
return { ok: true, value: fs.readFileSync(requested, 'utf8') };
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return { ok: false, error: { code: 'SECURITY_DISMISS_INPUT_INVALID', message: 'Dismissal comment file could not be read', retryable: false } };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export { dismissSecurityAlert, readCommentFile, readSecurityAlert };
|
|
155
|
+
//# sourceMappingURL=security-alerts.js.map
|
|
@@ -6,9 +6,7 @@ import { resolvePlatformProviderContext } from "./context.js";
|
|
|
6
6
|
import { hasCheckedRequirement, resolveRequirementSection } from "./issue-metadata.js";
|
|
7
7
|
import { requirementSectionAnchors } from "./issues.js";
|
|
8
8
|
import { taskTypeLabel } from "./metadata-labels.js";
|
|
9
|
-
import { planInLabelUpdate, validateInLabelMapping
|
|
10
|
-
import { inspectGitHubPullRequest } from "./pull-requests.js";
|
|
11
|
-
import { createGitHubClient } from "./github-client.js";
|
|
9
|
+
import { planInLabelUpdate, validateInLabelMapping } from "./in-label-sync.js";
|
|
12
10
|
import { readPrDeliveryFact } from "../task/pr-delivery-fact.js";
|
|
13
11
|
import { providerError, providerOperationContext, resourceIdentityNumber, unsupportedProviderOperation } from "./provider-bridge.js";
|
|
14
12
|
import { taskIssueIdentity } from "./task-identities.js";
|
|
@@ -174,7 +172,6 @@ async function buildSyncContext({ taskDir, config, artifactFile }) {
|
|
|
174
172
|
prIdentity,
|
|
175
173
|
issueNumber,
|
|
176
174
|
prNumber,
|
|
177
|
-
upstreamRepo: platformContext.platform.repository,
|
|
178
175
|
repoOwnerType: String(loaded.ok ? loaded.value.snapshot.metadata?.ownerType || "unknown" : "unknown"),
|
|
179
176
|
hasTriage: platformContext.capabilities.triage,
|
|
180
177
|
hasPush: platformContext.capabilities.push,
|
|
@@ -281,6 +278,28 @@ async function fetchRemoteData(context) {
|
|
|
281
278
|
prComments = listed.value.map((comment) => ({ id: comment.id, body: comment.body }));
|
|
282
279
|
}
|
|
283
280
|
const changeRequest = facts.value.changeRequest;
|
|
281
|
+
let inLabelMapping = {};
|
|
282
|
+
let repositoryLabels = [];
|
|
283
|
+
if (context.config.verify_in_labels_computed && context.hasTriage) {
|
|
284
|
+
const mapping = loadInLabelMapping();
|
|
285
|
+
if (!mapping.ok)
|
|
286
|
+
return { earlyReturn: failResult(CHECK_TYPE, mapping.message, "check_failed") };
|
|
287
|
+
inLabelMapping = mapping.value;
|
|
288
|
+
if (Object.keys(inLabelMapping).length > 0) {
|
|
289
|
+
const labels = provider?.issues?.listLabels
|
|
290
|
+
? await provider.issues.listLabels({ context: operationContext })
|
|
291
|
+
: unsupportedProviderOperation(provider, "issues.listLabels");
|
|
292
|
+
if (!labels.ok) {
|
|
293
|
+
const error = providerError(labels.error, "PLATFORM_PROVIDER_OPERATION_FAILED");
|
|
294
|
+
return {
|
|
295
|
+
earlyReturn: error.retryable
|
|
296
|
+
? blockedResult(CHECK_TYPE, `${error.code}: ${error.message}`, "network_error")
|
|
297
|
+
: failResult(CHECK_TYPE, `${error.code}: ${error.message}`, "check_failed")
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
repositoryLabels = labels.value;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
284
303
|
return {
|
|
285
304
|
issue,
|
|
286
305
|
comments: facts.value.comments.map((comment) => ({ id: comment.id, body: comment.body })),
|
|
@@ -294,7 +313,9 @@ async function fetchRemoteData(context) {
|
|
|
294
313
|
? (changeRequest.milestone ? { title: changeRequest.milestone } : null)
|
|
295
314
|
: undefined,
|
|
296
315
|
prAssignees: changeRequest?.assignees,
|
|
297
|
-
prHeadSha: changeRequest?.headSha
|
|
316
|
+
prHeadSha: changeRequest?.headSha,
|
|
317
|
+
inLabelMapping,
|
|
318
|
+
repositoryLabels
|
|
298
319
|
};
|
|
299
320
|
}
|
|
300
321
|
function mapTaskTypeToLabel(taskType) {
|
|
@@ -467,7 +488,7 @@ function checkInLabelsComputed(context, remoteData) {
|
|
|
467
488
|
if (!context.config.verify_in_labels_computed || !context.hasTriage) {
|
|
468
489
|
return null;
|
|
469
490
|
}
|
|
470
|
-
const expectedInLabels = computeExpectedInLabels(context.taskDir,
|
|
491
|
+
const expectedInLabels = computeExpectedInLabels(context.taskDir, remoteData.repositoryLabels, remoteData.inLabelMapping);
|
|
471
492
|
if (!expectedInLabels.ok) {
|
|
472
493
|
return expectedInLabels.type === "check_failed"
|
|
473
494
|
? failResult(CHECK_TYPE, expectedInLabels.message, expectedInLabels.type)
|
|
@@ -767,7 +788,7 @@ function arraysEqual(left, right) {
|
|
|
767
788
|
function formatLabelList(labels) {
|
|
768
789
|
return labels.length > 0 ? labels.join(", ") : "none";
|
|
769
790
|
}
|
|
770
|
-
function computeExpectedInLabels(taskDir,
|
|
791
|
+
function computeExpectedInLabels(taskDir, repositoryLabels = [], mappingOverride) {
|
|
771
792
|
const task = loadTask(taskDir);
|
|
772
793
|
if (!task.ok) {
|
|
773
794
|
return task;
|
|
@@ -784,29 +805,15 @@ function computeExpectedInLabels(taskDir, repository) {
|
|
|
784
805
|
.split(/\r?\n/)
|
|
785
806
|
.map((value) => value.trim())
|
|
786
807
|
.filter(Boolean);
|
|
787
|
-
const mapping =
|
|
788
|
-
if (
|
|
789
|
-
return mapping;
|
|
790
|
-
}
|
|
791
|
-
if (Object.keys(mapping.value ?? {}).length === 0) {
|
|
808
|
+
const mapping = mappingOverride ?? {};
|
|
809
|
+
if (Object.keys(mapping).length === 0) {
|
|
792
810
|
return { ok: true, labels: [], mode: "mapped" };
|
|
793
811
|
}
|
|
794
|
-
const client = createGitHubClient();
|
|
795
|
-
const repoLabelsResult = withRetry(() => client.json([
|
|
796
|
-
"api", "--paginate", "--slurp", `repos/${repository}/labels?per_page=100`
|
|
797
|
-
], { cwd: taskDir }));
|
|
798
|
-
if (!repoLabelsResult.ok) {
|
|
799
|
-
return repoLabelsResult;
|
|
800
|
-
}
|
|
801
|
-
const repositoryLabels = validateRepositoryLabelPayload(repoLabelsResult.value);
|
|
802
|
-
if (!repositoryLabels.ok) {
|
|
803
|
-
return { ok: false, type: "check_failed", message: repositoryLabels.error.message };
|
|
804
|
-
}
|
|
805
812
|
const planned = planInLabelUpdate({
|
|
806
813
|
changedFiles,
|
|
807
814
|
currentLabels: [],
|
|
808
|
-
mapping
|
|
809
|
-
repositoryLabels: new Set(repositoryLabels
|
|
815
|
+
mapping,
|
|
816
|
+
repositoryLabels: new Set(repositoryLabels)
|
|
810
817
|
});
|
|
811
818
|
if (planned.error) {
|
|
812
819
|
return { ok: false, type: "check_failed", message: planned.error.message };
|
|
@@ -829,7 +836,7 @@ function loadInLabelMapping() {
|
|
|
829
836
|
return { ok: false, type: "check_failed", message: `Unable to parse .agents/.airc.json: ${error.message}` };
|
|
830
837
|
}
|
|
831
838
|
}
|
|
832
|
-
// ===
|
|
839
|
+
// === Git working tree ===
|
|
833
840
|
function gitText(args, cwd) {
|
|
834
841
|
try {
|
|
835
842
|
const value = execFileSync("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -9,6 +9,7 @@ import { readAppliedOverlays, repairSnapshot } from './repair.js';
|
|
|
9
9
|
import { collectGitHubBoundary, resolveGitHubRepository } from './sources.js';
|
|
10
10
|
import { canonicalJsonBytes, createObjectStore, findSnapshot, publishSnapshotV2, verifySnapshot } from './store.js';
|
|
11
11
|
import { createGitHubClient } from '../platform/github-client.js';
|
|
12
|
+
import { PUBLIC_CLI_ROUTE_SELECTORS } from '../internal/cli-route-inventory.js';
|
|
12
13
|
const USAGE = `Usage: ai data <command> [options]
|
|
13
14
|
|
|
14
15
|
Commands:
|
|
@@ -18,6 +19,7 @@ Commands:
|
|
|
18
19
|
repair <snapshot-id> [--root <dir>] [--apply]
|
|
19
20
|
export <snapshot-id> [--root <dir>] [--repairs none|applied] [--as-of <ISO>] [--output <file|->]
|
|
20
21
|
`;
|
|
22
|
+
const DATA_OPERATIONS = PUBLIC_CLI_ROUTE_SELECTORS.data;
|
|
21
23
|
function parseArgs(args, valueOptions, booleanOptions) {
|
|
22
24
|
const positionals = [];
|
|
23
25
|
const options = new Map();
|
|
@@ -286,6 +288,11 @@ async function cmdData(args) {
|
|
|
286
288
|
return command ? 0 : 1;
|
|
287
289
|
}
|
|
288
290
|
try {
|
|
291
|
+
if (!DATA_OPERATIONS.includes(command)) {
|
|
292
|
+
process.stderr.write(`Unknown data command: ${command}\n`);
|
|
293
|
+
process.stdout.write(USAGE);
|
|
294
|
+
return 1;
|
|
295
|
+
}
|
|
289
296
|
switch (command) {
|
|
290
297
|
case 'capture': return capture(rest);
|
|
291
298
|
case 'verify': return verify(rest);
|