@fitlab-ai/agent-infra 0.11.15 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.ts +1 -1
- package/dist/bin/cli.js +1 -1
- package/dist/bin/internal-cli.js +6 -1
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +6 -6
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +8 -18
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +1 -1
- package/dist/lib/decide.js +2 -7
- package/dist/lib/internal/cli-route-inventory.js +3 -0
- package/dist/lib/internal/manual-validation.js +19 -33
- package/dist/lib/internal/platform-comment.js +59 -9
- package/dist/lib/internal/task-activity.js +1 -12
- package/dist/lib/internal/task-event.js +1 -12
- package/dist/lib/internal/task-ledger.js +1 -12
- package/dist/lib/internal/task-operation-registry.js +2 -1
- package/dist/lib/internal/task-qualification.js +6 -15
- package/dist/lib/internal/task-review.js +3 -16
- package/dist/lib/internal/task-short-id.js +2 -1
- package/dist/lib/internal/task-verify.js +1 -11
- package/dist/lib/internal/task-warning.js +1 -12
- package/dist/lib/internal/task-workspace.js +43 -0
- package/dist/lib/merge.js +4 -3
- package/dist/lib/platform/issue-comments.js +373 -267
- package/dist/lib/platform/issue-summary-content.js +112 -0
- package/dist/lib/platform/pr-change-report.js +175 -26
- package/dist/lib/platform/pr-summary-content.js +54 -0
- package/dist/lib/platform/pr-summary.js +321 -296
- package/dist/lib/platform/pull-requests.js +3 -15
- package/dist/lib/platform/summary-content-pipeline.js +18 -0
- package/dist/lib/pr-review/evidence-grading.js +3 -2
- package/dist/lib/process-data/index.js +5 -4
- package/dist/lib/process-data/sources.js +6 -0
- package/dist/lib/run/index.js +3 -2
- package/dist/lib/sandbox/commands/create.js +5 -1
- package/dist/lib/sandbox/commands/enter.js +1 -1
- package/dist/lib/sandbox/commands/list-running.js +2 -1
- package/dist/lib/sandbox/control/client.js +8 -13
- package/dist/lib/sandbox/control/completed-reentry.js +2 -1
- package/dist/lib/sandbox/control/task-view.js +4 -2
- package/dist/lib/sandbox/mounts.js +4 -4
- package/dist/lib/sandbox/recovery.js +26 -16
- package/dist/lib/sandbox/removal.js +62 -12
- package/dist/lib/sandbox/task-resolver.js +9 -6
- package/dist/lib/sandbox/workspace-identity.js +6 -5
- package/dist/lib/sandbox/workspace-view.js +29 -22
- package/dist/lib/task/activity-intent.js +2 -12
- package/dist/lib/task/artifact-lifecycle.js +17 -11
- package/dist/lib/task/artifact-operations.js +41 -49
- package/dist/lib/task/capabilities.js +2 -2
- package/dist/lib/task/commands/ls.js +4 -3
- package/dist/lib/task/commands/status.js +1 -1
- package/dist/lib/task/commit-operation.js +6 -6
- package/dist/lib/task/control-authority.js +32 -32
- package/dist/lib/task/create-service.js +2 -4
- package/dist/lib/task/create.js +12 -65
- package/dist/lib/task/delegation-receipts.js +1 -1
- package/dist/lib/task/delivery.js +2 -8
- package/dist/lib/task/events.js +5 -31
- package/dist/lib/task/finalization.js +33 -29
- package/dist/lib/task/lifecycle.js +9 -48
- package/dist/lib/task/local-artifact-finalization.js +1 -2
- package/dist/lib/task/orchestration.js +24 -57
- package/dist/lib/task/platform-operation-recovery.js +87 -88
- package/dist/lib/task/resolve-ref.js +17 -12
- package/dist/lib/task/review-finalization.js +2 -35
- package/dist/lib/task/review-identity.js +3 -1
- package/dist/lib/task/short-id.js +10 -8
- package/dist/lib/task/verification-engine.js +19 -58
- package/dist/lib/task/workspace-root.js +59 -0
- package/dist/lib/task/workspace-snapshot.js +4 -3
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +6 -6
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +8 -34
- package/lib/agent-clients/adapters/codex-orchestration.ts +1 -1
- package/lib/decide.ts +2 -7
- package/lib/internal/cli-route-inventory.ts +2 -0
- package/lib/internal/manual-validation.ts +20 -37
- package/lib/internal/platform-comment.ts +49 -6
- package/lib/internal/task-activity.ts +1 -10
- package/lib/internal/task-event.ts +1 -10
- package/lib/internal/task-ledger.ts +1 -10
- package/lib/internal/task-operation-registry.ts +2 -1
- package/lib/internal/task-qualification.ts +5 -11
- package/lib/internal/task-review.ts +3 -14
- package/lib/internal/task-short-id.ts +2 -1
- package/lib/internal/task-verify.ts +1 -9
- package/lib/internal/task-warning.ts +1 -10
- package/lib/internal/task-workspace.ts +39 -0
- package/lib/merge.ts +4 -3
- package/lib/platform/issue-comments.ts +478 -280
- package/lib/platform/issue-summary-content.ts +132 -0
- package/lib/platform/pr-change-report.ts +165 -20
- package/lib/platform/pr-summary-content.ts +60 -0
- package/lib/platform/pr-summary.ts +367 -269
- package/lib/platform/pull-requests.ts +3 -24
- package/lib/platform/summary-content-pipeline.ts +23 -0
- package/lib/pr-review/evidence-grading.ts +3 -2
- package/lib/process-data/index.ts +4 -3
- package/lib/process-data/sources.ts +6 -0
- package/lib/run/index.ts +3 -2
- package/lib/sandbox/commands/create.ts +5 -1
- package/lib/sandbox/commands/enter.ts +1 -1
- package/lib/sandbox/commands/list-running.ts +2 -1
- package/lib/sandbox/control/client.ts +7 -12
- package/lib/sandbox/control/completed-reentry.ts +2 -1
- package/lib/sandbox/control/task-view.ts +4 -2
- package/lib/sandbox/mounts.ts +4 -4
- package/lib/sandbox/recovery.ts +26 -18
- package/lib/sandbox/removal.ts +60 -27
- package/lib/sandbox/task-resolver.ts +9 -6
- package/lib/sandbox/workspace-identity.ts +6 -5
- package/lib/sandbox/workspace-view.ts +28 -20
- package/lib/task/activity-intent.ts +3 -17
- package/lib/task/artifact-lifecycle.ts +39 -11
- package/lib/task/artifact-operations.ts +28 -35
- package/lib/task/capabilities.ts +2 -2
- package/lib/task/commands/ls.ts +4 -3
- package/lib/task/commands/status.ts +1 -1
- package/lib/task/commit-operation.ts +5 -6
- package/lib/task/control-authority.ts +29 -35
- package/lib/task/create-service.ts +2 -4
- package/lib/task/create.ts +10 -51
- package/lib/task/delegation-receipts.ts +1 -1
- package/lib/task/delivery.ts +2 -10
- package/lib/task/events.ts +5 -32
- package/lib/task/finalization.ts +27 -30
- package/lib/task/lifecycle.ts +9 -50
- package/lib/task/local-artifact-finalization.ts +1 -4
- package/lib/task/orchestration.ts +31 -80
- package/lib/task/platform-operation-recovery.ts +70 -82
- package/lib/task/resolve-ref.ts +18 -12
- package/lib/task/review-finalization.ts +2 -52
- package/lib/task/review-identity.ts +3 -1
- package/lib/task/short-id.ts +10 -8
- package/lib/task/verification-engine.ts +20 -62
- package/lib/task/workspace-root.ts +78 -0
- package/lib/task/workspace-snapshot.ts +4 -3
- package/package.json +1 -1
- package/templates/.agents/QUICKSTART.en.md +19 -8
- package/templates/.agents/QUICKSTART.zh-CN.md +19 -8
- package/templates/.agents/README.en.md +10 -15
- package/templates/.agents/README.zh-CN.md +9 -13
- package/templates/.agents/rules/issue-sync.en.md +1 -1
- package/templates/.agents/rules/issue-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.en.md +1 -1
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +1 -1
- package/templates/.agents/rules/next-step-output.en.md +2 -2
- package/templates/.agents/rules/next-step-output.zh-CN.md +2 -2
- package/templates/.agents/rules/pr-sync.en.md +5 -3
- package/templates/.agents/rules/pr-sync.zh-CN.md +7 -10
- package/templates/.agents/rules/release-commands.en.md +3 -0
- package/templates/.agents/rules/release-commands.zh-CN.md +3 -0
- package/templates/.agents/rules/task-management.en.md +0 -2
- package/templates/.agents/rules/task-management.zh-CN.md +0 -2
- package/templates/.agents/rules/task-short-id.en.md +2 -2
- package/templates/.agents/rules/task-short-id.zh-CN.md +2 -2
- package/templates/.agents/scripts/task-short-id.js +2 -8
- package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
- package/templates/.agents/skills/analyze-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/archive-tasks/SKILL.en.md +5 -5
- package/templates/.agents/skills/archive-tasks/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/archive-tasks/scripts/archive-tasks.sh +10 -2
- package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
- package/templates/.agents/skills/block-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/block-task/config/verify.json +0 -1
- package/templates/.agents/skills/cancel-task/SKILL.en.md +7 -7
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +7 -7
- package/templates/.agents/skills/cancel-task/config/verify.json +0 -1
- package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/code-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/code-task/reference/output-template.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +1 -1
- 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/commit/config/verify.json +0 -1
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +2 -2
- package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +0 -1
- package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +3 -3
- package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +3 -3
- package/templates/.agents/skills/complete-task/SKILL.en.md +15 -30
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +17 -32
- package/templates/.agents/skills/complete-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/create-pr/SKILL.en.md +3 -3
- package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/create-pr/config/verify.json +0 -1
- package/templates/.agents/skills/create-pr/reference/change-report.en.md +10 -3
- package/templates/.agents/skills/create-pr/reference/change-report.zh-CN.md +10 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +3 -3
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +3 -3
- package/templates/.agents/skills/create-release-note/SKILL.en.md +2 -2
- package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/create-task/SKILL.en.md +4 -22
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +4 -22
- package/templates/.agents/skills/create-task/config/verify.json +0 -1
- package/templates/.agents/skills/import-codescan/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/import-codescan/config/verify.json +0 -1
- package/templates/.agents/skills/import-dependabot/SKILL.en.md +3 -3
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/import-dependabot/config/verify.json +0 -1
- package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
- package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/import-issue/config/verify.json +0 -1
- package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/plan-task/config/verify.en.json +0 -1
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/restore-task/config/verify.json +0 -1
- package/templates/.agents/skills/review-analysis/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/config/verify.en.json +0 -1
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +5 -5
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +4 -4
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +4 -4
- package/templates/.agents/skills/review-plan/SKILL.en.md +1 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-plan/config/verify.en.json +0 -1
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +5 -5
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +5 -5
- package/templates/.agents/skills/review-pr/SKILL.en.md +2 -2
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-pr/config/verify.en.json +0 -1
- package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +0 -1
- package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +1 -1
- package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +1 -1
- package/templates/.agents/skills/run-manual-validation/config/verify.en.json +0 -1
- package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +0 -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/test/SKILL.en.md +0 -3
- package/templates/.agents/skills/test/SKILL.zh-CN.md +0 -3
- package/templates/.agents/skills/test-integration/SKILL.en.md +0 -3
- package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +0 -3
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +13 -6
- package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +0 -3
- package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +0 -3
- package/templates/.agents/skills/watch-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/watch-pr/config/verify.json +0 -1
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +3 -3
- package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +3 -3
- package/templates/.agents/templates/handoff.en.md +1 -1
- package/templates/.agents/templates/handoff.zh-CN.md +1 -1
- package/templates/.agents/workflows/bug-fix.en.yaml +1 -1
- package/templates/.agents/workflows/feature-development.en.yaml +1 -1
- package/templates/.agents/workflows/refactoring.en.yaml +1 -1
- package/dist/lib/task/task-execution-lock.js +0 -250
- package/lib/task/task-execution-lock.ts +0 -320
|
@@ -8,7 +8,6 @@ import { finalizeReviewSummaryContent } from './review-artifacts.js';
|
|
|
8
8
|
import { inspectDecisionDetailDuplicates } from './decision-details.js';
|
|
9
9
|
import { resolveTaskRef } from './resolve-ref.js';
|
|
10
10
|
import { validateLifecycleExecution } from './lifecycle-execution.js';
|
|
11
|
-
import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
|
|
12
11
|
import { getArtifactSchema } from './artifact-schema.js';
|
|
13
12
|
import { validateQualificationAudit } from './qualification-audit.js';
|
|
14
13
|
import { canonicalSemanticDigest, inspectArtifactContract, sha256Content } from './artifact-operations.js';
|
|
@@ -47,7 +46,7 @@ function preflightFailed(request, code, message, taskId = null, extra = {}) {
|
|
|
47
46
|
};
|
|
48
47
|
}
|
|
49
48
|
/** Validate the current review draft before any finding-ledger write. */
|
|
50
|
-
function
|
|
49
|
+
function preflightReviewSummary(request, options = {}) {
|
|
51
50
|
const stage = request.stage;
|
|
52
51
|
const spec = STAGES[stage];
|
|
53
52
|
if (!spec)
|
|
@@ -106,21 +105,6 @@ function preflightReviewSummaryUnlocked(request, options = {}) {
|
|
|
106
105
|
status: 'passed', changed: false, error: null
|
|
107
106
|
};
|
|
108
107
|
}
|
|
109
|
-
function preflightReviewSummary(request, options = {}) {
|
|
110
|
-
if (request.dryRun || options.lockAlreadyHeld)
|
|
111
|
-
return preflightReviewSummaryUnlocked(request, options);
|
|
112
|
-
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
113
|
-
if (!resolved.ok)
|
|
114
|
-
return preflightReviewSummaryUnlocked(request, options);
|
|
115
|
-
try {
|
|
116
|
-
return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.preflight', () => preflightReviewSummaryUnlocked(request, { ...options, lockAlreadyHeld: true }));
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
if (!(error instanceof TaskExecutionLockError))
|
|
120
|
-
throw error;
|
|
121
|
-
return preflightFailed(request, 'REVIEW_PROVENANCE_INVALID', `${error.code}: ${error.message}`, resolved.taskId);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
108
|
/** Prepare domain validation, summary bytes and provenance before any publication. */
|
|
125
109
|
function prepareReviewSummaryCandidate(request, artifactContent, options = {}) {
|
|
126
110
|
let taskId = null;
|
|
@@ -208,7 +192,6 @@ function prepareReviewSummaryCandidate(request, artifactContent, options = {}) {
|
|
|
208
192
|
operations: transformed.changed ? [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }] : [],
|
|
209
193
|
error: null
|
|
210
194
|
},
|
|
211
|
-
lockAlreadyHeld: options.lockAlreadyHeld
|
|
212
195
|
};
|
|
213
196
|
}
|
|
214
197
|
function commitReviewSummaryProvenance(prepared, repoRoot, options = {}) {
|
|
@@ -230,7 +213,7 @@ function replaceCurrentArtifactAtomically(file, content) {
|
|
|
230
213
|
}
|
|
231
214
|
}
|
|
232
215
|
}
|
|
233
|
-
function
|
|
216
|
+
function finalizeReviewSummary(request, options = {}) {
|
|
234
217
|
const spec = STAGES[request.stage];
|
|
235
218
|
if (!spec || !request.taskRef || !request.artifact)
|
|
236
219
|
return prepareReviewSummaryCandidate(request, '', options).result;
|
|
@@ -267,21 +250,5 @@ function finalizeReviewSummaryUnlocked(request, options = {}) {
|
|
|
267
250
|
return failed(request, 'REVIEW_RECOVERY_COMMIT_FAILED', `cannot update current review artifact: ${error instanceof Error ? error.message : String(error)}`, resolved.taskId);
|
|
268
251
|
}
|
|
269
252
|
}
|
|
270
|
-
function finalizeReviewSummary(request, options = {}) {
|
|
271
|
-
const effectiveOptions = options;
|
|
272
|
-
if (request.dryRun || options.lockAlreadyHeld)
|
|
273
|
-
return finalizeReviewSummaryUnlocked(request, effectiveOptions);
|
|
274
|
-
const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
|
|
275
|
-
if (!resolved.ok)
|
|
276
|
-
return finalizeReviewSummaryUnlocked(request, effectiveOptions);
|
|
277
|
-
try {
|
|
278
|
-
return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.finalize-summary', () => finalizeReviewSummaryUnlocked(request, { ...effectiveOptions, lockAlreadyHeld: true }));
|
|
279
|
-
}
|
|
280
|
-
catch (error) {
|
|
281
|
-
if (!(error instanceof TaskExecutionLockError))
|
|
282
|
-
throw error;
|
|
283
|
-
return failed(request, 'REVIEW_PROVENANCE_INVALID', `${error.code}: ${error.message}`, resolved.taskId);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
253
|
export { finalizeReviewSummary, preflightReviewSummary, prepareReviewSummaryCandidate, commitReviewSummaryProvenance };
|
|
287
254
|
//# sourceMappingURL=review-finalization.js.map
|
|
@@ -23,7 +23,9 @@ export function inspectReviewIdentity(taskDir, reportContent, repositoryRoot) {
|
|
|
23
23
|
}
|
|
24
24
|
try {
|
|
25
25
|
const metadata = parseTypedTaskFrontmatter(fs.readFileSync(path.join(taskDir, 'task.md'), 'utf8'));
|
|
26
|
-
const taskRepositoryRoot =
|
|
26
|
+
const taskRepositoryRoot = repositoryRoot
|
|
27
|
+
? fs.realpathSync.native(repositoryRoot)
|
|
28
|
+
: git(taskDir, ['rev-parse', '--show-toplevel']);
|
|
27
29
|
const branch = String(metadata.branch ?? '').trim();
|
|
28
30
|
const gitRoot = branch ? resolveBranchWorktree(taskRepositoryRoot, branch) : taskRepositoryRoot;
|
|
29
31
|
if (!gitRoot)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { parseTypedTaskFrontmatter } from './frontmatter.js';
|
|
4
|
+
import { resolveProjectTaskWorkspaceRoot } from './workspace-root.js';
|
|
4
5
|
const REGISTRY_NAME = '.short-ids.json';
|
|
5
6
|
const LOCK_NAME = '.short-ids.json.lock';
|
|
6
7
|
function normalizeShortIdInput(input, opts) {
|
|
@@ -42,7 +43,7 @@ function resolveShortIdReadOnly(input, repoRoot, opts) {
|
|
|
42
43
|
return shortIdFailure('SHORT_ID_NOT_FOUND', `short id '${input}' not found in active task registry`);
|
|
43
44
|
}
|
|
44
45
|
const key = normalized.value;
|
|
45
|
-
const registryPath = path.join(repoRoot, '
|
|
46
|
+
const registryPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', REGISTRY_NAME);
|
|
46
47
|
if (!fs.existsSync(registryPath)) {
|
|
47
48
|
return shortIdFailure('SHORT_ID_REGISTRY_NOT_FOUND', `short id '${key}' not found; active task registry is empty.`);
|
|
48
49
|
}
|
|
@@ -95,8 +96,9 @@ function resolveShortIdReadOnly(input, repoRoot, opts) {
|
|
|
95
96
|
: `short id '${key}' not found in task short-id registry.`;
|
|
96
97
|
return shortIdFailure('SHORT_ID_NOT_FOUND', message);
|
|
97
98
|
}
|
|
98
|
-
const
|
|
99
|
-
const
|
|
99
|
+
const workspaceRoot = resolveProjectTaskWorkspaceRoot(repoRoot);
|
|
100
|
+
const activeTask = path.join(workspaceRoot, 'active', taskId, 'task.md');
|
|
101
|
+
const completedTask = path.join(workspaceRoot, 'completed', taskId, 'task.md');
|
|
100
102
|
let isValidCompletedTask = false;
|
|
101
103
|
try {
|
|
102
104
|
const task = parseTypedTaskFrontmatter(fs.readFileSync(completedTask, 'utf8'));
|
|
@@ -210,7 +212,7 @@ function writeRegistry(registryPath, registry) {
|
|
|
210
212
|
}
|
|
211
213
|
}
|
|
212
214
|
function mutateShortIdRegistry(repoRoot, taskId, requested) {
|
|
213
|
-
const activeDir = path.join(repoRoot, '
|
|
215
|
+
const activeDir = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active');
|
|
214
216
|
return mutateShortIdRegistryAt(activeDir, configuredShortIdLength(repoRoot), taskId, requested);
|
|
215
217
|
}
|
|
216
218
|
function mutateShortIdRegistryAt(activeDir, width, taskId, requested, onlyReleaseWhenInactive = false, pruneOrphans = true) {
|
|
@@ -267,7 +269,7 @@ function mutateShortIdRegistryAt(activeDir, width, taskId, requested, onlyReleas
|
|
|
267
269
|
});
|
|
268
270
|
}
|
|
269
271
|
function releaseStaleShortIdRegistry(repoRoot, taskId) {
|
|
270
|
-
const activeDir = path.join(repoRoot, '
|
|
272
|
+
const activeDir = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active');
|
|
271
273
|
return mutateShortIdRegistryAt(activeDir, configuredShortIdLength(repoRoot), taskId, 'release', true, false);
|
|
272
274
|
}
|
|
273
275
|
function executeShortIdCommand(request) {
|
|
@@ -327,7 +329,7 @@ function executeShortIdCommand(request) {
|
|
|
327
329
|
}
|
|
328
330
|
}
|
|
329
331
|
function readRegistry(repoRoot) {
|
|
330
|
-
const registryPath = path.join(repoRoot, '
|
|
332
|
+
const registryPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', REGISTRY_NAME);
|
|
331
333
|
if (!fs.existsSync(registryPath))
|
|
332
334
|
return null;
|
|
333
335
|
try {
|
|
@@ -342,7 +344,7 @@ function readRegistry(repoRoot) {
|
|
|
342
344
|
}
|
|
343
345
|
}
|
|
344
346
|
function readBranchFromTaskMd(repoRoot, taskId) {
|
|
345
|
-
const taskMdPath = path.join(repoRoot, '
|
|
347
|
+
const taskMdPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', taskId, 'task.md');
|
|
346
348
|
if (!fs.existsSync(taskMdPath))
|
|
347
349
|
return null;
|
|
348
350
|
const content = fs.readFileSync(taskMdPath, 'utf8');
|
|
@@ -362,7 +364,7 @@ function loadShortIdByTaskId(repoRoot) {
|
|
|
362
364
|
return map;
|
|
363
365
|
}
|
|
364
366
|
function inspectShortIdRegistry(repoRoot, shortIdLength = configuredShortIdLength(repoRoot)) {
|
|
365
|
-
const registryPath = path.join(repoRoot, '
|
|
367
|
+
const registryPath = path.join(resolveProjectTaskWorkspaceRoot(repoRoot), 'active', REGISTRY_NAME);
|
|
366
368
|
if (!fs.existsSync(registryPath)) {
|
|
367
369
|
return {
|
|
368
370
|
status: 'missing',
|
|
@@ -54,9 +54,7 @@ const DEFAULT_REQUIRED_FIELDS = [
|
|
|
54
54
|
"assigned_to"
|
|
55
55
|
];
|
|
56
56
|
const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
|
|
57
|
-
//
|
|
58
|
-
// "latest action" / freshness computation so a step's in-flight marker never
|
|
59
|
-
// satisfies a skill's expected_action_pattern; the matching done entry does.
|
|
57
|
+
// Started rows do not represent completed lifecycle actions.
|
|
60
58
|
const ACTIVITY_LOG_STARTED_RE = /\s*\[started\]\s*$/;
|
|
61
59
|
const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
62
60
|
// Review disagreement ledger (see .agents/rules/review-handshake.md).
|
|
@@ -322,15 +320,9 @@ function checkTaskMeta({ taskDir, config, repositoryRoot, skillName, artifactFil
|
|
|
322
320
|
if (expectedStep && metadata.current_step !== expectedStep) {
|
|
323
321
|
let validLifecycleArtifact = false;
|
|
324
322
|
if (currentTask) {
|
|
325
|
-
const activityConfig = loadVerificationConfig(repositoryRoot, skillName).checks?.["activity-log"];
|
|
326
323
|
const { section, invalidEntries } = inspectActivityLog(task.content);
|
|
327
|
-
if (
|
|
328
|
-
|
|
329
|
-
for (const entry of section.entries) {
|
|
330
|
-
if (!ACTIVITY_LOG_STARTED_RE.test(entry.step))
|
|
331
|
-
latestAction = entry.step;
|
|
332
|
-
}
|
|
333
|
-
validLifecycleArtifact = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, activityConfig, task, section.entries, latestAction)?.status === "pass";
|
|
324
|
+
if (section && invalidEntries.length === 0) {
|
|
325
|
+
validLifecycleArtifact = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, section.entries)?.status === "pass";
|
|
334
326
|
}
|
|
335
327
|
}
|
|
336
328
|
if (!validLifecycleArtifact) {
|
|
@@ -634,14 +626,14 @@ function checkImplementationInput({ taskDir, artifactFile }) {
|
|
|
634
626
|
return passResult("implementation-input", `${actionDecision} matches Activity Log, report, and task table`);
|
|
635
627
|
}
|
|
636
628
|
const ARTIFACT_ACTIVITY_STAGES = {
|
|
637
|
-
"analyze-task": { family: "analysis", event: "analyze.completed" },
|
|
638
|
-
"plan-task": { family: "plan", event: "plan.completed" },
|
|
639
|
-
"review-analysis": { family: "review-analysis", event: "review-analysis.completed" },
|
|
640
|
-
"review-plan": { family: "review-plan", event: "review-plan.completed" },
|
|
641
|
-
"code-task": { family: "code", event: "code.completed" },
|
|
642
|
-
"review-code": { family: "review-code", event: "review-code.completed" }
|
|
629
|
+
"analyze-task": { family: "analysis", event: "analyze.completed", action: "Analyze Task" },
|
|
630
|
+
"plan-task": { family: "plan", event: "plan.completed", action: "Plan Task" },
|
|
631
|
+
"review-analysis": { family: "review-analysis", event: "review-analysis.completed", action: "Review Analysis" },
|
|
632
|
+
"review-plan": { family: "review-plan", event: "review-plan.completed", action: "Review Plan" },
|
|
633
|
+
"code-task": { family: "code", event: "code.completed", action: "Code Task" },
|
|
634
|
+
"review-code": { family: "review-code", event: "review-code.completed", action: "Review Code" }
|
|
643
635
|
};
|
|
644
|
-
function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName,
|
|
636
|
+
function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, entries) {
|
|
645
637
|
const stage = ARTIFACT_ACTIVITY_STAGES[skillName];
|
|
646
638
|
if (!stage)
|
|
647
639
|
return null;
|
|
@@ -680,26 +672,18 @@ function checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, con
|
|
|
680
672
|
return failResult("activity-log", `Input '${input.name}' changed or is no longer current; rerun ${skillName} to refresh '${output}'`);
|
|
681
673
|
}
|
|
682
674
|
}
|
|
683
|
-
const
|
|
675
|
+
const roundActionPattern = new RegExp(`^${stage.action} \\(Round ${identity.round}(?:, [^)]+)?\\)$`);
|
|
684
676
|
const roundAction = entries.find((entry) => {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
return false;
|
|
689
|
-
expectedAction.lastIndex = 0;
|
|
690
|
-
const actionRound = /\(Round (\d+)/.exec(entry.step)?.[1];
|
|
691
|
-
return actionRound === String(identity.round) && entry.note.includes(`→ ${output}`);
|
|
677
|
+
return !ACTIVITY_LOG_STARTED_RE.test(entry.step)
|
|
678
|
+
&& roundActionPattern.test(entry.step)
|
|
679
|
+
&& entry.note.includes(`→ ${output}`);
|
|
692
680
|
});
|
|
693
681
|
if (!roundAction) {
|
|
694
682
|
return failResult("activity-log", `No completed Activity Log row records '${output}' for ${skillName} Round ${identity.round}`);
|
|
695
683
|
}
|
|
696
|
-
if (skillName === "plan-task" && /^(?:Human Decision|Decision)\b/.test(latestAction)
|
|
697
|
-
&& expectedAction.test(latestAction)) {
|
|
698
|
-
return passResult("activity-log", `Plan completion '${output}' is current; latest action '${latestAction}' is a human decision`);
|
|
699
|
-
}
|
|
700
684
|
return passResult("activity-log", `Current ${stage.family} completion '${output}' is valid for Round ${identity.round}`);
|
|
701
685
|
}
|
|
702
|
-
function checkActivityLog({ taskDir,
|
|
686
|
+
function checkActivityLog({ taskDir, skillName, artifactFile }) {
|
|
703
687
|
const task = loadTask(taskDir);
|
|
704
688
|
if (!task.ok) {
|
|
705
689
|
return failResult("activity-log", task.message);
|
|
@@ -712,37 +696,14 @@ function checkActivityLog({ taskDir, config, skillName, artifactFile }) {
|
|
|
712
696
|
const entries = section.entries;
|
|
713
697
|
if (entries.length === 0)
|
|
714
698
|
return failResult("activity-log", "Activity Log has no entries");
|
|
715
|
-
let latestAction = "";
|
|
716
|
-
let latestTimestamp = "";
|
|
717
|
-
const doneActions = [];
|
|
718
699
|
for (const entry of entries) {
|
|
719
700
|
if (!entry.note.trim())
|
|
720
701
|
return failResult("activity-log", "Activity Log entry note is required");
|
|
721
|
-
const { time: timestamp, step: action } = entry;
|
|
722
|
-
// A `[started]` marker is not a terminal action: keep latestAction/latestTimestamp
|
|
723
|
-
// on the most recent done entry so expected_action_pattern sees it.
|
|
724
|
-
if (!ACTIVITY_LOG_STARTED_RE.test(action)) {
|
|
725
|
-
latestTimestamp = timestamp;
|
|
726
|
-
latestAction = action;
|
|
727
|
-
doneActions.push(action);
|
|
728
|
-
}
|
|
729
702
|
}
|
|
730
|
-
const artifactLifecycleResult = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName,
|
|
703
|
+
const artifactLifecycleResult = checkArtifactLifecycleActivityLog(taskDir, artifactFile, skillName, task, entries);
|
|
731
704
|
if (artifactLifecycleResult)
|
|
732
705
|
return artifactLifecycleResult;
|
|
733
|
-
|
|
734
|
-
const expected = new RegExp(config.expected_action_pattern);
|
|
735
|
-
let index = doneActions.length - 1;
|
|
736
|
-
while (index >= 0 && doneActions[index] === 'Commit' && !expected.test(doneActions[index]))
|
|
737
|
-
index -= 1;
|
|
738
|
-
if (index >= 0 && expected.test(doneActions[index])) {
|
|
739
|
-
latestAction = doneActions[index];
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
if (config.expected_action_pattern && !new RegExp(config.expected_action_pattern).test(latestAction)) {
|
|
743
|
-
return failResult("activity-log", `Latest action '${latestAction}' does not match '${config.expected_action_pattern}'`);
|
|
744
|
-
}
|
|
745
|
-
return passResult("activity-log", `Latest entry '${latestAction}' at ${latestTimestamp}`);
|
|
706
|
+
return passResult("activity-log", "Activity Log is valid");
|
|
746
707
|
}
|
|
747
708
|
function checkCompletionChecklist({ taskDir, config }) {
|
|
748
709
|
const task = loadTask(taskDir);
|
|
@@ -932,10 +893,10 @@ async function checkPostReviewCommit({ taskDir, config, repositoryRoot }) {
|
|
|
932
893
|
}
|
|
933
894
|
let gitRoot;
|
|
934
895
|
try {
|
|
935
|
-
gitRoot = execFileSync("git", ["-C",
|
|
896
|
+
gitRoot = execFileSync("git", ["-C", repositoryRoot, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
|
|
936
897
|
}
|
|
937
898
|
catch {
|
|
938
|
-
return blockedResult("post-review-commit", "git unavailable or
|
|
899
|
+
return blockedResult("post-review-commit", "git unavailable or repository root is not inside a git repository");
|
|
939
900
|
}
|
|
940
901
|
const task = loadTask(taskDir);
|
|
941
902
|
if (!task.ok)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { isSandbox } from '../sandbox/environment.js';
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the physical task-workspace boundary from the verified process
|
|
7
|
+
* execution context. Sandbox mode (task-bound / branch-only) does not affect
|
|
8
|
+
* the task workspace mount location.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveTaskWorkspaceExecutionBoundary(env = process.env) {
|
|
11
|
+
if (env.AGENT_INFRA_SANDBOX !== '1')
|
|
12
|
+
return 'host';
|
|
13
|
+
const statusMountPath = env.AGENT_INFRA_CONTROL_STATUS_DIR;
|
|
14
|
+
if (!statusMountPath || !isSandbox(env, { statusMountPath })) {
|
|
15
|
+
throw new Error('task workspace boundary requires a verified sandbox execution context');
|
|
16
|
+
}
|
|
17
|
+
return 'container';
|
|
18
|
+
}
|
|
19
|
+
export function resolveTaskWorkspaceLayout(input) {
|
|
20
|
+
const { project, boundary } = input;
|
|
21
|
+
if (!project || project === '.' || project === '..' || /[\\/\u0000-\u001f\u007f]/u.test(project)) {
|
|
22
|
+
throw new TypeError('project must be a safe single path segment');
|
|
23
|
+
}
|
|
24
|
+
let root;
|
|
25
|
+
if (boundary === 'container') {
|
|
26
|
+
root = '/task-workspace';
|
|
27
|
+
}
|
|
28
|
+
else if (boundary === 'host') {
|
|
29
|
+
if (!input.home)
|
|
30
|
+
throw new TypeError('home is required for host task workspace resolution');
|
|
31
|
+
if (!path.isAbsolute(input.home))
|
|
32
|
+
throw new TypeError('home must be an absolute path for host task workspace resolution');
|
|
33
|
+
root = path.join(input.home, '.agent-infra', 'task-workspaces', project);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
throw new TypeError(`unsupported task workspace boundary: ${String(boundary)}`);
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
projectKey: project,
|
|
40
|
+
boundary,
|
|
41
|
+
root,
|
|
42
|
+
active: path.join(root, 'active'),
|
|
43
|
+
blocked: path.join(root, 'blocked'),
|
|
44
|
+
completed: path.join(root, 'completed'),
|
|
45
|
+
archive: path.join(root, 'archive'),
|
|
46
|
+
shortIds: path.join(root, 'active', '.short-ids.json')
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function resolveProjectTaskWorkspaceLayout(repoRoot, boundary = resolveTaskWorkspaceExecutionBoundary()) {
|
|
50
|
+
const configPath = path.join(repoRoot, '.agents', '.airc.json');
|
|
51
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
52
|
+
if (typeof config.project !== 'string')
|
|
53
|
+
throw new TypeError(`project is missing from ${configPath}`);
|
|
54
|
+
return resolveTaskWorkspaceLayout({ project: config.project, boundary, home: process.env.HOME || os.homedir() });
|
|
55
|
+
}
|
|
56
|
+
export function resolveProjectTaskWorkspaceRoot(repoRoot) {
|
|
57
|
+
return resolveProjectTaskWorkspaceLayout(repoRoot).root;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=workspace-root.js.map
|
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { resolveProjectTaskWorkspaceRoot } from './workspace-root.js';
|
|
6
7
|
function git(repoRoot, indexFile, args) {
|
|
7
8
|
const env = indexFile ? { ...process.env, GIT_INDEX_FILE: indexFile } : process.env;
|
|
8
9
|
const result = spawnSync('git', args, { cwd: repoRoot, env, encoding: 'utf8' });
|
|
@@ -32,7 +33,7 @@ function captureWorktreeTree(repoRoot, forcedPath) {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
function taskFileFingerprints(stateRoot, taskId) {
|
|
35
|
-
const activeRoot = path.join(stateRoot, '
|
|
36
|
+
const activeRoot = path.join(resolveProjectTaskWorkspaceRoot(stateRoot), 'active');
|
|
36
37
|
const roots = taskId ? [path.join(activeRoot, taskId)] : [activeRoot];
|
|
37
38
|
const records = [];
|
|
38
39
|
const visit = (absolute, relative) => {
|
|
@@ -45,7 +46,7 @@ function taskFileFingerprints(stateRoot, taskId) {
|
|
|
45
46
|
}
|
|
46
47
|
if (!stat.isFile() && !stat.isSymbolicLink())
|
|
47
48
|
return;
|
|
48
|
-
if (
|
|
49
|
+
if (/^task-workspace\/(?:active|blocked|completed)\/TASK-[0-9]{8}-[0-9]{6}\/\.runtime\/orchestration\.json$/u.test(relative))
|
|
49
50
|
return;
|
|
50
51
|
const content = stat.isSymbolicLink()
|
|
51
52
|
? Buffer.from(fs.readlinkSync(absolute))
|
|
@@ -60,7 +61,7 @@ function taskFileFingerprints(stateRoot, taskId) {
|
|
|
60
61
|
for (const root of roots) {
|
|
61
62
|
if (!fs.existsSync(root))
|
|
62
63
|
continue;
|
|
63
|
-
const relative = path.posix.join('
|
|
64
|
+
const relative = path.posix.join('task-workspace/active', path.relative(activeRoot, root).split(path.sep).join('/'));
|
|
64
65
|
visit(root, relative.replace(/\/$/, ''));
|
|
65
66
|
}
|
|
66
67
|
return records.sort((left, right) => left.path.localeCompare(right.path));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"protocolVersion": 3,
|
|
3
|
-
"packageVersion": "0.
|
|
4
|
-
"sourceInputHash": "
|
|
5
|
-
"internalExecutableBuildHash": "
|
|
3
|
+
"packageVersion": "0.12.1",
|
|
4
|
+
"sourceInputHash": "b998fe9d348d3f7f55e1258d2d09793f09240d1d70173d6bce49a9ce6c89429e",
|
|
5
|
+
"internalExecutableBuildHash": "d75b6e06c5ed88b0cd03663d98e2001c3f5c661d9637b8e6b8993580f69a3f16"
|
|
6
6
|
}
|
|
@@ -11,7 +11,7 @@ import { captureTaskWriteMetadata, writeTask } from '../../../task/write.ts';
|
|
|
11
11
|
import { parseTypedTaskFrontmatter } from '../../../task/frontmatter.ts';
|
|
12
12
|
import { resolveTaskRef } from '../../../task/resolve-ref.ts';
|
|
13
13
|
import {
|
|
14
|
-
|
|
14
|
+
recoverActivatedOrchestrationDelegation,
|
|
15
15
|
readRun
|
|
16
16
|
} from '../../../task/orchestration.ts';
|
|
17
17
|
import type { OrchestrationOptions, OrchestrationRun } from '../../../task/orchestration.ts';
|
|
@@ -265,7 +265,7 @@ function appendRecoveryLog(
|
|
|
265
265
|
});
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
-
function
|
|
268
|
+
function recoverStartedLifecycle(
|
|
269
269
|
request: LifecycleRecoveryRequest,
|
|
270
270
|
options: LifecycleRecoveryOptions = {}
|
|
271
271
|
): LifecycleRecoveryResult {
|
|
@@ -372,7 +372,7 @@ function consumeRecoveryEvidence(
|
|
|
372
372
|
let consumed = stored;
|
|
373
373
|
if (stored.consumer === null) {
|
|
374
374
|
try {
|
|
375
|
-
consumed = store.
|
|
375
|
+
consumed = store.consume(pending.childId!, pending.id, stored.state.startEvidence?.hookDefinitionHash, {
|
|
376
376
|
taskId: pending.taskId, runId: pending.runId, receiptId: pending.id
|
|
377
377
|
});
|
|
378
378
|
} catch (error) {
|
|
@@ -393,7 +393,7 @@ function finishActiveRecovery(
|
|
|
393
393
|
row: StepRow,
|
|
394
394
|
options: LifecycleRecoveryOptions
|
|
395
395
|
): LifecycleRecoveryResult {
|
|
396
|
-
const recovered =
|
|
396
|
+
const recovered = recoverActivatedOrchestrationDelegation(taskId, {
|
|
397
397
|
receiptId: pending.id,
|
|
398
398
|
stage: pending.stage,
|
|
399
399
|
round: pending.round,
|
|
@@ -411,8 +411,8 @@ function recoverStartedLifecycleFromAdapter(
|
|
|
411
411
|
request: LifecycleRecoveryRequest,
|
|
412
412
|
options: LifecycleRecoveryOptions = {}
|
|
413
413
|
): LifecycleRecoveryResult {
|
|
414
|
-
return
|
|
414
|
+
return recoverStartedLifecycle(request, options);
|
|
415
415
|
}
|
|
416
416
|
|
|
417
|
-
export {
|
|
417
|
+
export { recoverStartedLifecycle, recoverStartedLifecycleFromAdapter };
|
|
418
418
|
export type { LifecycleRecoveryOptions, LifecycleRecoveryRequest, LifecycleRecoveryResult };
|
|
@@ -3,7 +3,6 @@ import path from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
mutateDelegationAdapterEvidence,
|
|
6
|
-
mutateDelegationAdapterEvidenceWithinTaskLock,
|
|
7
6
|
readRun
|
|
8
7
|
} from '../../../task/orchestration.ts';
|
|
9
8
|
import type { DelegationReceipt } from '../../../task/delegation-receipts.ts';
|
|
@@ -195,12 +194,10 @@ function createCodexLifecycleStore(options: CodexLifecycleStoreOptions) {
|
|
|
195
194
|
function update(
|
|
196
195
|
binding: CodexLifecycleTaskBinding,
|
|
197
196
|
key: string,
|
|
198
|
-
mutate: (current: StoredCodexLifecycle | null) => StoredCodexLifecycle
|
|
199
|
-
taskLockHeld = false
|
|
197
|
+
mutate: (current: StoredCodexLifecycle | null) => StoredCodexLifecycle
|
|
200
198
|
): StoredCodexLifecycle {
|
|
201
199
|
let result: StoredCodexLifecycle | null = null;
|
|
202
|
-
|
|
203
|
-
updateState(options.taskId, binding.receiptId, 'codex', (value) => {
|
|
200
|
+
mutateDelegationAdapterEvidence(options.taskId, binding.receiptId, 'codex', (value) => {
|
|
204
201
|
const currentState = storedEvidence(value);
|
|
205
202
|
const current = currentState.records[key] ?? null;
|
|
206
203
|
result = mutate(current);
|
|
@@ -304,23 +301,18 @@ function createCodexLifecycleStore(options: CodexLifecycleStoreOptions) {
|
|
|
304
301
|
return matches[0]!;
|
|
305
302
|
}
|
|
306
303
|
|
|
307
|
-
function
|
|
304
|
+
function consume(
|
|
308
305
|
childThreadId: string,
|
|
309
306
|
consumer: string,
|
|
310
|
-
expectedHookDefinitionHash
|
|
311
|
-
expectedTaskBinding
|
|
312
|
-
taskLockHeld: boolean
|
|
307
|
+
expectedHookDefinitionHash?: string,
|
|
308
|
+
expectedTaskBinding?: CodexLifecycleTaskBinding
|
|
313
309
|
): StoredCodexLifecycle {
|
|
314
310
|
if (!consumer.trim()) throw new Error('Codex lifecycle consumer is required');
|
|
315
311
|
const current = read(childThreadId);
|
|
316
312
|
const binding = expectedTaskBinding ?? current.taskBinding;
|
|
317
313
|
if (!binding) throw new Error('Codex lifecycle task receipt binding is missing');
|
|
318
314
|
const spawn = current.state.spawn;
|
|
319
|
-
if (!spawn)
|
|
320
|
-
throw new Error(taskLockHeld
|
|
321
|
-
? 'Codex lifecycle task receipt binding is missing'
|
|
322
|
-
: 'Codex lifecycle spawn evidence is missing');
|
|
323
|
-
}
|
|
315
|
+
if (!spawn) throw new Error('Codex lifecycle spawn evidence is missing');
|
|
324
316
|
const key = recordKey(spawn.sessionId, spawn.turnId, spawn.toolUseId);
|
|
325
317
|
return update(binding, key, (latest) => {
|
|
326
318
|
if (!latest || expectedTaskBinding && JSON.stringify(latest.taskBinding) !== JSON.stringify(expectedTaskBinding)) {
|
|
@@ -335,25 +327,7 @@ function createCodexLifecycleStore(options: CodexLifecycleStoreOptions) {
|
|
|
335
327
|
}
|
|
336
328
|
if (latest.consumer) return latest;
|
|
337
329
|
return Object.freeze({ ...latest, revision: latest.revision + 1, consumer, consumedAt: now(), updatedAt: now() });
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
function consume(
|
|
342
|
-
childThreadId: string,
|
|
343
|
-
consumer: string,
|
|
344
|
-
expectedHookDefinitionHash?: string,
|
|
345
|
-
expectedTaskBinding?: CodexLifecycleTaskBinding
|
|
346
|
-
): StoredCodexLifecycle {
|
|
347
|
-
return consumeWithLockMode(childThreadId, consumer, expectedHookDefinitionHash, expectedTaskBinding, false);
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function consumeWithinTaskLock(
|
|
351
|
-
childThreadId: string,
|
|
352
|
-
consumer: string,
|
|
353
|
-
expectedHookDefinitionHash?: string,
|
|
354
|
-
expectedTaskBinding?: CodexLifecycleTaskBinding
|
|
355
|
-
): StoredCodexLifecycle {
|
|
356
|
-
return consumeWithLockMode(childThreadId, consumer, expectedHookDefinitionHash, expectedTaskBinding, true);
|
|
330
|
+
});
|
|
357
331
|
}
|
|
358
332
|
|
|
359
333
|
function expireBefore(cutoff: string): number {
|
|
@@ -373,7 +347,7 @@ function createCodexLifecycleStore(options: CodexLifecycleStoreOptions) {
|
|
|
373
347
|
return changed;
|
|
374
348
|
}
|
|
375
349
|
|
|
376
|
-
return Object.freeze({ taskId: options.taskId, root: path.join(taskDir, '.runtime'), apply, applyToSpawn, consume,
|
|
350
|
+
return Object.freeze({ taskId: options.taskId, root: path.join(taskDir, '.runtime'), apply, applyToSpawn, consume, expireBefore, findByParent, findByTaskBinding, read });
|
|
377
351
|
}
|
|
378
352
|
|
|
379
353
|
export { createCodexLifecycleStore, hasActiveCodexLifecycleEvidence, readCodexLifecycleActivationEvidence };
|
|
@@ -481,7 +481,7 @@ async function sealCodexOrchestrationDelegation(
|
|
|
481
481
|
coreOptions(options),
|
|
482
482
|
() => {
|
|
483
483
|
try {
|
|
484
|
-
const consumed = store.
|
|
484
|
+
const consumed = store.consume(
|
|
485
485
|
childThreadId,
|
|
486
486
|
current.receipt.id,
|
|
487
487
|
existing.state.spawn?.hookDefinitionHash,
|
package/lib/decide.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { parseTaskScope } from './task/command-options.ts';
|
|
|
3
3
|
import { applyHumanDecision } from './task/decision-intents.ts';
|
|
4
4
|
import { canonicalTimestamp } from './task/write.ts';
|
|
5
5
|
import { resolveTaskContext } from './task/resolve-ref.ts';
|
|
6
|
-
import { TaskExecutionLockError, withTaskExecutionLock } from './task/task-execution-lock.ts';
|
|
7
6
|
|
|
8
7
|
type DecideOptions = {
|
|
9
8
|
repoRoot?: string;
|
|
@@ -70,15 +69,11 @@ export async function decide(args: string[], options: DecideOptions = {}): Promi
|
|
|
70
69
|
repoRoot: resolved.repoRoot,
|
|
71
70
|
metadataProvider: () => ({ timestamp: now, agentInfraVersion: options.version ?? VERSION })
|
|
72
71
|
};
|
|
73
|
-
|
|
74
|
-
const execute = async () => applyHumanDecision(request, writeOptions);
|
|
75
|
-
result = await withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-decision', execute);
|
|
72
|
+
const result = await applyHumanDecision(request, writeOptions);
|
|
76
73
|
if (result.error) throw new Error(result.error.message);
|
|
77
74
|
return 0;
|
|
78
75
|
} catch (error) {
|
|
79
|
-
const message = error instanceof
|
|
80
|
-
? `${error.code}: ${error.message}`
|
|
81
|
-
: error instanceof Error ? error.message : String(error);
|
|
76
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
82
77
|
process.stderr.write(`Error: ${message}\n`);
|
|
83
78
|
return 1;
|
|
84
79
|
}
|
|
@@ -52,6 +52,7 @@ export const INTERNAL_HANDLER_ROUTE_SELECTORS = Object.freeze({
|
|
|
52
52
|
'pr-review-grade': ['decide', 'resolve-host', 'verify-artifact'],
|
|
53
53
|
'platform-checks': ['inspect', 'watch', 'resolve-run', 'logs'],
|
|
54
54
|
'task-context': ['resolve'],
|
|
55
|
+
'task-workspace': ['resolve'],
|
|
55
56
|
'task-ledger': ['decision-next-id', 'stage-status', 'finding-upsert', 'finding-respond', 'finding-review', 'decision-upsert', 'rework-intent-upsert', 'rework-intent-rebuild'],
|
|
56
57
|
'task-warning': ['list', 'add', 'set-status'],
|
|
57
58
|
'task-activity': ['pr-review-inspect', 'pr-review-start', 'pr-review-complete', 'pr-review-terminate'],
|
|
@@ -104,6 +105,7 @@ export function internalRouteSelector(command: string, args: readonly string[]):
|
|
|
104
105
|
if (['task-ledger', 'task-warning', 'task-activity'].includes(command)) return args[1] ?? '';
|
|
105
106
|
if (command === 'task-delivery') return args[1] ?? '';
|
|
106
107
|
if (command === 'task-context') return first(args);
|
|
108
|
+
if (command === 'task-workspace') return first(args);
|
|
107
109
|
return first(args);
|
|
108
110
|
}
|
|
109
111
|
|