@fitlab-ai/agent-infra 0.11.6 → 0.11.7
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/lib/git/primary-worktree.js +58 -0
- package/dist/lib/platform/pull-requests.js +29 -3
- package/dist/lib/sandbox/control/server.js +6 -2
- package/dist/lib/server/config.js +7 -27
- package/dist/lib/server/daemon.js +4 -3
- package/dist/lib/server/process-control.js +4 -2
- package/dist/lib/server/runner.js +4 -3
- package/dist/lib/task/artifact-lifecycle.js +42 -10
- package/dist/lib/task/artifact-receipts.js +62 -22
- package/dist/lib/task/capabilities.js +22 -4
- package/dist/lib/task/completion-facts.js +56 -0
- package/dist/lib/task/create-service.js +6 -2
- package/dist/lib/task/create.js +46 -82
- package/dist/lib/task/events.js +268 -195
- package/dist/lib/task/finalization-handoff.js +2 -1
- package/dist/lib/task/invalidation-command.js +4 -2
- package/dist/lib/task/invalidation.js +38 -9
- package/dist/lib/task/local-artifact-finalization.js +17 -3
- package/dist/lib/task/qualification-audit.js +23 -105
- package/dist/lib/task/review-finalization.js +7 -0
- package/dist/lib/task/review-identity.js +69 -0
- package/dist/lib/task/sections.js +6 -5
- package/dist/lib/task/task-execution-lock.js +6 -3
- package/dist/lib/task/verification-engine.js +14 -63
- package/dist/lib/task/verification.js +35 -38
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/git/primary-worktree.ts +62 -0
- package/lib/platform/pull-requests.ts +27 -3
- package/lib/sandbox/control/server.ts +5 -2
- package/lib/server/config.ts +7 -29
- package/lib/server/daemon.ts +5 -3
- package/lib/server/process-control.ts +4 -2
- package/lib/server/runner.ts +7 -4
- package/lib/server/server.schema.json +0 -4
- package/lib/task/artifact-lifecycle.ts +35 -11
- package/lib/task/artifact-receipts.ts +55 -15
- package/lib/task/capabilities.ts +17 -3
- package/lib/task/completion-facts.ts +66 -0
- package/lib/task/create-service.ts +7 -3
- package/lib/task/create.ts +44 -71
- package/lib/task/events.ts +248 -182
- package/lib/task/finalization-handoff.ts +2 -1
- package/lib/task/invalidation-command.ts +4 -2
- package/lib/task/invalidation.ts +35 -10
- package/lib/task/local-artifact-finalization.ts +13 -3
- package/lib/task/qualification-audit.ts +21 -114
- package/lib/task/review-finalization.ts +7 -0
- package/lib/task/review-identity.ts +85 -0
- package/lib/task/sections.ts +6 -6
- package/lib/task/task-execution-lock.ts +7 -3
- package/lib/task/verification-engine.ts +13 -86
- package/lib/task/verification.ts +34 -38
- package/package.json +1 -1
- package/templates/.agents/rules/README.en.md +1 -0
- package/templates/.agents/rules/README.zh-CN.md +1 -0
- package/templates/.agents/rules/decision-qualification.en.md +4 -3
- package/templates/.agents/rules/decision-qualification.zh-CN.md +4 -3
- package/templates/.agents/rules/validation-output.en.md +19 -0
- package/templates/.agents/rules/validation-output.zh-CN.md +19 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -1
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/block-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +3 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/reference/report-template.en.md +4 -8
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +4 -8
- package/templates/.agents/skills/commit/SKILL.en.md +1 -1
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/complete-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/create-pr/SKILL.en.md +2 -0
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/create-task/SKILL.en.md +2 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.en.md +2 -0
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +2 -0
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +2 -0
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/plan-task/SKILL.en.md +3 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +4 -8
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +4 -8
- package/templates/.agents/skills/review-code/SKILL.en.md +13 -12
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +11 -12
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -3
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -3
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +23 -46
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +27 -48
- package/templates/.agents/skills/review-code/reference/report-template.en.md +8 -11
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +8 -11
- package/templates/.agents/skills/review-code/reference/review-criteria.en.md +2 -2
- package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +2 -2
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -1
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +5 -9
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +5 -9
- package/templates/.agents/skills/review-pr/SKILL.en.md +2 -0
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +2 -0
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/watch-pr/SKILL.en.md +2 -0
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +1 -1
- package/templates/.agents/templates/task.en.md +2 -2
- package/templates/.agents/templates/task.zh-CN.md +2 -2
|
@@ -48,9 +48,10 @@ export function parseTaskCreateResult(value) {
|
|
|
48
48
|
if (!['applied', 'no-op', 'degraded', 'failed', 'blocked'].includes(result.status)
|
|
49
49
|
|| typeof result.changed !== 'boolean'
|
|
50
50
|
|| !result.task || typeof result.task !== 'object' || Array.isArray(result.task)
|
|
51
|
-
|| !exactKeys(result.task, ['id', 'shortId'])
|
|
51
|
+
|| !exactKeys(result.task, ['id', 'shortId', 'state'])
|
|
52
52
|
|| !validTaskReference(result.task.id)
|
|
53
53
|
|| !validTaskReference(result.task.shortId)
|
|
54
|
+
|| ![null, 'active', 'blocked', 'completed', 'archive'].includes(result.task.state)
|
|
54
55
|
|| !Array.isArray(result.operations)
|
|
55
56
|
|| !result.operations.every((operation) => {
|
|
56
57
|
if (!operation || typeof operation !== 'object' || Array.isArray(operation))
|
|
@@ -93,7 +94,7 @@ export function taskCreateFailure(error, control) {
|
|
|
93
94
|
return {
|
|
94
95
|
status: error.retryable ? 'blocked' : 'failed',
|
|
95
96
|
changed: false,
|
|
96
|
-
task: { id: null, shortId: null },
|
|
97
|
+
task: { id: null, shortId: null, state: null },
|
|
97
98
|
issue: null,
|
|
98
99
|
operations: [],
|
|
99
100
|
warnings: [],
|
|
@@ -156,6 +157,9 @@ async function createTask(value, options) {
|
|
|
156
157
|
const operations = [{
|
|
157
158
|
name: 'task:local', status: local.status, reasonCode: null
|
|
158
159
|
}];
|
|
160
|
+
if (local.status === 'no-op' && local.task.state !== 'active') {
|
|
161
|
+
return { status: 'no-op', changed: false, task: local.task, issue: null, operations, warnings: [], error: null };
|
|
162
|
+
}
|
|
159
163
|
let issue = null;
|
|
160
164
|
const created = await dependencies.createIssue(local.task.id, { cwd: options.repoRoot, agent: candidate.agent });
|
|
161
165
|
operations.push(...platformOperations('platform-create', created.operations));
|
package/dist/lib/task/create.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { isValidAgentInfraVersion, VERSION } from '../version.js';
|
|
5
6
|
import { loadShortIdByTaskId, mutateShortIdRegistry } from './short-id.js';
|
|
@@ -7,6 +8,8 @@ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-
|
|
|
7
8
|
import { readDeliveryDefaults, validateBaseRef, validateRemote } from './delivery-target.js';
|
|
8
9
|
import { buildUnboundFact, encodePrDeliveryFact } from './pr-delivery-fact.js';
|
|
9
10
|
import { CANDIDATE_COLUMNS, CONSTRAINT_COLUMNS, parseTaskQualification } from './qualification-audit.js';
|
|
11
|
+
import { enumerateAllTaskDirs } from './resolve-ref.js';
|
|
12
|
+
import { parseTaskFrontmatter } from './frontmatter.js';
|
|
10
13
|
const AGENTS = ['claude', 'codex', 'antigravity', 'opencode', 'cursor'];
|
|
11
14
|
const TYPES = ['feature', 'bugfix', 'refactor', 'docs', 'chore'];
|
|
12
15
|
const PRIORITIES = ['Urgent', 'High', 'Medium', 'Low'];
|
|
@@ -292,10 +295,27 @@ function ensureRealDirectory(directory, code) {
|
|
|
292
295
|
}
|
|
293
296
|
fs.mkdirSync(directory, { mode: 0o700 });
|
|
294
297
|
}
|
|
295
|
-
function
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
function createLockRoot(project) {
|
|
299
|
+
const root = path.join(os.homedir(), '.agent-infra');
|
|
300
|
+
const directories = [root, path.join(root, 'run'), path.join(root, 'run', project), path.join(root, 'run', project, 'task-create-locks')];
|
|
301
|
+
for (const directory of directories) {
|
|
302
|
+
if (fs.existsSync(directory)) {
|
|
303
|
+
assertRealDirectory(directory, 'TASK_CREATE_LOCK_FAILED');
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
fs.mkdirSync(directory, { mode: 0o700 });
|
|
308
|
+
}
|
|
309
|
+
catch (error) {
|
|
310
|
+
if (error.code !== 'EEXIST')
|
|
311
|
+
throw error;
|
|
312
|
+
assertRealDirectory(directory, 'TASK_CREATE_LOCK_FAILED');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return directories.at(-1);
|
|
316
|
+
}
|
|
317
|
+
function withCreateLock(repoRoot, project, operation) {
|
|
318
|
+
const lockRoot = createLockRoot(project);
|
|
299
319
|
let callbackError;
|
|
300
320
|
try {
|
|
301
321
|
return withTaskExecutionLock(repoRoot, 'task-create', 'task-create', () => {
|
|
@@ -306,7 +326,7 @@ function withCreateLock(repoRoot, workspaceRoot, operation) {
|
|
|
306
326
|
callbackError = error;
|
|
307
327
|
throw error;
|
|
308
328
|
}
|
|
309
|
-
}, { lockRoot });
|
|
329
|
+
}, { lockRoot, identityScope: `task-create\0${project}` });
|
|
310
330
|
}
|
|
311
331
|
catch (error) {
|
|
312
332
|
if (callbackError !== undefined)
|
|
@@ -318,45 +338,24 @@ function withCreateLock(repoRoot, workspaceRoot, operation) {
|
|
|
318
338
|
throw new Error(`TASK_CREATE_LOCK_FAILED: ${message}`);
|
|
319
339
|
}
|
|
320
340
|
}
|
|
321
|
-
function
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
fs.renameSync(temporary, receiptPath);
|
|
326
|
-
}
|
|
327
|
-
catch (error) {
|
|
328
|
-
try {
|
|
329
|
-
fs.unlinkSync(temporary);
|
|
330
|
-
}
|
|
331
|
-
catch { /* best effort */ }
|
|
332
|
-
throw error;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
function recoverPublishedTask(activeRoot, repoRoot, keyDigest, candidateDigest) {
|
|
336
|
-
for (const name of fs.readdirSync(activeRoot)) {
|
|
337
|
-
if (!/^TASK-\d{8}-\d{6}$/.test(name))
|
|
338
|
-
continue;
|
|
339
|
-
const taskDir = path.join(activeRoot, name);
|
|
340
|
-
const stat = fs.lstatSync(taskDir);
|
|
341
|
-
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
342
|
-
continue;
|
|
343
|
-
const taskMd = path.join(taskDir, 'task.md');
|
|
344
|
-
if (!fs.existsSync(taskMd))
|
|
345
|
-
continue;
|
|
341
|
+
function recoverPublishedTask(repoRoot, keyDigest, candidateDigest) {
|
|
342
|
+
for (const task of enumerateAllTaskDirs(repoRoot)) {
|
|
343
|
+
const taskMd = path.join(task.taskDir, 'task.md');
|
|
346
344
|
const taskStat = fs.lstatSync(taskMd);
|
|
347
345
|
if (!taskStat.isFile() || taskStat.isSymbolicLink())
|
|
346
|
+
throw new Error('TASK_CREATE_TASK_INVALID');
|
|
347
|
+
const frontmatter = parseTaskFrontmatter(fs.readFileSync(taskMd, 'utf8'));
|
|
348
|
+
if (frontmatter.task_create_key_digest !== keyDigest)
|
|
348
349
|
continue;
|
|
349
|
-
|
|
350
|
-
if (!content.includes(`task_create_key_digest: ${keyDigest}`))
|
|
351
|
-
continue;
|
|
352
|
-
if (!content.includes(`task_create_candidate_digest: ${candidateDigest}`)) {
|
|
350
|
+
if (frontmatter.task_create_candidate_digest !== candidateDigest) {
|
|
353
351
|
throw new Error('TASK_CREATE_IDEMPOTENCY_CONFLICT');
|
|
354
352
|
}
|
|
355
|
-
const shortId =
|
|
356
|
-
?? mutateShortIdRegistry(repoRoot,
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
353
|
+
const shortId = task.state === 'active'
|
|
354
|
+
? loadShortIdByTaskId(repoRoot).get(task.taskId) ?? mutateShortIdRegistry(repoRoot, task.taskId, 'alloc').shortId
|
|
355
|
+
: null;
|
|
356
|
+
if (task.state === 'active' && !shortId)
|
|
357
|
+
throw new Error('TASK_CREATE_SHORT_ID_FAILED');
|
|
358
|
+
return { taskId: task.taskId, shortId, state: task.state };
|
|
360
359
|
}
|
|
361
360
|
return null;
|
|
362
361
|
}
|
|
@@ -376,30 +375,10 @@ function createLocalTask(value, options) {
|
|
|
376
375
|
const canonical = canonicalTaskCreateCandidate(candidate);
|
|
377
376
|
const candidateDigest = sha256(canonical);
|
|
378
377
|
const keyDigest = sha256(candidate.idempotencyKey);
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if (fs.existsSync(receipts))
|
|
382
|
-
assertRealDirectory(receipts, 'TASK_CREATE_RECEIPT_INVALID');
|
|
383
|
-
const receiptPath = path.join(receipts, `${keyDigest}.json`);
|
|
384
|
-
if (fs.existsSync(receiptPath)) {
|
|
385
|
-
const stat = fs.lstatSync(receiptPath);
|
|
386
|
-
if (!stat.isFile() || stat.isSymbolicLink())
|
|
387
|
-
throw new Error('TASK_CREATE_RECEIPT_INVALID');
|
|
388
|
-
const receipt = JSON.parse(fs.readFileSync(receiptPath, 'utf8'));
|
|
389
|
-
if (receipt.candidateDigest !== candidateDigest)
|
|
390
|
-
throw new Error('TASK_CREATE_IDEMPOTENCY_CONFLICT');
|
|
391
|
-
if (!receipt.taskId || !receipt.shortId || !fs.existsSync(path.join(activeRoot, receipt.taskId, 'task.md'))) {
|
|
392
|
-
throw new Error('TASK_CREATE_RECEIPT_INVALID');
|
|
393
|
-
}
|
|
394
|
-
return { status: 'no-op', changed: false, task: { id: receipt.taskId, shortId: receipt.shortId } };
|
|
395
|
-
}
|
|
396
|
-
const recovered = recoverPublishedTask(activeRoot, repoRoot, keyDigest, candidateDigest);
|
|
378
|
+
return withCreateLock(repoRoot, projectConfig.project, () => {
|
|
379
|
+
const recovered = recoverPublishedTask(repoRoot, keyDigest, candidateDigest);
|
|
397
380
|
if (recovered) {
|
|
398
|
-
|
|
399
|
-
writeReceipt(receiptPath, {
|
|
400
|
-
version: 1, candidateDigest, taskId: recovered.taskId, shortId: recovered.shortId, status: 'recovered'
|
|
401
|
-
});
|
|
402
|
-
return { status: 'no-op', changed: false, task: { id: recovered.taskId, shortId: recovered.shortId } };
|
|
381
|
+
return { status: 'no-op', changed: false, task: { id: recovered.taskId, shortId: recovered.shortId, state: recovered.state } };
|
|
403
382
|
}
|
|
404
383
|
const base = options.now?.() ?? new Date();
|
|
405
384
|
let taskDate = new Date(base.getTime());
|
|
@@ -418,32 +397,17 @@ function createLocalTask(value, options) {
|
|
|
418
397
|
agentInfraVersion, keyDigest, candidateDigest
|
|
419
398
|
});
|
|
420
399
|
validateRenderedQualification(rendered, candidate);
|
|
421
|
-
ensureRealDirectory(receipts, 'TASK_CREATE_RECEIPT_INVALID');
|
|
422
400
|
const temporary = path.join(workspaceRoot, `.task-create.tmp.${process.pid}.${randomUUID()}`);
|
|
423
401
|
fs.mkdirSync(temporary, { mode: 0o700 });
|
|
424
402
|
fs.writeFileSync(path.join(temporary, 'task.md'), rendered, { flag: 'wx', mode: 0o600 });
|
|
425
403
|
const destination = path.join(activeRoot, taskId);
|
|
426
404
|
fs.renameSync(temporary, destination);
|
|
427
405
|
let shortId;
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
catch (error) {
|
|
435
|
-
fs.rmSync(destination, { recursive: true, force: true });
|
|
436
|
-
throw error;
|
|
437
|
-
}
|
|
438
|
-
try {
|
|
439
|
-
writeReceipt(receiptPath, { version: 1, candidateDigest, taskId, shortId, status: 'created' });
|
|
440
|
-
}
|
|
441
|
-
catch (error) {
|
|
442
|
-
mutateShortIdRegistry(repoRoot, taskId, 'release');
|
|
443
|
-
fs.rmSync(destination, { recursive: true, force: true });
|
|
444
|
-
throw error;
|
|
445
|
-
}
|
|
446
|
-
return { status: 'applied', changed: true, task: { id: taskId, shortId } };
|
|
406
|
+
const allocated = mutateShortIdRegistry(repoRoot, taskId, 'alloc');
|
|
407
|
+
if (!allocated.shortId)
|
|
408
|
+
throw new Error('TASK_CREATE_SHORT_ID_FAILED');
|
|
409
|
+
shortId = allocated.shortId;
|
|
410
|
+
return { status: 'applied', changed: true, task: { id: taskId, shortId, state: 'active' } };
|
|
447
411
|
});
|
|
448
412
|
}
|
|
449
413
|
export { canonicalTaskCreateCandidate, createLocalTask, validateTaskCreateCandidate };
|