@fitlab-ai/agent-infra 0.11.9 → 0.11.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/dist/bin/internal-cli.js +0 -6
- package/dist/lib/git/workflow.js +1 -1
- package/dist/lib/internal/cli-route-inventory.js +0 -3
- package/dist/lib/internal/sandbox-control.js +30 -5
- package/dist/lib/internal/task-finalization.js +14 -23
- package/dist/lib/internal/task-operation-registry.js +2 -3
- package/dist/lib/internal/task-platform-recovery.js +9 -4
- package/dist/lib/platform/completion-backfill.js +2 -1
- package/dist/lib/platform/context.js +4 -2
- package/dist/lib/platform/github-client.js +20 -17
- package/dist/lib/platform/github-provider.js +42 -22
- package/dist/lib/platform/github-release-notes.js +4 -2
- package/dist/lib/platform/in-label-sync.js +2 -1
- package/dist/lib/platform/issue-comments.js +13 -9
- package/dist/lib/platform/operation-coordinator.js +1 -1
- package/dist/lib/platform/pr-review.js +2 -1
- package/dist/lib/platform/provider-bridge.js +4 -5
- package/dist/lib/platform/provider-contract.d.ts +3 -6
- package/dist/lib/platform/provider-contract.js +3 -15
- package/dist/lib/platform/provider-validation.js +9 -4
- package/dist/lib/platform/pull-requests.js +4 -2
- package/dist/lib/sandbox/control/client.js +54 -6
- package/dist/lib/sandbox/control/executor.js +8 -3
- package/dist/lib/sandbox/removal.js +0 -1
- package/dist/lib/task/artifact-command.js +11 -1
- package/dist/lib/task/artifact-lifecycle.js +119 -62
- package/dist/lib/task/artifact-selection.js +1 -1
- package/dist/lib/task/capabilities.js +55 -21
- package/dist/lib/task/commands/status.js +0 -27
- package/dist/lib/task/commit-identity.js +22 -7
- package/dist/lib/task/commit-intent.js +67 -26
- package/dist/lib/task/commit-operation.js +19 -8
- package/dist/lib/task/completion-facts.js +32 -10
- package/dist/lib/task/control-authority.js +2 -4
- package/dist/lib/task/current-contract.js +1 -5
- package/dist/lib/task/events.js +8 -274
- package/dist/lib/task/execution-inputs.js +14 -0
- package/dist/lib/task/finalization-envelope.js +4 -0
- package/dist/lib/task/finalization.js +10 -36
- package/dist/lib/task/frontmatter.js +1 -1
- package/dist/lib/task/ledger-intents.js +4 -7
- package/dist/lib/task/orchestration.js +11 -10
- package/dist/lib/task/platform-operation-journal.js +17 -10
- package/dist/lib/task/platform-operation-recovery.js +95 -28
- package/dist/lib/task/review-fingerprint.js +4 -26
- package/dist/lib/task/verification-engine.js +95 -6
- package/dist/lib/task/write.js +0 -11
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/git/workflow.ts +1 -1
- package/lib/internal/cli-route-inventory.ts +0 -2
- package/lib/internal/sandbox-control.ts +39 -6
- package/lib/internal/task-finalization.ts +16 -24
- package/lib/internal/task-operation-registry.ts +2 -3
- package/lib/internal/task-platform-recovery.ts +9 -4
- package/lib/platform/completion-backfill.ts +2 -1
- package/lib/platform/context.ts +8 -4
- package/lib/platform/github-client.ts +24 -20
- package/lib/platform/github-provider.ts +47 -26
- package/lib/platform/github-release-notes.ts +5 -3
- package/lib/platform/in-label-sync.ts +2 -1
- package/lib/platform/issue-comments.ts +14 -9
- package/lib/platform/operation-coordinator.ts +1 -1
- package/lib/platform/pr-review.ts +2 -1
- package/lib/platform/provider-bridge.ts +10 -9
- package/lib/platform/provider-contract.ts +6 -21
- package/lib/platform/provider-loader.ts +7 -6
- package/lib/platform/provider-validation.ts +30 -8
- package/lib/platform/pull-requests.ts +4 -2
- package/lib/platform/repository-metadata.ts +3 -2
- package/lib/platform/security-alerts.ts +1 -1
- package/lib/platform/types.ts +2 -0
- package/lib/sandbox/control/client.ts +57 -6
- package/lib/sandbox/control/executor.ts +8 -3
- package/lib/sandbox/removal.ts +2 -10
- package/lib/task/artifact-command.ts +10 -1
- package/lib/task/artifact-lifecycle.ts +100 -52
- package/lib/task/artifact-selection.ts +1 -1
- package/lib/task/capabilities.ts +47 -24
- package/lib/task/commands/status.ts +0 -31
- package/lib/task/commit-identity.ts +24 -7
- package/lib/task/commit-intent.ts +58 -24
- package/lib/task/commit-operation.ts +17 -8
- package/lib/task/completion-facts.ts +31 -9
- package/lib/task/control-authority.ts +1 -4
- package/lib/task/current-contract.ts +1 -6
- package/lib/task/events.ts +8 -247
- package/lib/task/execution-inputs.ts +25 -0
- package/lib/task/finalization-envelope.ts +21 -0
- package/lib/task/finalization.ts +10 -35
- package/lib/task/frontmatter.ts +1 -1
- package/lib/task/ledger-intents.ts +4 -7
- package/lib/task/orchestration.ts +11 -17
- package/lib/task/platform-operation-journal.ts +18 -11
- package/lib/task/platform-operation-recovery.ts +90 -31
- package/lib/task/review-fingerprint.ts +4 -26
- package/lib/task/verification-engine.ts +103 -9
- package/lib/task/write.ts +0 -19
- package/package.json +1 -1
- package/templates/.agents/rules/commit-and-pr.en.md +5 -5
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +5 -5
- package/templates/.agents/rules/decision-qualification.en.md +1 -1
- package/templates/.agents/rules/decision-qualification.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +25 -9
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +26 -9
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +5 -16
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +5 -16
- package/templates/.agents/skills/code-task/reference/report-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +15 -12
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +11 -10
- package/templates/.agents/skills/update-agent-infra/SKILL.en.md +1 -1
- package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +1 -1
- package/templates/.agents/templates/task.zh-CN.md +0 -12
- package/templates/.github/workflows/pr-label.yml +1 -2
- package/dist/lib/internal/task-invalidation.js +0 -63
- package/dist/lib/task/intermediate-cleanup.js +0 -327
- package/dist/lib/task/invalidation-command.js +0 -88
- package/dist/lib/task/invalidation.js +0 -242
- package/lib/internal/task-invalidation.ts +0 -41
- package/lib/task/intermediate-cleanup.ts +0 -393
- package/lib/task/invalidation-command.ts +0 -88
- package/lib/task/invalidation.ts +0 -313
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
const MAX_INTENT_SIZE = 1024 * 1024;
|
|
5
|
+
const TASK_ID_PATTERN = /^TASK-\d{8}-\d{6}$/;
|
|
6
|
+
function intentPath(taskDir) {
|
|
7
|
+
return path.join(taskDir, '.checkpoint-intent.json');
|
|
6
8
|
}
|
|
7
|
-
function
|
|
8
|
-
|
|
9
|
+
function assertTaskDirectory(taskDir, taskId) {
|
|
10
|
+
if (!TASK_ID_PATTERN.test(taskId) || path.basename(path.resolve(taskDir)) !== taskId) {
|
|
11
|
+
throw new Error('COMMIT_INTENT_INVALID: task directory does not match task ID');
|
|
12
|
+
}
|
|
13
|
+
const stat = fs.statSync(taskDir);
|
|
14
|
+
if (!stat.isDirectory())
|
|
15
|
+
throw new Error('COMMIT_INTENT_INVALID: task directory is not a directory');
|
|
9
16
|
}
|
|
10
17
|
function checkpointIntentDigest(identity) {
|
|
11
18
|
return createHash('sha256').update(JSON.stringify({
|
|
@@ -23,8 +30,13 @@ function isIntent(value) {
|
|
|
23
30
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
24
31
|
return false;
|
|
25
32
|
const intent = value;
|
|
33
|
+
const validState = ['prepared', 'committed', 'synced'].includes(String(intent.state));
|
|
34
|
+
const validHead = intent.committedHead === null
|
|
35
|
+
? intent.state === 'prepared'
|
|
36
|
+
: typeof intent.committedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.committedHead)
|
|
37
|
+
&& intent.state !== 'prepared';
|
|
26
38
|
return intent.version === 1
|
|
27
|
-
&& typeof intent.taskId === 'string' && intent.taskId
|
|
39
|
+
&& typeof intent.taskId === 'string' && TASK_ID_PATTERN.test(intent.taskId)
|
|
28
40
|
&& typeof intent.branch === 'string' && intent.branch.length > 0
|
|
29
41
|
&& intent.mode === 'local'
|
|
30
42
|
&& typeof intent.expectedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.expectedHead)
|
|
@@ -33,28 +45,57 @@ function isIntent(value) {
|
|
|
33
45
|
&& typeof intent.message === 'string' && intent.message.length > 0
|
|
34
46
|
&& Number.isSafeInteger(intent.round) && Number(intent.round) > 0
|
|
35
47
|
&& typeof intent.digest === 'string' && /^[a-f0-9]{64}$/.test(intent.digest)
|
|
36
|
-
&&
|
|
37
|
-
&& (intent.committedHead === null || (typeof intent.committedHead === 'string' && /^[a-f0-9]{40,64}$/.test(intent.committedHead)))
|
|
48
|
+
&& validState && validHead
|
|
38
49
|
&& typeof intent.createdAt === 'string' && intent.createdAt.length > 0
|
|
39
50
|
&& typeof intent.updatedAt === 'string' && intent.updatedAt.length > 0
|
|
40
51
|
&& intent.digest === checkpointIntentDigest(intent);
|
|
41
52
|
}
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
function invalidIntent() {
|
|
54
|
+
throw new Error('COMMIT_INTENT_INVALID: checkpoint intent schema is invalid');
|
|
55
|
+
}
|
|
56
|
+
function readCheckpointIntent(taskDir, taskId) {
|
|
57
|
+
assertTaskDirectory(taskDir, taskId);
|
|
58
|
+
const target = intentPath(taskDir);
|
|
59
|
+
let before;
|
|
60
|
+
try {
|
|
61
|
+
before = fs.lstatSync(target);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error.code === 'ENOENT')
|
|
65
|
+
return null;
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
if (!before.isFile() || before.isSymbolicLink() || before.size > MAX_INTENT_SIZE)
|
|
69
|
+
return invalidIntent();
|
|
70
|
+
let descriptor;
|
|
71
|
+
try {
|
|
72
|
+
const noFollow = typeof fs.constants.O_NOFOLLOW === 'number' ? fs.constants.O_NOFOLLOW : 0;
|
|
73
|
+
descriptor = fs.openSync(target, fs.constants.O_RDONLY | noFollow);
|
|
74
|
+
const opened = fs.fstatSync(descriptor);
|
|
75
|
+
if (!opened.isFile() || opened.dev !== before.dev || opened.ino !== before.ino
|
|
76
|
+
|| opened.size !== before.size || opened.size > MAX_INTENT_SIZE)
|
|
77
|
+
return invalidIntent();
|
|
78
|
+
const value = JSON.parse(fs.readFileSync(descriptor, 'utf8'));
|
|
79
|
+
if (!isIntent(value) || value.taskId !== taskId)
|
|
80
|
+
return invalidIntent();
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error instanceof Error && error.message.startsWith('COMMIT_INTENT_INVALID:'))
|
|
85
|
+
throw error;
|
|
86
|
+
return invalidIntent();
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
if (descriptor !== undefined)
|
|
90
|
+
fs.closeSync(descriptor);
|
|
91
|
+
}
|
|
50
92
|
}
|
|
51
|
-
function writeCheckpointIntent(
|
|
93
|
+
function writeCheckpointIntent(taskDir, value) {
|
|
94
|
+
assertTaskDirectory(taskDir, value.taskId);
|
|
52
95
|
if (!isIntent(value))
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
const target = intentPath(repoRoot, value.taskId);
|
|
57
|
-
const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
96
|
+
return invalidIntent();
|
|
97
|
+
const target = intentPath(taskDir);
|
|
98
|
+
const temporary = `${target}.${process.pid}.${randomBytes(8).toString('hex')}.tmp`;
|
|
58
99
|
fs.writeFileSync(temporary, `${JSON.stringify(value)}\n`, { encoding: 'utf8', mode: 0o600, flag: 'wx' });
|
|
59
100
|
try {
|
|
60
101
|
fs.renameSync(temporary, target);
|
|
@@ -75,10 +116,10 @@ function updateCheckpointIntent(value, patch) {
|
|
|
75
116
|
throw new Error('COMMIT_INTENT_INVALID: committed intent requires a committed head');
|
|
76
117
|
return next;
|
|
77
118
|
}
|
|
78
|
-
function removeCheckpointIntent(
|
|
79
|
-
|
|
119
|
+
function removeCheckpointIntent(taskDir, taskId) {
|
|
120
|
+
assertTaskDirectory(taskDir, taskId);
|
|
80
121
|
try {
|
|
81
|
-
fs.unlinkSync(
|
|
122
|
+
fs.unlinkSync(intentPath(taskDir));
|
|
82
123
|
}
|
|
83
124
|
catch (error) {
|
|
84
125
|
if (error.code !== 'ENOENT')
|
|
@@ -96,5 +137,5 @@ function sameCheckpointIntent(left, right) {
|
|
|
96
137
|
&& left.round === right.round
|
|
97
138
|
&& JSON.stringify(left.paths) === JSON.stringify(right.paths);
|
|
98
139
|
}
|
|
99
|
-
export { checkpointIntentDigest, intentPath,
|
|
140
|
+
export { checkpointIntentDigest, intentPath, isIntent, readCheckpointIntent, removeCheckpointIntent, sameCheckpointIntent, updateCheckpointIntent, writeCheckpointIntent };
|
|
100
141
|
//# sourceMappingURL=commit-intent.js.map
|
|
@@ -206,7 +206,7 @@ function executeUnlocked(input, task, mode) {
|
|
|
206
206
|
? (() => {
|
|
207
207
|
const identity = checkpointIdentity(input, task, delivery);
|
|
208
208
|
try {
|
|
209
|
-
pendingIntent = readCheckpointIntent(task.
|
|
209
|
+
pendingIntent = readCheckpointIntent(task.taskDir, task.taskId);
|
|
210
210
|
}
|
|
211
211
|
catch (error) {
|
|
212
212
|
return {
|
|
@@ -215,6 +215,11 @@ function executeUnlocked(input, task, mode) {
|
|
|
215
215
|
};
|
|
216
216
|
}
|
|
217
217
|
if (pendingIntent && !sameCheckpointIntent(pendingIntent, identity)) {
|
|
218
|
+
if (pendingIntent.state !== 'prepared')
|
|
219
|
+
return {
|
|
220
|
+
status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
|
|
221
|
+
error: { code: 'COMMIT_INTENT_INVALID', message: 'A committed checkpoint intent must be recovered with its original request' }
|
|
222
|
+
};
|
|
218
223
|
const timestamp = checkpointTimestamp();
|
|
219
224
|
pendingIntent = {
|
|
220
225
|
version: 1, ...identity,
|
|
@@ -222,7 +227,7 @@ function executeUnlocked(input, task, mode) {
|
|
|
222
227
|
state: 'prepared', committedHead: null, createdAt: timestamp, updatedAt: timestamp
|
|
223
228
|
};
|
|
224
229
|
try {
|
|
225
|
-
writeCheckpointIntent(task.
|
|
230
|
+
writeCheckpointIntent(task.taskDir, pendingIntent);
|
|
226
231
|
}
|
|
227
232
|
catch (error) {
|
|
228
233
|
return {
|
|
@@ -231,6 +236,12 @@ function executeUnlocked(input, task, mode) {
|
|
|
231
236
|
};
|
|
232
237
|
}
|
|
233
238
|
}
|
|
239
|
+
if (pendingIntent && pendingIntent.state !== 'prepared'
|
|
240
|
+
&& !checkpointCommitMatches(task.repoRoot, pendingIntent, pendingIntent.committedHead))
|
|
241
|
+
return {
|
|
242
|
+
status: 'failed', changed: false, snapshot: inspected.snapshot, operations: [],
|
|
243
|
+
error: { code: 'COMMIT_INTENT_INVALID', message: 'Committed checkpoint intent does not match its Git commit' }
|
|
244
|
+
};
|
|
234
245
|
if (!pendingIntent) {
|
|
235
246
|
const timestamp = checkpointTimestamp();
|
|
236
247
|
pendingIntent = {
|
|
@@ -238,7 +249,7 @@ function executeUnlocked(input, task, mode) {
|
|
|
238
249
|
committedHead: null, createdAt: timestamp, updatedAt: timestamp
|
|
239
250
|
};
|
|
240
251
|
try {
|
|
241
|
-
writeCheckpointIntent(task.
|
|
252
|
+
writeCheckpointIntent(task.taskDir, pendingIntent);
|
|
242
253
|
}
|
|
243
254
|
catch (error) {
|
|
244
255
|
return {
|
|
@@ -264,7 +275,7 @@ function executeUnlocked(input, task, mode) {
|
|
|
264
275
|
pendingIntent = updateCheckpointIntent(pendingIntent, {
|
|
265
276
|
state: 'committed', committedHead: checkpointCommittedHead, updatedAt: checkpointTimestamp()
|
|
266
277
|
});
|
|
267
|
-
writeCheckpointIntent(task.
|
|
278
|
+
writeCheckpointIntent(task.taskDir, pendingIntent);
|
|
268
279
|
return {
|
|
269
280
|
status: 'no-op', changed: false, snapshot: inspected.snapshot,
|
|
270
281
|
operations: [{ name: 'commit', status: 'no-op' }], error: null
|
|
@@ -284,10 +295,10 @@ function executeUnlocked(input, task, mode) {
|
|
|
284
295
|
pendingIntent = updateCheckpointIntent(pendingIntent, {
|
|
285
296
|
state: 'committed', committedHead: checkpointCommittedHead, updatedAt: checkpointTimestamp()
|
|
286
297
|
});
|
|
287
|
-
writeCheckpointIntent(task.
|
|
298
|
+
writeCheckpointIntent(task.taskDir, pendingIntent);
|
|
288
299
|
}
|
|
289
300
|
else if (created.status === 'no-op') {
|
|
290
|
-
removeCheckpointIntent(task.
|
|
301
|
+
removeCheckpointIntent(task.taskDir, task.taskId);
|
|
291
302
|
pendingIntent = null;
|
|
292
303
|
}
|
|
293
304
|
return created;
|
|
@@ -377,8 +388,8 @@ function executeUnlocked(input, task, mode) {
|
|
|
377
388
|
const synced = updateCheckpointIntent(pendingIntent, {
|
|
378
389
|
state: 'synced', committedHead: checkpointCommittedHead, updatedAt: checkpointTimestamp()
|
|
379
390
|
});
|
|
380
|
-
writeCheckpointIntent(task.
|
|
381
|
-
removeCheckpointIntent(task.
|
|
391
|
+
writeCheckpointIntent(task.taskDir, synced);
|
|
392
|
+
removeCheckpointIntent(task.taskDir, task.taskId);
|
|
382
393
|
}
|
|
383
394
|
}
|
|
384
395
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { canonicalSemanticDigest } from './artifact-operations.js';
|
|
3
|
-
import { inspectActivityLog } from './activity-log.js';
|
|
3
|
+
import { inspectActivityLog, pairEntries } from './activity-log.js';
|
|
4
4
|
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
5
5
|
import { parseArtifactName } from './artifact-name.js';
|
|
6
6
|
import { sha256File } from './artifact-receipts.js';
|
|
@@ -39,18 +39,40 @@ export function hasArtifactCompletionFact(taskContent, artifactPath, event) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
export function hasArtifactCompletionLog(taskContent, artifact, event) {
|
|
42
|
+
return artifactCompletionOrder(taskContent, artifact, event) !== null;
|
|
43
|
+
}
|
|
44
|
+
/** Returns the stable Activity Log position of a paired completion row. */
|
|
45
|
+
export function artifactCompletionOrder(taskContent, artifact, event) {
|
|
42
46
|
const identity = parseArtifactName(artifact);
|
|
43
47
|
if (!identity)
|
|
44
|
-
return
|
|
45
|
-
const
|
|
46
|
-
: event === 'review-
|
|
47
|
-
: event === '
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
return null;
|
|
49
|
+
const family = event === 'analysis.completed' || event === 'analyze.completed' ? 'analysis'
|
|
50
|
+
: event === 'review-analysis.completed' ? 'review-analysis'
|
|
51
|
+
: event === 'plan.completed' ? 'plan'
|
|
52
|
+
: event === 'review-plan.completed' ? 'review-plan'
|
|
53
|
+
: event === 'code.completed' ? 'code'
|
|
54
|
+
: event === 'review-code.completed' ? 'review-code' : null;
|
|
55
|
+
if (!family || family !== identity.family)
|
|
56
|
+
return null;
|
|
57
|
+
const action = family === 'analysis' ? 'Analyze Task'
|
|
58
|
+
: family === 'review-analysis' ? 'Review Analysis'
|
|
59
|
+
: family === 'plan' ? 'Plan Task'
|
|
60
|
+
: family === 'review-plan' ? 'Review Plan'
|
|
61
|
+
: family === 'code' ? 'Code Task' : 'Review Code';
|
|
50
62
|
const { section, invalidEntries } = inspectActivityLog(taskContent);
|
|
51
63
|
if (!section || invalidEntries.length > 0)
|
|
52
|
-
return
|
|
53
|
-
const
|
|
54
|
-
|
|
64
|
+
return null;
|
|
65
|
+
const ordered = section.entries.map((entry, sourceOrder) => ({ entry, sourceOrder }))
|
|
66
|
+
.sort((left, right) => Date.parse(left.entry.time.replace(' ', 'T')) - Date.parse(right.entry.time.replace(' ', 'T')) || left.sourceOrder - right.sourceOrder);
|
|
67
|
+
const entries = ordered.map(({ entry }) => entry);
|
|
68
|
+
const roundPattern = new RegExp(`^${action} \\(Round ${identity.round}(?:, [^)]+)?\\)$`);
|
|
69
|
+
const row = pairEntries(entries).find((candidate) => candidate.started !== ''
|
|
70
|
+
&& candidate.done !== '' && roundPattern.test(candidate.step)
|
|
71
|
+
&& candidate.note.includes(`→ ${artifact}`));
|
|
72
|
+
if (!row)
|
|
73
|
+
return null;
|
|
74
|
+
const doneIndex = ordered.findIndex(({ entry }) => entry.time === row.done
|
|
75
|
+
&& entry.step === row.step && entry.note === row.note);
|
|
76
|
+
return doneIndex < 0 ? null : doneIndex;
|
|
55
77
|
}
|
|
56
78
|
//# sourceMappingURL=completion-facts.js.map
|
|
@@ -4,7 +4,7 @@ import { normalizeAgentToken } from '../agent-clients/tokens.js';
|
|
|
4
4
|
import { isAgentClientId } from '../agent-clients/types.js';
|
|
5
5
|
import { getAgentClientAdapter } from '../agent-clients/registry.js';
|
|
6
6
|
import { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, awaitOrchestrationDelegationActivation, beginOrResumeOrchestration, dispatchOrchestrationDelegation, OrchestrationStateError, pauseOrchestration, prepareOrchestrationDelegation, recoverPreparedOrchestrationDelegation, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration } from './orchestration.js';
|
|
7
|
-
import { applyTaskFinalization
|
|
7
|
+
import { applyTaskFinalization } from './finalization.js';
|
|
8
8
|
import { applyTaskLifecycle, taskLifecycleFailure } from './lifecycle.js';
|
|
9
9
|
import { resolveTaskRef, TASK_ID_RE } from './resolve-ref.js';
|
|
10
10
|
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
|
|
@@ -434,12 +434,10 @@ export function dispatchTaskControlOperation(context, operation) {
|
|
|
434
434
|
}
|
|
435
435
|
if (operation.family === 'task-finalization') {
|
|
436
436
|
operationTaskId(context, operation.request.taskRef);
|
|
437
|
-
|
|
438
|
-
return finalize(operation.request, {
|
|
437
|
+
return applyTaskFinalization(operation.request, {
|
|
439
438
|
repoRoot: context.repoRoot,
|
|
440
439
|
...(context.source === 'sandbox-executor' ? {
|
|
441
440
|
controlBinding: { generation: context.generation, requestId: context.requestId },
|
|
442
|
-
handoffDirectory: context.handoffDirectory,
|
|
443
441
|
manifestPath: context.manifestPath
|
|
444
442
|
} : {}),
|
|
445
443
|
preflight: (request, options) => verifyTaskEvent({ ...request, event: 'complete-task.hard-preflight' }, options)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { isValidAgentInfraVersion } from '../version.js';
|
|
2
2
|
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
3
3
|
import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, validateLedgerRows } from './ledger.js';
|
|
4
|
-
import { parseInvalidationDocument } from './invalidation.js';
|
|
5
4
|
function validateCurrentTaskContract(content) {
|
|
6
5
|
let metadata;
|
|
7
6
|
try {
|
|
@@ -30,10 +29,7 @@ function validateCurrentTaskContract(content) {
|
|
|
30
29
|
const invalid = validateLedgerRows(ledger.rows);
|
|
31
30
|
if (invalid)
|
|
32
31
|
return { ok: false, code: 'TASK_CURRENT_CONTRACT_INVALID', message: `${invalid.code}: ${invalid.message}` };
|
|
33
|
-
|
|
34
|
-
if (!invalidation.ok)
|
|
35
|
-
return { ok: false, code: 'TASK_CURRENT_CONTRACT_INVALID', message: `${invalidation.code}: ${invalidation.message}` };
|
|
36
|
-
return { ok: true, metadata, ledger, invalidation: invalidation.document };
|
|
32
|
+
return { ok: true, metadata, ledger };
|
|
37
33
|
}
|
|
38
34
|
export { validateCurrentTaskContract };
|
|
39
35
|
//# sourceMappingURL=current-contract.js.map
|