codex-orchestrator 2.0.13 → 2.0.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/CHANGELOG.md +7 -0
- package/dist/src/v2/acceptance-proof.js +1 -4
- package/dist/src/v2/acceptance-proof.js.map +1 -1
- package/dist/src/v2/containment.d.ts +1 -0
- package/dist/src/v2/containment.d.ts.map +1 -1
- package/dist/src/v2/containment.js +7 -1
- package/dist/src/v2/containment.js.map +1 -1
- package/dist/src/v2/pending-effect-settlement.d.ts +2 -2
- package/dist/src/v2/pending-effect-settlement.d.ts.map +1 -1
- package/dist/src/v2/pending-effect-settlement.js +2 -2
- package/dist/src/v2/pending-effect-settlement.js.map +1 -1
- package/dist/src/v2/run-issue.d.ts.map +1 -1
- package/dist/src/v2/run-issue.js +121 -68
- package/dist/src/v2/run-issue.js.map +1 -1
- package/dist/src/v2/run-state-projections.d.ts.map +1 -1
- package/dist/src/v2/run-state-projections.js +1 -1
- package/dist/src/v2/run-state-projections.js.map +1 -1
- package/dist/src/v2/run-store.d.ts +22 -7
- package/dist/src/v2/run-store.d.ts.map +1 -1
- package/dist/src/v2/run-store.js +27 -13
- package/dist/src/v2/run-store.js.map +1 -1
- package/dist/src/v2/runtime.d.ts.map +1 -1
- package/dist/src/v2/runtime.js +2 -4
- package/dist/src/v2/runtime.js.map +1 -1
- package/internal-workflow/manifest.json +1 -1
- package/internal-workflow/skills/tickets-orchestrator/SKILL.md +4 -0
- package/internal-workflow/skills/to-spec/SKILL.md +17 -8
- package/internal-workflow/skills/to-spec/evals/evals.json +6 -0
- package/internal-workflow/skills/to-tickets/SKILL.md +29 -2
- package/internal-workflow/skills/to-tickets/evals/evals.json +12 -0
- package/package.json +1 -1
package/dist/src/v2/run-issue.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dirname, resolve } from 'node:path';
|
|
2
2
|
import { checkedChangePayloadSha256, } from './checked-change.js';
|
|
3
3
|
import { parseAgentAutoConfig } from './config.js';
|
|
4
|
-
import { canonicalJson, containsCredentialEvidence, parseJsonWithoutDuplicateKeys, sha256 } from './containment.js';
|
|
4
|
+
import { canonicalJson, containsCredentialEvidence, containsHostIdentityEvidence, parseJsonWithoutDuplicateKeys, sha256 } from './containment.js';
|
|
5
5
|
import { findDeniedPathMatch } from './adapters/path-policy.js';
|
|
6
6
|
import { adoptActiveAttempt, confirmActiveAttemptCleanup, createActiveAttempt, launchActiveAttempt, observeActiveAttempt, } from './active-attempt.js';
|
|
7
7
|
import { validateImplementationReport } from './implementation-report.js';
|
|
@@ -774,13 +774,13 @@ export class RunIssue {
|
|
|
774
774
|
baseBranch: config.github.baseBranch,
|
|
775
775
|
});
|
|
776
776
|
if (!pullRequest?.number || !pullRequest.nodeId || !pullRequest.headSha) {
|
|
777
|
-
return { result: await this.
|
|
777
|
+
return { result: await this.terminal(starting, { status: 'blocked', kind: 'safety', resumable: false }, 'review-feedback-pr-identity-missing') };
|
|
778
778
|
}
|
|
779
779
|
const expectedHeadSha = feedback.previousPublishedHeadSha === null
|
|
780
780
|
? pullRequest.headSha
|
|
781
781
|
: feedback.previousPublishedHeadSha;
|
|
782
782
|
if (!expectedHeadSha) {
|
|
783
|
-
return { result: await this.
|
|
783
|
+
return { result: await this.terminal(starting, { status: 'blocked', kind: 'safety', resumable: false }, 'review-feedback-head-missing') };
|
|
784
784
|
}
|
|
785
785
|
const observed = await this.dependencies.reviewFeedback.observeAndFreeze({
|
|
786
786
|
runId: starting.record.runId,
|
|
@@ -801,7 +801,7 @@ export class RunIssue {
|
|
|
801
801
|
if (observed.status === 'retryable')
|
|
802
802
|
return { result: await this.invokedFailure(starting, 'review-feedback-observation-retryable') };
|
|
803
803
|
if (observed.status === 'blocked') {
|
|
804
|
-
return { result: await this.
|
|
804
|
+
return { result: await this.terminal(starting, { status: 'blocked', kind: 'safety', resumable: false }, 'review-feedback-observation-blocked') };
|
|
805
805
|
}
|
|
806
806
|
if (feedback.previousPublishedHeadSha === null) {
|
|
807
807
|
const sourceIds = observed.status === 'frozen'
|
|
@@ -1004,14 +1004,20 @@ export class RunIssue {
|
|
|
1004
1004
|
const seed = parseTerminalSeedSummary(active.record.pendingEffect.summary);
|
|
1005
1005
|
return await this.persistTerminal(active, seed, active.record.pendingEffect.code, false);
|
|
1006
1006
|
}
|
|
1007
|
-
if (active.record.pendingEffect?.kind === '
|
|
1008
|
-
return await this.
|
|
1007
|
+
if (active.record.pendingEffect?.kind === 'blocked-comment') {
|
|
1008
|
+
return await this.publishBlockedTerminal(active, {
|
|
1009
|
+
status: 'blocked',
|
|
1010
|
+
kind: active.record.pendingEffect.blockKind,
|
|
1011
|
+
resumable: active.record.pendingEffect.resumable,
|
|
1012
|
+
...(active.record.pendingEffect.blocker ? { blocker: active.record.pendingEffect.blocker } : {}),
|
|
1013
|
+
}, active.record.pendingEffect.evidenceCode);
|
|
1009
1014
|
}
|
|
1010
1015
|
if (active.record.pendingEffect?.kind === 'blocked-labels') {
|
|
1011
1016
|
return await this.publishBlockedTerminal(active, {
|
|
1012
1017
|
status: 'blocked',
|
|
1013
1018
|
kind: active.record.pendingEffect.blockKind,
|
|
1014
1019
|
resumable: active.record.pendingEffect.resumable,
|
|
1020
|
+
...(active.record.pendingEffect.blocker ? { blocker: active.record.pendingEffect.blocker } : {}),
|
|
1015
1021
|
}, active.record.pendingEffect.evidenceCode);
|
|
1016
1022
|
}
|
|
1017
1023
|
if (existing.terminalOutcome?.status === 'blocked'
|
|
@@ -1193,7 +1199,7 @@ export class RunIssue {
|
|
|
1193
1199
|
}
|
|
1194
1200
|
attemptLoop: while (true) {
|
|
1195
1201
|
if (!await this.authorized(active, config)) {
|
|
1196
|
-
return await this.terminal(active, { status: 'blocked', kind: 'safety', resumable: true });
|
|
1202
|
+
return await this.terminal(active, { status: 'blocked', kind: 'safety', resumable: true }, 'authorization-revoked');
|
|
1197
1203
|
}
|
|
1198
1204
|
if (this.signal.aborted)
|
|
1199
1205
|
return await this.terminal(active, { status: 'cancelled' });
|
|
@@ -1328,7 +1334,7 @@ export class RunIssue {
|
|
|
1328
1334
|
return await this.terminal(active, implementationBlockerOutcome(report.blocker));
|
|
1329
1335
|
}
|
|
1330
1336
|
if (await this.dependencies.git.getHead(worktreePath) !== expectedImplementationHead(active.record)) {
|
|
1331
|
-
return await this.terminal(active, { status: 'blocked', kind: 'safety', resumable: true });
|
|
1337
|
+
return await this.terminal(active, { status: 'blocked', kind: 'safety', resumable: true }, 'implementation-head-drift');
|
|
1332
1338
|
}
|
|
1333
1339
|
const changedFiles = await this.dependencies.git.listChangedFiles(worktreePath);
|
|
1334
1340
|
if (changedFiles.length === 0 || !sameStrings(changedFiles, report.changedFiles)) {
|
|
@@ -2392,7 +2398,7 @@ export class RunIssue {
|
|
|
2392
2398
|
: this.persistCandidateEvidenceSafetyTerminal(active, 'candidate-execution-missing');
|
|
2393
2399
|
}
|
|
2394
2400
|
if (inspection.value === 'mutated') {
|
|
2395
|
-
return this.
|
|
2401
|
+
return this.terminal(active, { status: 'blocked', kind: 'safety', resumable: false }, 'candidate-materialization-mutated');
|
|
2396
2402
|
}
|
|
2397
2403
|
if (active.record.activeAttempt?.stage === 'observed' && active.record.activeAttempt.result) {
|
|
2398
2404
|
return { active };
|
|
@@ -2484,7 +2490,7 @@ export class RunIssue {
|
|
|
2484
2490
|
reviewFeedback: blockReviewFeedback(active.record.reviewFeedback, 'safety', this.timestamp()),
|
|
2485
2491
|
});
|
|
2486
2492
|
}
|
|
2487
|
-
return this.
|
|
2493
|
+
return this.terminal(active, { status: 'blocked', kind: 'safety', resumable: false }, evidenceCode);
|
|
2488
2494
|
}
|
|
2489
2495
|
mapCandidateFailure(active, code) {
|
|
2490
2496
|
if (code === 'candidate-unstable' || code === 'candidate-io-failed' || code === 'candidate-materialization-io-failed') {
|
|
@@ -2860,49 +2866,7 @@ export class RunIssue {
|
|
|
2860
2866
|
const feedback = active.record.reviewFeedback;
|
|
2861
2867
|
if (!feedback?.activeBatch)
|
|
2862
2868
|
return this.terminal(active, { status: 'blocked', kind, resumable: false }, evidenceCode);
|
|
2863
|
-
{
|
|
2864
|
-
const config = active.config;
|
|
2865
|
-
const blockedLabels = [config.github.labels.auto.name, config.github.labels.blocked.name].sort();
|
|
2866
|
-
const existingIntent = active.record.pendingEffect;
|
|
2867
|
-
if (existingIntent?.kind !== 'review-blocked-labels') {
|
|
2868
|
-
active = await this.persist(active, { pendingEffect: {
|
|
2869
|
-
kind: 'review-blocked-labels', issueNumber: active.record.issueNumber,
|
|
2870
|
-
batchId: feedback.activeBatch.batchId, expected: blockedLabels, blockKind: kind, evidenceCode,
|
|
2871
|
-
} });
|
|
2872
|
-
}
|
|
2873
|
-
else if (existingIntent.issueNumber !== active.record.issueNumber
|
|
2874
|
-
|| existingIntent.batchId !== feedback.activeBatch.batchId
|
|
2875
|
-
|| !sameStrings(existingIntent.expected, blockedLabels)
|
|
2876
|
-
|| existingIntent.blockKind !== kind
|
|
2877
|
-
|| existingIntent.evidenceCode !== evidenceCode) {
|
|
2878
|
-
return this.invokedFailure(active, 'review-feedback-blocked-labels-pendingEffect-diverged');
|
|
2879
|
-
}
|
|
2880
|
-
const ownedRunningLabels = [config.github.labels.auto.name, config.github.labels.running.name].sort();
|
|
2881
|
-
const ownedReviewLabels = [config.github.labels.review.name];
|
|
2882
|
-
const effect = active.record.pendingEffect;
|
|
2883
|
-
if (effect?.kind !== 'review-blocked-labels') {
|
|
2884
|
-
return this.invokedFailure(active, 'review-feedback-blocked-labels-pendingEffect-diverged');
|
|
2885
|
-
}
|
|
2886
|
-
const settlement = await settleLabelsEffect(effect, {
|
|
2887
|
-
observe: async () => {
|
|
2888
|
-
const issue = await this.readIssue(active.record.issueNumber);
|
|
2889
|
-
if (!issue || issue.state !== 'OPEN')
|
|
2890
|
-
return 'diverged';
|
|
2891
|
-
if (sameStrings(issue.labels, blockedLabels))
|
|
2892
|
-
return 'confirmed';
|
|
2893
|
-
return sameStrings(issue.labels, ownedRunningLabels) || sameStrings(issue.labels, ownedReviewLabels)
|
|
2894
|
-
? 'absent' : 'diverged';
|
|
2895
|
-
},
|
|
2896
|
-
invoke: () => this.dependencies.issues.setLabels(active.record.issueNumber, blockedLabels),
|
|
2897
|
-
});
|
|
2898
|
-
if (settlement.status === 'unknown') {
|
|
2899
|
-
return this.invokedFailure(active, 'review-feedback-blocked-labels-delivery-unknown');
|
|
2900
|
-
}
|
|
2901
|
-
if (settlement.status !== 'confirmed') {
|
|
2902
|
-
return this.invokedFailure(active, 'review-feedback-blocked-labels-observation-diverged');
|
|
2903
|
-
}
|
|
2904
|
-
}
|
|
2905
|
-
return this.persistTerminal(active, outcome, evidenceCode, false, {
|
|
2869
|
+
return this.publishBlockedTerminal(active, outcome, evidenceCode, {
|
|
2906
2870
|
reviewFeedback: blockReviewFeedback(feedback, kind, this.timestamp()),
|
|
2907
2871
|
}, true);
|
|
2908
2872
|
}
|
|
@@ -2937,7 +2901,7 @@ export class RunIssue {
|
|
|
2937
2901
|
async revoked(active) {
|
|
2938
2902
|
if (active.record.pendingEffect)
|
|
2939
2903
|
return this.invokedFailure(active, 'revoked-with-pending-effect');
|
|
2940
|
-
return this.terminal(active, { status: 'blocked', kind: 'safety', resumable: true });
|
|
2904
|
+
return this.terminal(active, { status: 'blocked', kind: 'safety', resumable: true }, 'authorization-revoked');
|
|
2941
2905
|
}
|
|
2942
2906
|
async invokedFailure(active, code, summary = 'Publication delivery requires reconciliation.') {
|
|
2943
2907
|
const evidence = await this.dependencies.writeEvidence({ runId: active.record.runId, code, summary });
|
|
@@ -2992,23 +2956,68 @@ export class RunIssue {
|
|
|
2992
2956
|
}
|
|
2993
2957
|
return this.persistTerminal(active, outcome, evidenceCode, retainIntent);
|
|
2994
2958
|
}
|
|
2995
|
-
async publishBlockedTerminal(starting, outcome, evidenceCode) {
|
|
2959
|
+
async publishBlockedTerminal(starting, outcome, evidenceCode, additionalChanges = {}, replaceExistingIntent = false) {
|
|
2996
2960
|
let active = starting;
|
|
2961
|
+
const body = blockedComment(active.record.runId, outcome, evidenceCode);
|
|
2962
|
+
const marker = body.split('\n')[0];
|
|
2963
|
+
const commentIntent = {
|
|
2964
|
+
kind: 'blocked-comment',
|
|
2965
|
+
issueNumber: active.record.issueNumber,
|
|
2966
|
+
marker,
|
|
2967
|
+
bodySha256: sha256(body),
|
|
2968
|
+
blockKind: outcome.kind,
|
|
2969
|
+
resumable: outcome.resumable,
|
|
2970
|
+
evidenceCode,
|
|
2971
|
+
...(outcome.blocker ? { blocker: outcome.blocker } : {}),
|
|
2972
|
+
};
|
|
2997
2973
|
const autoBlocked = [active.config.github.labels.auto.name, active.config.github.labels.blocked.name].sort();
|
|
2998
2974
|
const blockedOnly = [active.config.github.labels.blocked.name];
|
|
2999
2975
|
let expected = autoBlocked;
|
|
3000
|
-
|
|
3001
|
-
if (!existing) {
|
|
3002
|
-
active = await this.persist(active, { pendingEffect:
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
2976
|
+
let existing = active.record.pendingEffect;
|
|
2977
|
+
if (!existing || replaceExistingIntent) {
|
|
2978
|
+
active = await this.persist(active, { ...additionalChanges, pendingEffect: commentIntent });
|
|
2979
|
+
existing = active.record.pendingEffect;
|
|
2980
|
+
}
|
|
2981
|
+
if (existing?.kind === 'blocked-comment') {
|
|
2982
|
+
if (existing.issueNumber !== commentIntent.issueNumber || existing.marker !== marker
|
|
2983
|
+
|| existing.bodySha256 !== sha256(body) || existing.blockKind !== outcome.kind
|
|
2984
|
+
|| existing.resumable !== outcome.resumable || existing.evidenceCode !== evidenceCode) {
|
|
2985
|
+
return this.invokedFailure(active, 'blocked-comment-pendingEffect-diverged');
|
|
2986
|
+
}
|
|
2987
|
+
const settlement = await settleCommentEffect(existing, {
|
|
2988
|
+
observe: async () => {
|
|
2989
|
+
const observation = await this.readIssue(active.record.issueNumber);
|
|
2990
|
+
if (!observation || observation.state !== 'OPEN')
|
|
2991
|
+
return 'diverged';
|
|
2992
|
+
const matching = observation ? commentsWithMarker(observation, marker) : [];
|
|
2993
|
+
if (matching.length === 0)
|
|
2994
|
+
return 'absent';
|
|
2995
|
+
return matching.length === 1 && sha256(matching[0].body) === sha256(body)
|
|
2996
|
+
? 'confirmed' : 'diverged';
|
|
2997
|
+
},
|
|
2998
|
+
invoke: () => this.dependencies.issues.postComment(active.record.issueNumber, body),
|
|
2999
|
+
});
|
|
3000
|
+
if (settlement.status === 'unknown')
|
|
3001
|
+
return this.invokedFailure(active, 'blocked-comment-delivery-unknown');
|
|
3002
|
+
if (settlement.status !== 'confirmed')
|
|
3003
|
+
return this.invokedFailure(active, 'blocked-comment-observation-diverged');
|
|
3004
|
+
try {
|
|
3005
|
+
active = await this.persist(active, { pendingEffect: {
|
|
3006
|
+
kind: 'blocked-labels',
|
|
3007
|
+
issueNumber: active.record.issueNumber,
|
|
3008
|
+
expected,
|
|
3009
|
+
blockKind: outcome.kind,
|
|
3010
|
+
resumable: outcome.resumable,
|
|
3011
|
+
evidenceCode,
|
|
3012
|
+
...(outcome.blocker ? { blocker: outcome.blocker } : {}),
|
|
3013
|
+
} });
|
|
3014
|
+
}
|
|
3015
|
+
catch {
|
|
3016
|
+
throw new PostEffectStateError(active);
|
|
3017
|
+
}
|
|
3018
|
+
existing = active.record.pendingEffect;
|
|
3010
3019
|
}
|
|
3011
|
-
|
|
3020
|
+
if (existing?.kind !== 'blocked-labels'
|
|
3012
3021
|
|| existing.issueNumber !== active.record.issueNumber
|
|
3013
3022
|
|| existing.blockKind !== outcome.kind
|
|
3014
3023
|
|| existing.resumable !== outcome.resumable
|
|
@@ -3059,8 +3068,7 @@ export class RunIssue {
|
|
|
3059
3068
|
}
|
|
3060
3069
|
}
|
|
3061
3070
|
try {
|
|
3062
|
-
|
|
3063
|
-
return await this.persistTerminal(active, outcome, evidenceCode, false);
|
|
3071
|
+
return await this.persistTerminal(active, outcome, evidenceCode, false, {}, true);
|
|
3064
3072
|
}
|
|
3065
3073
|
catch {
|
|
3066
3074
|
throw new PostEffectStateError(active);
|
|
@@ -3277,6 +3285,51 @@ function pendingCandidateBoundary(record) {
|
|
|
3277
3285
|
function commentsWithMarker(issue, marker) {
|
|
3278
3286
|
return issue.comments.filter((comment) => comment.body.split('\n')[0] === marker);
|
|
3279
3287
|
}
|
|
3288
|
+
function blockedComment(runId, outcome, evidenceCode) {
|
|
3289
|
+
const lines = [
|
|
3290
|
+
`<!-- codex-orchestrator:run:${runId}:blocked -->`,
|
|
3291
|
+
'codex-orchestrator blocked this run.',
|
|
3292
|
+
'',
|
|
3293
|
+
`Kind: ${outcome.kind}`,
|
|
3294
|
+
`Resumable: ${outcome.resumable ? 'yes' : 'no'}`,
|
|
3295
|
+
];
|
|
3296
|
+
if (outcome.blocker) {
|
|
3297
|
+
lines.push('', `Reason: ${publicBlockedText(outcome.blocker.summary, evidenceCode, 2_000)}`);
|
|
3298
|
+
if (outcome.blocker.reviewerRejectionDetail) {
|
|
3299
|
+
lines.push(`Detail: ${publicBlockedText(outcome.blocker.reviewerRejectionDetail, 'Review detail was unsafe or unavailable.', 2_000)}`);
|
|
3300
|
+
}
|
|
3301
|
+
if (outcome.blocker.attempted.length > 0) {
|
|
3302
|
+
const attempted = [];
|
|
3303
|
+
let remaining = 8_000;
|
|
3304
|
+
for (const attempt of outcome.blocker.attempted.slice(0, 16)) {
|
|
3305
|
+
if (remaining <= 0)
|
|
3306
|
+
break;
|
|
3307
|
+
const text = publicBlockedText(attempt, 'Unsafe or unavailable attempted action.', Math.min(2_000, remaining));
|
|
3308
|
+
attempted.push(`- ${text}`);
|
|
3309
|
+
remaining -= text.length;
|
|
3310
|
+
}
|
|
3311
|
+
lines.push('', 'Attempted:', ...attempted);
|
|
3312
|
+
}
|
|
3313
|
+
else {
|
|
3314
|
+
lines.push('', 'Attempted:', '- No attempted actions were recorded.');
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
else {
|
|
3318
|
+
lines.push('', `Reason: ${evidenceCode}`, '', 'Attempted:', '- No attempted actions were recorded.');
|
|
3319
|
+
}
|
|
3320
|
+
return lines.join('\n');
|
|
3321
|
+
}
|
|
3322
|
+
function publicBlockedText(value, fallback, maxLength) {
|
|
3323
|
+
if (containsCredentialEvidence(value) || containsHostIdentityEvidence(value)
|
|
3324
|
+
|| /["']?token["']?\s*[:=]\s*["']?[^\s"']{8,}/iu.test(value))
|
|
3325
|
+
return fallback;
|
|
3326
|
+
const normalized = value.replace(/[\r\n]+/gu, ' ').trim();
|
|
3327
|
+
if (normalized.length === 0)
|
|
3328
|
+
return fallback;
|
|
3329
|
+
return normalized.length <= maxLength
|
|
3330
|
+
? normalized
|
|
3331
|
+
: `${normalized.slice(0, Math.max(0, maxLength - 12))} [truncated]`;
|
|
3332
|
+
}
|
|
3280
3333
|
function sortedUnique(values) {
|
|
3281
3334
|
return [...new Set(values)].sort();
|
|
3282
3335
|
}
|