@fitlab-ai/agent-infra 0.9.8 → 0.9.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/bin/internal-cli.js +11 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +58 -21
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +25 -11
- package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +173 -10
- package/dist/lib/agent-clients/adapters/codex-lifecycle/controller-context.js +127 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +14 -0
- package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +63 -92
- package/dist/lib/agent-clients/adapters/codex-sandbox.js +72 -11
- package/dist/lib/agent-clients/adapters/index.js +3 -1
- package/dist/lib/agent-clients/adapters/traecli.js +66 -0
- package/dist/lib/agent-clients/tokens.js +2 -2
- package/dist/lib/agent-clients/types.js +2 -1
- package/dist/lib/defaults.json +5 -0
- package/dist/lib/git/workflow.js +10 -1
- package/dist/lib/internal/codex-lifecycle.js +20 -6
- package/dist/lib/internal/codex-sandbox-controller.js +9 -15
- package/dist/lib/internal/git-workflow.js +5 -7
- package/dist/lib/internal/platform-pr.js +20 -7
- package/dist/lib/internal/release-workflow.js +2 -1
- package/dist/lib/internal/sandbox-control.js +79 -2
- package/dist/lib/internal/task-finalization.js +54 -0
- package/dist/lib/internal/task-orchestration.js +156 -291
- package/dist/lib/{task/commands/validate.js → internal/task-validate.js} +75 -42
- package/dist/lib/platform/pr-summary.js +48 -10
- package/dist/lib/platform/pull-requests.js +205 -41
- package/dist/lib/run/tui.js +5 -2
- package/dist/lib/sandbox/commands/rm.js +316 -55
- package/dist/lib/sandbox/control/client.js +190 -6
- package/dist/lib/sandbox/control/controller-registration.js +275 -0
- package/dist/lib/sandbox/control/executor.js +140 -5
- package/dist/lib/sandbox/control/lifecycle.js +3 -1
- package/dist/lib/sandbox/control/protocol.js +67 -6
- package/dist/lib/sandbox/index.js +5 -3
- package/dist/lib/sandbox/managed-fs.js +5 -0
- package/dist/lib/sandbox/task-resolver.js +50 -6
- package/dist/lib/sandbox/workspace-identity.js +27 -0
- package/dist/lib/sandbox/worktree-safety.js +215 -2
- package/dist/lib/task/codex-orchestration.js +161 -39
- package/dist/lib/task/commands/status.js +59 -1
- package/dist/lib/task/commit-operation.js +335 -0
- package/dist/lib/task/commit-policy.js +18 -0
- package/dist/lib/task/delegation-receipts.js +248 -6
- package/dist/lib/task/finalization.js +593 -0
- package/dist/lib/task/index.js +0 -9
- package/dist/lib/task/operation-outcome.js +33 -0
- package/dist/lib/task/orchestration.js +187 -761
- package/dist/lib/task/short-id.js +59 -1
- package/dist/lib/task/task-execution-lock.js +6 -1
- package/dist/lib/task/verification-engine.js +110 -60
- package/dist/lib/task/verification.js +2 -1
- package/dist/lib/task/workflow-warning-intents.js +50 -1
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +61 -19
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +37 -10
- package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +276 -12
- package/lib/agent-clients/adapters/codex-lifecycle/controller-context.ts +163 -0
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +19 -0
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +9 -1
- package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +91 -118
- package/lib/agent-clients/adapters/codex-sandbox.ts +89 -14
- package/lib/agent-clients/adapters/index.ts +3 -1
- package/lib/agent-clients/adapters/traecli.ts +67 -0
- package/lib/agent-clients/tokens.ts +2 -2
- package/lib/agent-clients/types.ts +2 -1
- package/lib/defaults.json +5 -0
- package/lib/git/workflow.ts +11 -2
- package/lib/internal/codex-lifecycle.ts +19 -6
- package/lib/internal/codex-sandbox-controller.ts +9 -14
- package/lib/internal/git-workflow.ts +5 -6
- package/lib/internal/platform-pr.ts +14 -7
- package/lib/internal/release-workflow.ts +2 -1
- package/lib/internal/sandbox-control.ts +92 -2
- package/lib/internal/task-finalization.ts +68 -0
- package/lib/internal/task-orchestration.ts +20 -103
- package/lib/{task/commands/validate.ts → internal/task-validate.ts} +75 -40
- package/lib/platform/pr-summary.ts +55 -11
- package/lib/platform/pull-requests.ts +211 -41
- package/lib/run/tui.ts +5 -3
- package/lib/sandbox/commands/rm.ts +413 -61
- package/lib/sandbox/control/client.ts +255 -6
- package/lib/sandbox/control/controller-registration.ts +352 -0
- package/lib/sandbox/control/executor.ts +169 -5
- package/lib/sandbox/control/lifecycle.ts +2 -1
- package/lib/sandbox/control/protocol.ts +80 -7
- package/lib/sandbox/index.ts +5 -3
- package/lib/sandbox/managed-fs.ts +5 -0
- package/lib/sandbox/task-resolver.ts +58 -7
- package/lib/sandbox/workspace-identity.ts +50 -2
- package/lib/sandbox/workspace-view.ts +3 -3
- package/lib/sandbox/worktree-safety.ts +236 -2
- package/lib/task/codex-orchestration.ts +168 -40
- package/lib/task/commands/status.ts +78 -1
- package/lib/task/commit-operation.ts +430 -0
- package/lib/task/commit-policy.ts +30 -0
- package/lib/task/delegation-receipts.ts +263 -4
- package/lib/task/finalization.ts +761 -0
- package/lib/task/index.ts +0 -8
- package/lib/task/operation-outcome.ts +48 -0
- package/lib/task/orchestration.ts +218 -982
- package/lib/task/short-id.ts +65 -1
- package/lib/task/task-execution-lock.ts +10 -1
- package/lib/task/verification-engine.ts +115 -63
- package/lib/task/verification.ts +3 -2
- package/lib/task/workflow-warning-intents.ts +57 -2
- package/package.json +2 -2
- package/templates/.agents/QUICKSTART.en.md +3 -4
- package/templates/.agents/QUICKSTART.zh-CN.md +3 -4
- package/templates/.agents/hooks/lifecycle-delegation.js +1 -21
- package/templates/.agents/rules/README.en.md +1 -0
- package/templates/.agents/rules/README.zh-CN.md +1 -0
- package/templates/.agents/rules/compatibility-policy.en.md +39 -0
- package/templates/.agents/rules/compatibility-policy.zh-CN.md +39 -0
- package/templates/.agents/rules/lifecycle-orchestration.en.md +4 -4
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +4 -4
- package/templates/.agents/rules/pr-sync.en.md +1 -1
- package/templates/.agents/rules/pr-sync.github.en.md +2 -1
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +2 -0
- package/templates/.agents/rules/pr-sync.zh-CN.md +1 -0
- package/templates/.agents/rules/review-method.en.md +1 -0
- package/templates/.agents/rules/review-method.zh-CN.md +1 -0
- package/templates/.agents/rules/task-management.en.md +2 -2
- package/templates/.agents/rules/task-management.zh-CN.md +2 -2
- package/templates/.agents/skills/analyze-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +1 -0
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -4
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -4
- package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/close-codescan/SKILL.en.md +6 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +6 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +6 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +6 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -0
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/commit/SKILL.en.md +41 -125
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +52 -123
- package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +14 -43
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +14 -49
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +2 -35
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +2 -35
- package/templates/.agents/skills/complete-task/SKILL.en.md +31 -38
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +31 -38
- package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
- package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
- package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +17 -9
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +17 -9
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +41 -0
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +41 -0
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +2 -2
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -1
- package/templates/.agents/skills/review-code/reference/migration-risks.en.md +8 -6
- package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +8 -6
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +3 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +1 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -2
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -2
- package/templates/.agents/skills/run-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +2 -2
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +2 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +24 -0
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +1 -1
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +1 -1
- package/templates/.codex/hooks.json +4 -4
- package/templates/.trae/skills/update-agent-infra.en.md +8 -0
- package/templates/.trae/skills/update-agent-infra.zh-CN.md +8 -0
- package/dist/lib/task/commit-finalization.js +0 -305
- package/dist/lib/task/commit-intent.js +0 -165
- package/lib/task/commit-finalization.ts +0 -419
- package/lib/task/commit-intent.ts +0 -230
|
@@ -8,6 +8,13 @@ import { resolvePlatformContext } from './context.js';
|
|
|
8
8
|
import { createGitHubClient } from './github-client.js';
|
|
9
9
|
import { listRemoteComments, normalizeCommentContent, writeComment } from './issue-comments.js';
|
|
10
10
|
import { platformResult } from './types.js';
|
|
11
|
+
function warningResultForPrimary(primaryResult) {
|
|
12
|
+
if (primaryResult === 'pr_created')
|
|
13
|
+
return 'pr_created_with_warnings';
|
|
14
|
+
if (primaryResult === 'pr_reused')
|
|
15
|
+
return 'pr_reused_with_warnings';
|
|
16
|
+
return 'no_op_with_warnings';
|
|
17
|
+
}
|
|
11
18
|
function summaryMarker(taskId) {
|
|
12
19
|
return `<!-- sync-pr:${taskId}:summary -->`;
|
|
13
20
|
}
|
|
@@ -51,40 +58,71 @@ function summaryContext(taskRef, options = {}) {
|
|
|
51
58
|
return { ...platformResult('no-op'), task: { id: resolved.taskId, prNumber }, artifacts: canonicalArtifacts(resolved.taskDir) };
|
|
52
59
|
}
|
|
53
60
|
function syncPullRequestSummary(taskRef, options) {
|
|
61
|
+
const warningResult = warningResultForPrimary(options.primaryResult);
|
|
62
|
+
let knownPrNumber = null;
|
|
63
|
+
const softenFailure = (output) => {
|
|
64
|
+
const prNumber = output.resource.kind === 'pull-request' && output.resource.number
|
|
65
|
+
? output.resource.number
|
|
66
|
+
: knownPrNumber;
|
|
67
|
+
const warning = output.error && prNumber
|
|
68
|
+
&& output.error.code !== 'PR_NOT_LINKED'
|
|
69
|
+
? {
|
|
70
|
+
code: output.error.code,
|
|
71
|
+
message: output.error.message,
|
|
72
|
+
retryable: output.error.retryable,
|
|
73
|
+
step: 'pr-summary',
|
|
74
|
+
target: `pull-request:${prNumber}`,
|
|
75
|
+
severity: 'ACTION_REQUIRED'
|
|
76
|
+
}
|
|
77
|
+
: null;
|
|
78
|
+
return warning
|
|
79
|
+
? {
|
|
80
|
+
...output,
|
|
81
|
+
status: 'applied',
|
|
82
|
+
changed: false,
|
|
83
|
+
resource: { kind: 'pull-request', number: prNumber },
|
|
84
|
+
error: null,
|
|
85
|
+
result: warningResult,
|
|
86
|
+
warnings: [warning]
|
|
87
|
+
}
|
|
88
|
+
: { ...output, result: null, warnings: [] };
|
|
89
|
+
};
|
|
54
90
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
55
91
|
if (!resolved.ok)
|
|
56
|
-
return platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } });
|
|
92
|
+
return softenFailure(platformResult('failed', { error: { code: resolved.code, message: resolved.message, retryable: false } }));
|
|
57
93
|
const frontmatter = parseTaskFrontmatter(fs.readFileSync(resolved.taskMdPath, 'utf8'));
|
|
58
94
|
const prNumber = Number(frontmatter.pr_number);
|
|
59
95
|
if (!Number.isInteger(prNumber) || prNumber <= 0)
|
|
60
|
-
return platformResult('failed', { error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false } });
|
|
96
|
+
return softenFailure(platformResult('failed', { error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false } }));
|
|
97
|
+
knownPrNumber = prNumber;
|
|
61
98
|
const client = options.client || createGitHubClient();
|
|
62
99
|
const context = resolvePlatformContext({ cwd: resolved.repoRoot, client });
|
|
63
100
|
if (!context.platform.repository || !['no-op', 'degraded'].includes(context.status))
|
|
64
|
-
return context;
|
|
101
|
+
return softenFailure(context);
|
|
65
102
|
let headSha;
|
|
66
103
|
try {
|
|
67
104
|
headSha = execFileSync('git', ['rev-parse', 'HEAD'], { cwd: resolved.repoRoot, encoding: 'utf8' }).trim();
|
|
68
105
|
}
|
|
69
106
|
catch (error) {
|
|
70
|
-
return platformResult('failed', { platform: context.platform, capabilities: context.capabilities, error: { code: 'GIT_HEAD_UNRESOLVED', message: error instanceof Error ? error.message : String(error), retryable: false } });
|
|
107
|
+
return softenFailure(platformResult('failed', { platform: context.platform, capabilities: context.capabilities, error: { code: 'GIT_HEAD_UNRESOLVED', message: error instanceof Error ? error.message : String(error), retryable: false } }));
|
|
71
108
|
}
|
|
72
109
|
const desired = buildPullRequestSummary(resolved.taskId, options.body, headSha, renderHumanOverrideAudit(fs.readFileSync(resolved.taskMdPath, 'utf8')));
|
|
73
110
|
const listed = listRemoteComments(client, context.platform.repository, prNumber, resolved.repoRoot);
|
|
74
111
|
if (!listed.ok)
|
|
75
|
-
return platformResult(listed.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: listed.error });
|
|
112
|
+
return softenFailure(platformResult(listed.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: listed.error }));
|
|
76
113
|
const reconciliation = reconcileSummaryComment(listed.value, resolved.taskId, desired);
|
|
77
114
|
if (reconciliation.action === 'conflict')
|
|
78
|
-
return platformResult('failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: { code: 'PR_SUMMARY_MARKER_AMBIGUOUS', message: 'Multiple PR comments contain the summary marker', retryable: false } });
|
|
115
|
+
return softenFailure(platformResult('failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: { code: 'PR_SUMMARY_MARKER_AMBIGUOUS', message: 'Multiple PR comments contain the summary marker', retryable: false } }));
|
|
79
116
|
if (reconciliation.action === 'no-op')
|
|
80
|
-
return platformResult('no-op', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: [reconciliation.commentId], parts: 1 }, error: null });
|
|
117
|
+
return softenFailure(platformResult('no-op', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: [reconciliation.commentId], parts: 1 }, error: null }));
|
|
81
118
|
if (options.dryRun)
|
|
82
|
-
return platformResult('planned', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, operations: [{ name: `summary:${reconciliation.action}`, status: 'planned', reasonCode: null }], error: null });
|
|
119
|
+
return softenFailure(platformResult('planned', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, operations: [{ name: `summary:${reconciliation.action}`, status: 'planned', reasonCode: null }], error: null }));
|
|
83
120
|
const written = writeComment(client, context.platform.repository, prNumber, resolved.repoRoot, desired, reconciliation.commentId || undefined);
|
|
84
121
|
if (!written.ok)
|
|
85
|
-
return platformResult(written.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: written.error });
|
|
122
|
+
return softenFailure(platformResult(written.error.retryable ? 'blocked' : 'failed', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, error: written.error }));
|
|
86
123
|
const id = Number(written.value.id || reconciliation.commentId);
|
|
87
|
-
return platformResult('applied', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: Number.isInteger(id) ? [id] : [], parts: 1 }, operations: [{ name: `summary:${reconciliation.action}`, status: 'applied', reasonCode: null }], error: null });
|
|
124
|
+
return softenFailure(platformResult('applied', { platform: context.platform, capabilities: context.capabilities, resource: { kind: 'pull-request', number: prNumber }, comment: { kind: 'summary', marker: summaryMarker(resolved.taskId), ids: Number.isInteger(id) ? [id] : [], parts: 1 }, operations: [{ name: `summary:${reconciliation.action}`, status: 'applied', reasonCode: null }], error: null }));
|
|
88
125
|
}
|
|
89
126
|
export { buildPullRequestSummary, reconcileSummaryComment, summaryContext, summaryMarker, syncPullRequestSummary };
|
|
127
|
+
export { warningResultForPrimary };
|
|
90
128
|
//# sourceMappingURL=pr-summary.js.map
|
|
@@ -11,15 +11,25 @@ import { inspectPlatformIssue } from './issues.js';
|
|
|
11
11
|
import { planPullRequestMetadata } from './pull-request-metadata.js';
|
|
12
12
|
import { platformResult } from './types.js';
|
|
13
13
|
import { inspectCompletionArtifacts } from '../task/finalization-artifacts.js';
|
|
14
|
-
import { inspectCreatePrCommitGate } from '../task/commit-finalization.js';
|
|
15
14
|
import { TaskExecutionLockError, withTaskExecutionLock } from '../task/task-execution-lock.js';
|
|
15
|
+
import { mergeOperationWarnings } from '../task/operation-outcome.js';
|
|
16
|
+
function warningResultForPrimary(primaryResult) {
|
|
17
|
+
if (primaryResult === 'pr_created')
|
|
18
|
+
return 'pr_created_with_warnings';
|
|
19
|
+
if (primaryResult === 'pr_reused')
|
|
20
|
+
return 'pr_reused_with_warnings';
|
|
21
|
+
return 'no_op_with_warnings';
|
|
22
|
+
}
|
|
16
23
|
function result(status, taskId, issueNumber, prNumber, overrides = {}) {
|
|
17
|
-
|
|
24
|
+
const output = {
|
|
18
25
|
...platformResult(status),
|
|
19
26
|
task: { id: taskId, issueNumber, prNumber },
|
|
20
27
|
pullRequest: null,
|
|
28
|
+
result: null,
|
|
29
|
+
warnings: [],
|
|
21
30
|
...overrides
|
|
22
31
|
};
|
|
32
|
+
return { ...output, warnings: mergeOperationWarnings(output.warnings) };
|
|
23
33
|
}
|
|
24
34
|
function externalResult(base, overrides = {}) {
|
|
25
35
|
return {
|
|
@@ -202,7 +212,7 @@ function expectedHead(repository, head) {
|
|
|
202
212
|
const repoName = repository.split('/')[1] || '';
|
|
203
213
|
return { repository: `${head.slice(0, colon)}/${repoName}`, ref: head.slice(colon + 1) };
|
|
204
214
|
}
|
|
205
|
-
function selectPullRequest(remotes, repository, head, base) {
|
|
215
|
+
function selectPullRequest(remotes, repository, head, base, expectedSha) {
|
|
206
216
|
const wanted = expectedHead(repository, head);
|
|
207
217
|
const matches = remotes.flatMap((remote) => {
|
|
208
218
|
const normalized = normalizePullRequest(remote, repository);
|
|
@@ -210,10 +220,89 @@ function selectPullRequest(remotes, repository, head, base) {
|
|
|
210
220
|
normalized.head.ref === wanted.ref && normalized.base.repository === repository && normalized.base.ref === base
|
|
211
221
|
? [normalized] : [];
|
|
212
222
|
});
|
|
223
|
+
if (expectedSha && matches.some((match) => match.head.sha !== expectedSha)) {
|
|
224
|
+
return { status: 'head-mismatch', pullRequest: null };
|
|
225
|
+
}
|
|
213
226
|
if (matches.length === 1)
|
|
214
227
|
return { status: 'resolved', pullRequest: matches[0] };
|
|
215
228
|
return { status: matches.length === 0 ? 'missing' : 'ambiguous', pullRequest: null };
|
|
216
229
|
}
|
|
230
|
+
function repositoryHead(cwd) {
|
|
231
|
+
return execFileSync('git', ['rev-parse', 'HEAD'], {
|
|
232
|
+
cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe']
|
|
233
|
+
}).trim();
|
|
234
|
+
}
|
|
235
|
+
function remoteBranchHead(cwd, repository, head) {
|
|
236
|
+
const wanted = expectedHead(repository, head);
|
|
237
|
+
if (!wanted.ref || !/^[A-Za-z0-9._/-]+$/.test(wanted.ref))
|
|
238
|
+
return {
|
|
239
|
+
ok: false,
|
|
240
|
+
error: { code: 'PR_HEAD_INVALID', message: 'Pull request head ref is invalid', retryable: false }
|
|
241
|
+
};
|
|
242
|
+
const remotes = configuredGitRemotes(cwd);
|
|
243
|
+
const remote = remotes.find((item) => repositoryKey(item.repository) === repositoryKey(wanted.repository))
|
|
244
|
+
?? remotes.find((item) => item.name === 'origin');
|
|
245
|
+
if (!remote)
|
|
246
|
+
return {
|
|
247
|
+
ok: false,
|
|
248
|
+
error: { code: 'PR_REMOTE_BRANCH_MISSING', message: `No configured remote can verify ${wanted.repository}:${wanted.ref}`, retryable: false }
|
|
249
|
+
};
|
|
250
|
+
try {
|
|
251
|
+
const output = execFileSync('git', ['ls-remote', '--refs', remote.name, `refs/heads/${wanted.ref}`], {
|
|
252
|
+
cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe']
|
|
253
|
+
}).trim();
|
|
254
|
+
const match = output.split(/\r?\n/).map((line) => line.trim()).find((line) => line.endsWith(`refs/heads/${wanted.ref}`));
|
|
255
|
+
const sha = match?.split(/\s+/)[0] || null;
|
|
256
|
+
if (!sha || !/^[a-f0-9]{40}$/i.test(sha))
|
|
257
|
+
return {
|
|
258
|
+
ok: false,
|
|
259
|
+
error: { code: 'PR_REMOTE_BRANCH_MISSING', message: `Remote branch ${wanted.repository}:${wanted.ref} does not exist`, retryable: false }
|
|
260
|
+
};
|
|
261
|
+
return { ok: true, value: sha };
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
return {
|
|
265
|
+
ok: false,
|
|
266
|
+
error: { code: 'PR_REMOTE_BRANCH_UNAVAILABLE', message: error instanceof Error ? error.message : String(error), retryable: true }
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function verifyCreateHead(base, head) {
|
|
271
|
+
let localHead;
|
|
272
|
+
try {
|
|
273
|
+
localHead = repositoryHead(base.resolved.repoRoot);
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
return { ok: false, error: { code: 'PR_LOCAL_HEAD_UNAVAILABLE', message: error instanceof Error ? error.message : String(error), retryable: false } };
|
|
277
|
+
}
|
|
278
|
+
const remote = remoteBranchHead(base.resolved.repoRoot, base.context.platform.repository, head);
|
|
279
|
+
if (!remote.ok)
|
|
280
|
+
return remote;
|
|
281
|
+
if (remote.value !== localHead)
|
|
282
|
+
return {
|
|
283
|
+
ok: false,
|
|
284
|
+
error: { code: 'PR_REMOTE_HEAD_MISMATCH', message: `Remote head ${remote.value} does not match local HEAD ${localHead}`, retryable: false }
|
|
285
|
+
};
|
|
286
|
+
return { ok: true, value: localHead };
|
|
287
|
+
}
|
|
288
|
+
function validateBoundPullRequest(base, pullRequest, head, baseRef, expectedSha) {
|
|
289
|
+
if (!pullRequest)
|
|
290
|
+
return {
|
|
291
|
+
ok: false,
|
|
292
|
+
error: { code: 'PR_BIND_RECHECK_FAILED', message: 'Bound pull request identity is unavailable', retryable: false }
|
|
293
|
+
};
|
|
294
|
+
const wanted = expectedHead(base.context.platform.repository, head);
|
|
295
|
+
if (pullRequest.head.repository !== wanted.repository
|
|
296
|
+
|| pullRequest.head.ref !== wanted.ref
|
|
297
|
+
|| pullRequest.head.sha !== expectedSha
|
|
298
|
+
|| pullRequest.base.repository !== base.context.platform.repository
|
|
299
|
+
|| pullRequest.base.ref !== baseRef)
|
|
300
|
+
return {
|
|
301
|
+
ok: false,
|
|
302
|
+
error: { code: 'PR_BIND_IDENTITY_MISMATCH', message: 'Bound pull request identity does not match the current expected head/base', retryable: false }
|
|
303
|
+
};
|
|
304
|
+
return { ok: true };
|
|
305
|
+
}
|
|
217
306
|
function resolvedContext(taskRef, options) {
|
|
218
307
|
const resolved = resolveTaskRef(taskRef, options.cwd ? { repoRoot: options.cwd } : {});
|
|
219
308
|
if (!resolved.ok)
|
|
@@ -338,19 +427,22 @@ registerPlatformCapabilities('github', {
|
|
|
338
427
|
return resolveGitHubChangeRequestGitEvidence(context);
|
|
339
428
|
}
|
|
340
429
|
});
|
|
341
|
-
function locatePullRequest(base, head, target) {
|
|
430
|
+
function locatePullRequest(base, head, target, expectedSha) {
|
|
342
431
|
const repository = base.context.platform.repository;
|
|
343
432
|
const listed = base.client.json([
|
|
344
433
|
'api', `repos/${repository}/pulls?state=open&base=${encodeURIComponent(target)}&per_page=100`
|
|
345
434
|
], { cwd: base.resolved.repoRoot });
|
|
346
435
|
if (!listed.ok)
|
|
347
436
|
return listed;
|
|
348
|
-
const selected = selectPullRequest(listed.value, repository, head, target);
|
|
437
|
+
const selected = selectPullRequest(listed.value, repository, head, target, expectedSha);
|
|
349
438
|
return selected.status === 'resolved'
|
|
350
439
|
? { ok: true, value: selected.pullRequest }
|
|
351
440
|
: { ok: false, error: {
|
|
352
|
-
code: selected.status === 'ambiguous' ? 'PR_IDENTITY_AMBIGUOUS'
|
|
353
|
-
|
|
441
|
+
code: selected.status === 'ambiguous' ? 'PR_IDENTITY_AMBIGUOUS'
|
|
442
|
+
: selected.status === 'head-mismatch' ? 'PR_HEAD_SHA_MISMATCH' : 'PR_NOT_FOUND',
|
|
443
|
+
message: selected.status === 'ambiguous' ? 'Multiple pull requests match the exact head/base identity'
|
|
444
|
+
: selected.status === 'head-mismatch' ? 'A pull request matches head/base but not the expected head SHA'
|
|
445
|
+
: 'No pull request matches the exact head/base identity',
|
|
354
446
|
retryable: false
|
|
355
447
|
} };
|
|
356
448
|
}
|
|
@@ -622,28 +714,47 @@ function createPlatformPullRequestUnlocked(taskRef, options) {
|
|
|
622
714
|
return result('failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
623
715
|
error: { code: 'PR_PAYLOAD_INVALID', message: 'base, head, title and body are required', retryable: false }
|
|
624
716
|
});
|
|
625
|
-
if (base.prNumber)
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
717
|
+
if (base.prNumber) {
|
|
718
|
+
const headCheck = verifyCreateHead(base, options.head);
|
|
719
|
+
if (!headCheck.ok)
|
|
720
|
+
return result(headCheck.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
721
|
+
platform: base.context.platform,
|
|
722
|
+
capabilities: base.context.capabilities,
|
|
723
|
+
error: headCheck.error
|
|
724
|
+
});
|
|
725
|
+
const inspected = inspectPlatformPullRequest(taskRef, options);
|
|
726
|
+
const identity = validateBoundPullRequest(base, inspected.pullRequest, options.head, options.base, headCheck.value);
|
|
727
|
+
if (!identity.ok)
|
|
728
|
+
return result('failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
729
|
+
platform: base.context.platform,
|
|
730
|
+
capabilities: base.context.capabilities,
|
|
731
|
+
pullRequest: inspected.pullRequest,
|
|
732
|
+
error: identity.error
|
|
733
|
+
});
|
|
734
|
+
return { ...inspected, result: 'no_op' };
|
|
735
|
+
}
|
|
736
|
+
const headCheck = verifyCreateHead(base, options.head);
|
|
737
|
+
if (!headCheck.ok)
|
|
738
|
+
return result(headCheck.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, null, {
|
|
630
739
|
platform: base.context.platform,
|
|
631
740
|
capabilities: base.context.capabilities,
|
|
632
|
-
error:
|
|
633
|
-
code: gate.code,
|
|
634
|
-
message: `${gate.message}; action=${gate.action}`,
|
|
635
|
-
retryable: gate.action === 'rerun-commit' || gate.action === 'rerun-review-code'
|
|
636
|
-
}
|
|
741
|
+
error: headCheck.error
|
|
637
742
|
});
|
|
638
|
-
const
|
|
743
|
+
const expectedHeadSha = headCheck.value;
|
|
744
|
+
const located = locatePullRequest(base, options.head, options.base, expectedHeadSha);
|
|
639
745
|
if (!located.ok && located.error.code === 'PR_IDENTITY_AMBIGUOUS')
|
|
640
746
|
return result('failed', base.resolved.taskId, base.issueNumber, null, {
|
|
641
747
|
platform: base.context.platform, capabilities: base.context.capabilities, error: located.error
|
|
642
748
|
});
|
|
749
|
+
if (!located.ok && located.error.code === 'PR_HEAD_SHA_MISMATCH')
|
|
750
|
+
return result('failed', base.resolved.taskId, base.issueNumber, null, {
|
|
751
|
+
platform: base.context.platform, capabilities: base.context.capabilities, error: located.error
|
|
752
|
+
});
|
|
643
753
|
if (options.dryRun)
|
|
644
754
|
return result('planned', base.resolved.taskId, base.issueNumber, null, {
|
|
645
755
|
platform: base.context.platform, capabilities: base.context.capabilities,
|
|
646
|
-
operations: [{ name: located.ok ? 'pr:reuse' : 'pr:create', status: 'planned', reasonCode: null }],
|
|
756
|
+
operations: [{ name: located.ok ? 'pr:reuse' : 'pr:create', status: 'planned', reasonCode: null }],
|
|
757
|
+
result: located.ok ? 'pr_reused' : 'pr_created', error: null
|
|
647
758
|
});
|
|
648
759
|
const started = writeCreateStarted(base, options.agent);
|
|
649
760
|
if (started.status === 'failed')
|
|
@@ -662,7 +773,7 @@ function createPlatformPullRequestUnlocked(taskRef, options) {
|
|
|
662
773
|
if (response.ok)
|
|
663
774
|
pullRequest = normalizePullRequest(response.value, repository);
|
|
664
775
|
else if (response.error.retryable) {
|
|
665
|
-
const recovered = locatePullRequest(base, options.head, options.base);
|
|
776
|
+
const recovered = locatePullRequest(base, options.head, options.base, expectedHeadSha);
|
|
666
777
|
if (recovered.ok)
|
|
667
778
|
pullRequest = recovered.value;
|
|
668
779
|
else
|
|
@@ -681,8 +792,44 @@ function createPlatformPullRequestUnlocked(taskRef, options) {
|
|
|
681
792
|
return result('failed', base.resolved.taskId, base.issueNumber, null, {
|
|
682
793
|
error: { code: 'PR_CREATE_RESPONSE_INVALID', message: 'PR create response lacks validated identity', retryable: false }
|
|
683
794
|
});
|
|
795
|
+
if (pullRequest.head.sha !== expectedHeadSha)
|
|
796
|
+
return result('failed', base.resolved.taskId, base.issueNumber, pullRequest.number, {
|
|
797
|
+
platform: base.context.platform, capabilities: base.context.capabilities,
|
|
798
|
+
resource: { kind: 'pull-request', number: pullRequest.number }, pullRequest,
|
|
799
|
+
error: { code: 'PR_HEAD_SHA_MISMATCH', message: 'Created pull request head does not match the expected local HEAD', retryable: false }
|
|
800
|
+
});
|
|
684
801
|
created = true;
|
|
685
802
|
}
|
|
803
|
+
const bindHeadCheck = verifyCreateHead(base, options.head);
|
|
804
|
+
if (!bindHeadCheck.ok || bindHeadCheck.value !== expectedHeadSha) {
|
|
805
|
+
const error = bindHeadCheck.ok
|
|
806
|
+
? { code: 'PR_REMOTE_HEAD_MISMATCH', message: 'Remote head changed before task binding', retryable: false }
|
|
807
|
+
: bindHeadCheck.error;
|
|
808
|
+
return result(error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, pullRequest.number, {
|
|
809
|
+
platform: base.context.platform, capabilities: base.context.capabilities,
|
|
810
|
+
resource: { kind: 'pull-request', number: pullRequest.number }, pullRequest, error
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
const beforeBind = inspectGitHubPullRequest(base.client, base.context.platform.repository, pullRequest.number, base.resolved.repoRoot);
|
|
814
|
+
if (!beforeBind.ok || !beforeBind.value) {
|
|
815
|
+
const error = beforeBind.ok
|
|
816
|
+
? { code: 'PR_BIND_RECHECK_FAILED', message: 'Pull request recheck returned no identity', retryable: false }
|
|
817
|
+
: beforeBind.error;
|
|
818
|
+
return result(error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, pullRequest.number, {
|
|
819
|
+
platform: base.context.platform, capabilities: base.context.capabilities,
|
|
820
|
+
resource: { kind: 'pull-request', number: pullRequest.number }, pullRequest, error
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
if (beforeBind.value.head.sha !== expectedHeadSha
|
|
824
|
+
|| beforeBind.value.head.ref !== expectedHead(base.context.platform.repository, options.head).ref
|
|
825
|
+
|| beforeBind.value.base.ref !== options.base
|
|
826
|
+
|| beforeBind.value.base.repository !== base.context.platform.repository)
|
|
827
|
+
return result('failed', base.resolved.taskId, base.issueNumber, pullRequest.number, {
|
|
828
|
+
platform: base.context.platform, capabilities: base.context.capabilities,
|
|
829
|
+
resource: { kind: 'pull-request', number: pullRequest.number }, pullRequest: beforeBind.value,
|
|
830
|
+
error: { code: 'PR_BIND_IDENTITY_MISMATCH', message: 'Pull request identity changed before task binding', retryable: false }
|
|
831
|
+
});
|
|
832
|
+
pullRequest = beforeBind.value;
|
|
686
833
|
const refreshed = resolvedContext(taskRef, options);
|
|
687
834
|
if (!refreshed.ok)
|
|
688
835
|
return result('failed', base.resolved.taskId, base.issueNumber, null, {
|
|
@@ -699,7 +846,8 @@ function createPlatformPullRequestUnlocked(taskRef, options) {
|
|
|
699
846
|
return result('applied', base.resolved.taskId, base.issueNumber, pullRequest.number, {
|
|
700
847
|
changed: true, platform: base.context.platform, capabilities: base.context.capabilities,
|
|
701
848
|
resource: { kind: 'pull-request', number: pullRequest.number }, pullRequest,
|
|
702
|
-
operations: [{ name: created ? 'pr:create' : 'pr:reuse', status: created ? 'applied' : 'no-op', reasonCode: null }, { name: 'task:bind-pr', status: 'applied', reasonCode: null }],
|
|
849
|
+
operations: [{ name: created ? 'pr:create' : 'pr:reuse', status: created ? 'applied' : 'no-op', reasonCode: null }, { name: 'task:bind-pr', status: 'applied', reasonCode: null }],
|
|
850
|
+
result: created ? 'pr_created' : 'pr_reused', error: null
|
|
703
851
|
});
|
|
704
852
|
}
|
|
705
853
|
function createPlatformPullRequest(taskRef, options) {
|
|
@@ -711,8 +859,6 @@ function createPlatformPullRequest(taskRef, options) {
|
|
|
711
859
|
error: { code: 'PR_PAYLOAD_INVALID', message: 'base, head, title and body are required', retryable: false }
|
|
712
860
|
});
|
|
713
861
|
}
|
|
714
|
-
if (base.prNumber)
|
|
715
|
-
return inspectPlatformPullRequest(taskRef, options);
|
|
716
862
|
try {
|
|
717
863
|
return withTaskExecutionLock(base.resolved.repoRoot, base.resolved.taskId, 'platform-pr.create', () => createPlatformPullRequestUnlocked(taskRef, options));
|
|
718
864
|
}
|
|
@@ -736,29 +882,46 @@ function createPlatformPullRequest(taskRef, options) {
|
|
|
736
882
|
}
|
|
737
883
|
}
|
|
738
884
|
function syncPlatformPullRequest(taskRef, options) {
|
|
885
|
+
const warningResult = warningResultForPrimary(options.primaryResult);
|
|
886
|
+
const softenFailure = (output) => {
|
|
887
|
+
const warning = output.error && output.task.prNumber !== null
|
|
888
|
+
&& !['PR_NOT_LINKED', 'PR_BIND_CONFLICT'].includes(output.error.code)
|
|
889
|
+
? {
|
|
890
|
+
code: output.error.code,
|
|
891
|
+
message: output.error.message,
|
|
892
|
+
retryable: output.error.retryable,
|
|
893
|
+
step: 'pr-metadata',
|
|
894
|
+
target: `pull-request:${output.task.prNumber}`,
|
|
895
|
+
severity: 'ACTION_REQUIRED'
|
|
896
|
+
}
|
|
897
|
+
: null;
|
|
898
|
+
return warning
|
|
899
|
+
? { ...output, status: 'applied', changed: false, error: null, result: warningResult, warnings: mergeOperationWarnings([warning]) }
|
|
900
|
+
: output;
|
|
901
|
+
};
|
|
739
902
|
const base = resolvedContext(taskRef, options);
|
|
740
903
|
if (!base.ok)
|
|
741
|
-
return base.output;
|
|
904
|
+
return softenFailure(base.output);
|
|
742
905
|
if (!base.prNumber)
|
|
743
|
-
return result('failed', base.resolved.taskId, base.issueNumber, null, {
|
|
906
|
+
return softenFailure(result('failed', base.resolved.taskId, base.issueNumber, null, {
|
|
744
907
|
error: { code: 'PR_NOT_LINKED', message: 'Task has no valid pr_number', retryable: false }
|
|
745
|
-
});
|
|
908
|
+
}));
|
|
746
909
|
const fetched = inspectGitHubPullRequest(base.client, base.context.platform.repository, base.prNumber, base.resolved.repoRoot);
|
|
747
910
|
if (!fetched.ok)
|
|
748
|
-
return result(fetched.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, { error: fetched.error });
|
|
911
|
+
return softenFailure(result(fetched.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, { error: fetched.error }));
|
|
749
912
|
if (!options.metadata && !options.closingIssue)
|
|
750
|
-
return result('failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
913
|
+
return softenFailure(result('failed', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
751
914
|
error: { code: 'PR_PAYLOAD_INVALID', message: 'sync requires a desired-state option', retryable: false }
|
|
752
|
-
});
|
|
915
|
+
}));
|
|
753
916
|
if (!base.issueNumber)
|
|
754
|
-
return result('degraded', base.resolved.taskId, null, base.prNumber, {
|
|
917
|
+
return softenFailure(result('degraded', base.resolved.taskId, null, base.prNumber, {
|
|
755
918
|
pullRequest: fetched.value, error: { code: 'ISSUE_NOT_LINKED', message: 'Task has no linked Issue to copy metadata from', retryable: false }
|
|
756
|
-
});
|
|
919
|
+
}));
|
|
757
920
|
const issue = inspectPlatformIssue(taskRef, { cwd: base.resolved.repoRoot, client: base.client });
|
|
758
921
|
if (!issue.issue)
|
|
759
|
-
return result(issue.status, base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
922
|
+
return softenFailure(result(issue.status, base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
760
923
|
platform: base.context.platform, capabilities: base.context.capabilities, pullRequest: fetched.value, error: issue.error
|
|
761
|
-
});
|
|
924
|
+
}));
|
|
762
925
|
const planned = planPullRequestMetadata({
|
|
763
926
|
pullRequest: fetched.value,
|
|
764
927
|
issue: issue.issue,
|
|
@@ -769,9 +932,9 @@ function syncPlatformPullRequest(taskRef, options) {
|
|
|
769
932
|
.filter((operation) => options.closingIssue || operation.name !== 'closing-issue');
|
|
770
933
|
const operations = planned.map(({ name, status, reasonCode }) => ({ name, status, reasonCode }));
|
|
771
934
|
if (options.dryRun)
|
|
772
|
-
return result(planned.some((operation) => operation.status === 'planned') ? 'planned' : 'no-op', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
935
|
+
return softenFailure(result(planned.some((operation) => operation.status === 'planned') ? 'planned' : 'no-op', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
773
936
|
platform: base.context.platform, capabilities: base.context.capabilities, pullRequest: fetched.value, operations, error: null
|
|
774
|
-
});
|
|
937
|
+
}));
|
|
775
938
|
const payload = {};
|
|
776
939
|
for (const operation of planned) {
|
|
777
940
|
if (operation.status !== 'planned')
|
|
@@ -785,27 +948,28 @@ function syncPlatformPullRequest(taskRef, options) {
|
|
|
785
948
|
if (operation.name === 'milestone') {
|
|
786
949
|
const milestones = base.client.json(['api', '--paginate', '--slurp', `repos/${base.context.platform.repository}/milestones?state=open&per_page=100`], { cwd: base.resolved.repoRoot });
|
|
787
950
|
if (!milestones.ok)
|
|
788
|
-
return result(milestones.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, { pullRequest: fetched.value, operations, error: milestones.error });
|
|
951
|
+
return softenFailure(result(milestones.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, { pullRequest: fetched.value, operations, error: milestones.error }));
|
|
789
952
|
const flat = milestones.value.flatMap((entry) => Array.isArray(entry) ? entry : [entry]);
|
|
790
953
|
payload.milestone = flat.find((entry) => entry.title === operation.value)?.number ?? null;
|
|
791
954
|
}
|
|
792
955
|
}
|
|
793
956
|
if (Object.keys(payload).length === 0) {
|
|
794
957
|
const degraded = planned.some((operation) => operation.status === 'skipped');
|
|
795
|
-
return result(degraded ? 'degraded' : 'no-op', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
958
|
+
return softenFailure(result(degraded ? 'degraded' : 'no-op', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
796
959
|
platform: base.context.platform, capabilities: base.context.capabilities, resource: { kind: 'pull-request', number: base.prNumber }, pullRequest: fetched.value, operations, error: null
|
|
797
|
-
});
|
|
960
|
+
}));
|
|
798
961
|
}
|
|
799
962
|
const patched = base.client.json(['api', `repos/${base.context.platform.repository}/issues/${base.prNumber}`, '-X', 'PATCH', '--input', '-'], {
|
|
800
963
|
cwd: base.resolved.repoRoot, method: 'PATCH', input: JSON.stringify(payload)
|
|
801
964
|
});
|
|
802
965
|
if (!patched.ok)
|
|
803
|
-
return result(patched.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, { pullRequest: fetched.value, operations, error: patched.error });
|
|
804
|
-
return result(planned.some((operation) => operation.status === 'skipped') ? 'degraded' : 'applied', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
966
|
+
return softenFailure(result(patched.error.retryable ? 'blocked' : 'failed', base.resolved.taskId, base.issueNumber, base.prNumber, { pullRequest: fetched.value, operations, error: patched.error }));
|
|
967
|
+
return softenFailure(result(planned.some((operation) => operation.status === 'skipped') ? 'degraded' : 'applied', base.resolved.taskId, base.issueNumber, base.prNumber, {
|
|
805
968
|
changed: true, platform: base.context.platform, capabilities: base.context.capabilities,
|
|
806
969
|
resource: { kind: 'pull-request', number: base.prNumber }, pullRequest: fetched.value,
|
|
807
970
|
operations: operations.map((operation) => operation.status === 'planned' ? { ...operation, status: 'applied' } : operation), error: null
|
|
808
|
-
});
|
|
971
|
+
}));
|
|
809
972
|
}
|
|
810
973
|
export { bindPlatformPullRequest, createPlatformPullRequest, inspectGitHubPullRequest, inspectGitHubIssueClosingChangeRequests, inspectPlatformPullRequest, inspectPlatformPullRequestByNumber, normalizePullRequest, resolveGitHubChangeRequestGitEvidence, resolveExternalPullRequest, selectExternalPullRequest, selectPullRequest, syncPlatformPullRequest };
|
|
974
|
+
export { warningResultForPrimary };
|
|
811
975
|
//# sourceMappingURL=pull-requests.js.map
|
package/dist/lib/run/tui.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { renderAgentClientInvocation } from '../agent-clients/invocation.js';
|
|
2
2
|
import { getAgentClientAdapter } from '../agent-clients/registry.js';
|
|
3
|
-
const TUI_NAMES = new Set(['claude', 'codex', 'antigravity', 'opencode']);
|
|
3
|
+
const TUI_NAMES = new Set(['claude', 'codex', 'antigravity', 'opencode', 'traecli']);
|
|
4
4
|
const TUI_AGENT_CLIENT_IDS = Object.freeze({
|
|
5
5
|
claude: 'claude-code',
|
|
6
6
|
codex: 'codex',
|
|
7
7
|
antigravity: 'antigravity-cli',
|
|
8
|
-
opencode: 'opencode'
|
|
8
|
+
opencode: 'opencode',
|
|
9
|
+
traecli: 'traecli'
|
|
9
10
|
});
|
|
10
11
|
function isTuiName(value) {
|
|
11
12
|
return typeof value === 'string' && TUI_NAMES.has(value);
|
|
@@ -33,6 +34,8 @@ export function buildTuiCommand(tui, prompt) {
|
|
|
33
34
|
return ['agy', ['--dangerously-skip-permissions', '--print', prompt]];
|
|
34
35
|
if (tui === 'opencode')
|
|
35
36
|
return ['opencode', ['run', '--dangerously-skip-permissions', prompt]];
|
|
37
|
+
if (tui === 'traecli')
|
|
38
|
+
return ['traecli', ['exec', '--dangerously-bypass-approvals-and-sandbox', prompt]];
|
|
36
39
|
return ['codex', ['exec', '--dangerously-bypass-approvals-and-sandbox', prompt]];
|
|
37
40
|
}
|
|
38
41
|
//# sourceMappingURL=tui.js.map
|