@fitlab-ai/agent-infra 0.9.13 → 0.9.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/bin/cli.ts +26 -9
- package/dist/bin/cli.js +173 -157
- package/dist/bin/internal-cli.js +42 -21
- package/dist/lib/agent-client.js +5 -0
- package/dist/lib/internal/agent-client.js +5 -2
- package/dist/lib/internal/cli-route-inventory.js +152 -0
- package/dist/lib/internal/codex-lifecycle.js +9 -6
- package/dist/lib/internal/codex-sandbox-controller.js +8 -2
- package/dist/lib/internal/git-workflow.js +10 -6
- package/dist/lib/internal/platform-checks.js +16 -4
- package/dist/lib/internal/platform-comment.js +16 -4
- package/dist/lib/internal/platform-context.js +4 -1
- package/dist/lib/internal/platform-issue.js +12 -4
- package/dist/lib/internal/platform-metadata.js +88 -0
- package/dist/lib/internal/platform-pr-review.js +16 -3
- package/dist/lib/internal/platform-pr.js +24 -10
- package/dist/lib/internal/platform-release-notes.js +6 -3
- package/dist/lib/internal/platform-security.js +93 -0
- package/dist/lib/internal/pr-review-grade.js +14 -3
- package/dist/lib/internal/release-workflow.js +19 -5
- package/dist/lib/internal/sandbox-control.js +22 -5
- package/dist/lib/internal/task-activity.js +13 -4
- package/dist/lib/internal/task-artifact.js +186 -27
- package/dist/lib/internal/task-context.js +4 -1
- package/dist/lib/internal/task-create.js +48 -15
- package/dist/lib/internal/task-delivery.js +4 -1
- package/dist/lib/internal/task-event.js +4 -1
- package/dist/lib/internal/task-finalization.js +4 -1
- package/dist/lib/internal/task-invalidation.js +4 -1
- package/dist/lib/internal/task-ledger.js +12 -1
- package/dist/lib/internal/task-lifecycle.js +4 -1
- package/dist/lib/internal/task-operation-registry.js +421 -0
- package/dist/lib/internal/task-orchestration.js +12 -0
- package/dist/lib/internal/task-override.js +10 -3
- package/dist/lib/internal/task-qualification.js +90 -0
- package/dist/lib/internal/task-review.js +4 -1
- package/dist/lib/internal/task-short-id.js +11 -1
- package/dist/lib/internal/task-snapshot.js +4 -1
- package/dist/lib/internal/task-validate.js +7 -2
- package/dist/lib/internal/task-verify.js +5 -1
- package/dist/lib/internal/task-warning.js +8 -1
- package/dist/lib/platform/comment-safety.js +226 -0
- package/dist/lib/platform/github-provider.js +233 -6
- package/dist/lib/platform/issue-comments.js +146 -34
- package/dist/lib/platform/pr-change-report.js +6 -12
- package/dist/lib/platform/pr-summary.js +28 -7
- package/dist/lib/platform/provider-contract.d.ts +67 -1
- package/dist/lib/platform/provider-contract.js +6 -2
- package/dist/lib/platform/provider-validation.js +76 -3
- package/dist/lib/platform/pull-requests.js +115 -170
- package/dist/lib/platform/repository-metadata.js +377 -0
- package/dist/lib/platform/security-alerts.js +155 -0
- package/dist/lib/platform/verification-sync.js +33 -26
- package/dist/lib/process-data/index.js +7 -0
- package/dist/lib/run/index.js +5 -0
- package/dist/lib/sandbox/commands/control-status.js +22 -0
- package/dist/lib/sandbox/commands/create.js +32 -6
- package/dist/lib/sandbox/commands/ls.js +5 -0
- package/dist/lib/sandbox/commands/rm.js +827 -120
- package/dist/lib/sandbox/commands/show.js +16 -0
- package/dist/lib/sandbox/control/client.js +83 -9
- package/dist/lib/sandbox/control/completed-reentry.js +85 -0
- package/dist/lib/sandbox/control/container-identity.js +28 -31
- package/dist/lib/sandbox/control/executor.js +149 -14
- package/dist/lib/sandbox/control/lifecycle.js +621 -127
- package/dist/lib/sandbox/control/native-file-lock.js +177 -0
- package/dist/lib/sandbox/control/server.js +305 -35
- package/dist/lib/sandbox/control/state.js +5 -3
- package/dist/lib/sandbox/control/task-view.js +183 -0
- package/dist/lib/sandbox/engines/authority.js +289 -0
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +97 -0
- package/dist/lib/sandbox/index.js +5 -0
- package/dist/lib/sandbox/recovery.js +21 -1
- package/dist/lib/sandbox/workspace-view.js +2 -1
- package/dist/lib/sandbox/worktree-safety.js +4 -1
- package/dist/lib/server/index.js +8 -0
- package/dist/lib/task/artifact-lifecycle.js +42 -13
- package/dist/lib/task/artifact-operations.js +520 -0
- package/dist/lib/task/artifact-repair-intent.js +59 -0
- package/dist/lib/task/artifact-schema.js +135 -0
- package/dist/lib/task/capabilities.js +72 -1
- package/dist/lib/task/control-authority.js +4 -0
- package/dist/lib/task/create-service.js +103 -4
- package/dist/lib/task/create.js +25 -0
- package/dist/lib/task/events.js +186 -67
- package/dist/lib/task/index.js +11 -3
- package/dist/lib/task/local-artifact-finalization.js +75 -150
- package/dist/lib/task/orchestration.js +192 -52
- package/dist/lib/task/qualification-audit.js +490 -0
- package/dist/lib/task/qualification-confirmation.js +109 -0
- package/dist/lib/task/qualification-intents.js +148 -0
- package/dist/lib/task/review-artifacts.js +22 -23
- package/dist/lib/task/review-finalization.js +121 -4
- package/dist/lib/task/sections.js +6 -4
- package/dist/lib/task/verification-config.js +11 -0
- package/dist/lib/task/verification-engine.js +54 -4
- package/dist/lifecycle-build-manifest.json +3 -3
- package/lib/agent-client.ts +9 -0
- package/lib/internal/agent-client.ts +4 -2
- package/lib/internal/cli-route-inventory.ts +140 -0
- package/lib/internal/codex-lifecycle.ts +8 -6
- package/lib/internal/codex-sandbox-controller.ts +7 -2
- package/lib/internal/git-workflow.ts +9 -6
- package/lib/internal/platform-checks.ts +12 -4
- package/lib/internal/platform-comment.ts +12 -4
- package/lib/internal/platform-context.ts +3 -1
- package/lib/internal/platform-issue.ts +11 -4
- package/lib/internal/platform-metadata.ts +70 -0
- package/lib/internal/platform-pr-review.ts +14 -3
- package/lib/internal/platform-pr.ts +23 -10
- package/lib/internal/platform-release-notes.ts +5 -3
- package/lib/internal/platform-security.ts +83 -0
- package/lib/internal/pr-review-grade.ts +10 -3
- package/lib/internal/release-workflow.ts +17 -5
- package/lib/internal/sandbox-control.ts +19 -5
- package/lib/internal/task-activity.ts +12 -4
- package/lib/internal/task-artifact.ts +164 -25
- package/lib/internal/task-context.ts +3 -1
- package/lib/internal/task-create.ts +76 -15
- package/lib/internal/task-delivery.ts +3 -1
- package/lib/internal/task-event.ts +3 -1
- package/lib/internal/task-finalization.ts +3 -1
- package/lib/internal/task-invalidation.ts +3 -1
- package/lib/internal/task-ledger.ts +11 -1
- package/lib/internal/task-lifecycle.ts +3 -1
- package/lib/internal/task-operation-registry.ts +482 -0
- package/lib/internal/task-orchestration.ts +12 -0
- package/lib/internal/task-override.ts +9 -3
- package/lib/internal/task-qualification.ts +61 -0
- package/lib/internal/task-review.ts +3 -1
- package/lib/internal/task-short-id.ts +10 -1
- package/lib/internal/task-snapshot.ts +3 -1
- package/lib/internal/task-validate.ts +6 -2
- package/lib/internal/task-verify.ts +4 -1
- package/lib/internal/task-warning.ts +7 -1
- package/lib/platform/comment-safety.ts +250 -0
- package/lib/platform/github-provider.ts +229 -7
- package/lib/platform/issue-comments.ts +160 -35
- package/lib/platform/pr-change-report.ts +6 -12
- package/lib/platform/pr-summary.ts +27 -6
- package/lib/platform/provider-contract.ts +78 -3
- package/lib/platform/provider-validation.ts +85 -3
- package/lib/platform/pull-requests.ts +126 -178
- package/lib/platform/repository-metadata.ts +453 -0
- package/lib/platform/security-alerts.ts +191 -0
- package/lib/platform/verification-sync.ts +32 -28
- package/lib/process-data/index.ts +7 -0
- package/lib/run/index.ts +5 -0
- package/lib/sandbox/commands/control-status.ts +26 -0
- package/lib/sandbox/commands/create.ts +46 -6
- package/lib/sandbox/commands/ls.ts +7 -0
- package/lib/sandbox/commands/rm.ts +1000 -87
- package/lib/sandbox/commands/show.ts +16 -0
- package/lib/sandbox/control/client.ts +103 -9
- package/lib/sandbox/control/completed-reentry.ts +98 -0
- package/lib/sandbox/control/container-identity.ts +27 -43
- package/lib/sandbox/control/executor.ts +177 -12
- package/lib/sandbox/control/lifecycle.ts +629 -17
- package/lib/sandbox/control/native-file-lock.ts +209 -0
- package/lib/sandbox/control/protocol.ts +5 -2
- package/lib/sandbox/control/server.ts +319 -37
- package/lib/sandbox/control/state.ts +6 -3
- package/lib/sandbox/control/task-view.ts +240 -0
- package/lib/sandbox/engines/authority.ts +365 -0
- package/lib/sandbox/engines/docker-exact-discovery.ts +132 -0
- package/lib/sandbox/index.ts +7 -0
- package/lib/sandbox/recovery.ts +21 -1
- package/lib/sandbox/workspace-view.ts +9 -3
- package/lib/sandbox/worktree-safety.ts +4 -1
- package/lib/server/index.ts +10 -0
- package/lib/task/artifact-lifecycle.ts +38 -16
- package/lib/task/artifact-operations.ts +626 -0
- package/lib/task/artifact-repair-intent.ts +71 -0
- package/lib/task/artifact-schema.ts +192 -0
- package/lib/task/capabilities.ts +70 -1
- package/lib/task/control-authority.ts +11 -1
- package/lib/task/create-service.ts +131 -6
- package/lib/task/create.ts +27 -0
- package/lib/task/events.ts +161 -65
- package/lib/task/index.ts +16 -3
- package/lib/task/local-artifact-finalization.ts +87 -218
- package/lib/task/orchestration.ts +172 -49
- package/lib/task/qualification-audit.ts +599 -0
- package/lib/task/qualification-confirmation.ts +117 -0
- package/lib/task/qualification-intents.ts +150 -0
- package/lib/task/review-artifacts.ts +21 -22
- package/lib/task/review-finalization.ts +133 -4
- package/lib/task/sections.ts +6 -4
- package/lib/task/verification-config.ts +12 -0
- package/lib/task/verification-engine.ts +55 -4
- package/package.json +6 -1
- package/templates/.agents/rules/README.en.md +2 -0
- package/templates/.agents/rules/README.zh-CN.md +2 -0
- package/templates/.agents/rules/decision-qualification.en.md +22 -0
- package/templates/.agents/rules/decision-qualification.zh-CN.md +22 -0
- package/templates/.agents/rules/evidence-reporting.en.md +28 -0
- package/templates/.agents/rules/evidence-reporting.zh-CN.md +28 -0
- package/templates/.agents/rules/label-milestone-setup.en.md +7 -7
- package/templates/.agents/rules/label-milestone-setup.zh-CN.md +7 -7
- package/templates/.agents/rules/local-artifact-repair.en.md +5 -1
- package/templates/.agents/rules/local-artifact-repair.zh-CN.md +5 -1
- package/templates/.agents/rules/security-alerts.en.md +8 -8
- package/templates/.agents/rules/security-alerts.zh-CN.md +8 -8
- package/templates/.agents/skills/analyze-task/SKILL.en.md +15 -2
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +19 -2
- package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -12
- package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -12
- package/templates/.agents/skills/close-codescan/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.en.md +2 -2
- package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/code-task/config/verify.en.json +5 -14
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +5 -14
- package/templates/.agents/skills/code-task/reference/code-rules.en.md +5 -4
- package/templates/.agents/skills/code-task/reference/code-rules.zh-CN.md +5 -4
- package/templates/.agents/skills/code-task/reference/dual-mode.en.md +1 -1
- package/templates/.agents/skills/code-task/reference/dual-mode.zh-CN.md +1 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +3 -1
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +3 -1
- package/templates/.agents/skills/code-task/reference/report-template.en.md +42 -15
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +39 -12
- package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +5 -1
- package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
- package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
- package/templates/.agents/skills/complete-task/SKILL.en.md +9 -22
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +9 -22
- package/templates/.agents/skills/create-task/SKILL.en.md +8 -0
- package/templates/.agents/skills/create-task/SKILL.zh-CN.md +7 -0
- 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-dependabot/SKILL.en.md +1 -1
- package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/init-labels/SKILL.en.md +8 -8
- package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +8 -8
- package/templates/.agents/skills/init-milestones/SKILL.en.md +9 -11
- package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +9 -11
- package/templates/.agents/skills/plan-task/SKILL.en.md +14 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +16 -1
- package/templates/.agents/skills/plan-task/config/verify.en.json +4 -14
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +4 -14
- package/templates/.agents/skills/review-analysis/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +50 -23
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-code/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-code/config/verify.en.json +1 -23
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -23
- package/templates/.agents/skills/review-code/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-plan/SKILL.en.md +14 -1
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -1
- package/templates/.agents/skills/review-plan/config/verify.en.json +1 -18
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -18
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +49 -22
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +45 -18
- package/templates/.agents/skills/review-pr/SKILL.en.md +5 -1
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/review-pr/reference/report-template.en.md +4 -3
- package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +4 -3
- package/templates/.agents/skills/run-manual-validation/SKILL.en.md +5 -1
- package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +5 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +3 -1
- package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +3 -1
- package/templates/.agents/skills/test/SKILL.en.md +13 -2
- package/templates/.agents/skills/test/SKILL.zh-CN.md +13 -2
- package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +14 -0
- package/templates/.agents/templates/task.en.md +6 -0
- package/templates/.agents/templates/task.zh-CN.md +6 -0
- package/templates/.agents/scripts/security-alerts.github.sh +0 -151
- package/templates/.agents/scripts/security-alerts.sh +0 -31
- package/templates/.agents/skills/init-labels/scripts/init-labels.github.sh +0 -146
- package/templates/.agents/skills/init-labels/scripts/init-labels.sh +0 -32
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.github.sh +0 -294
- package/templates/.agents/skills/init-milestones/scripts/init-milestones.sh +0 -6
package/lib/task/events.ts
CHANGED
|
@@ -35,19 +35,20 @@ import { captureTaskWriteMetadata, writeTask } from './write.ts';
|
|
|
35
35
|
import type { TaskOperationSummary, TaskWriteErrorCode, TaskWriteOptions } from './write.ts';
|
|
36
36
|
import { allowsManualOverride } from './guard-override.ts';
|
|
37
37
|
import {
|
|
38
|
-
LOCAL_ARTIFACT_REQUIRED_PATTERNS,
|
|
39
|
-
LOCAL_ARTIFACT_REQUIRED_SECTIONS,
|
|
40
38
|
consumeLocalArtifactFinalizationIntent,
|
|
41
39
|
readLocalArtifactFinalizationIntent,
|
|
42
40
|
validateLocalArtifact
|
|
43
41
|
} from './local-artifact-finalization.ts';
|
|
44
42
|
import type { LocalArtifactFamily, LocalArtifactFinalizationIntent } from './local-artifact-finalization.ts';
|
|
45
|
-
import { loadVerificationConfig } from './verification-config.ts';
|
|
46
43
|
import { buildLifecycleFacts, canStart } from './capabilities.ts';
|
|
47
44
|
import type { ExplicitTrigger, LifecycleAction, TriggerInitiator, TriggerReason } from './capabilities.ts';
|
|
48
45
|
import { createInvalidationOperation, invalidationMutation, parseInvalidationDocument, targetIdFor, upsertInvalidation } from './invalidation.ts';
|
|
49
46
|
import type { InvalidationTargetKind } from './invalidation.ts';
|
|
50
47
|
import { consumeReworkIntents, parseReworkIntentDocument, reworkIntentMutation, supersedeReworkIntents } from './rework-intent.ts';
|
|
48
|
+
import { ARTIFACT_FAMILIES, expectedQualificationRelations, parseQualificationAudit, parseTaskQualification, upstreamArtifactDigest, validateQualificationAudit } from './qualification-audit.ts';
|
|
49
|
+
import type { QualificationAudit, UpstreamRelation } from './qualification-audit.ts';
|
|
50
|
+
import { getArtifactSchema } from './artifact-schema.ts';
|
|
51
|
+
import { inspectArtifactContract } from './artifact-operations.ts';
|
|
51
52
|
|
|
52
53
|
const eventCatalog = [
|
|
53
54
|
'analyze.started', 'analyze.awaiting-input', 'analyze.completed',
|
|
@@ -117,30 +118,6 @@ const SCHEMAS: Record<TaskEventName, { required?: string[]; optional?: string[]
|
|
|
117
118
|
'validation-run.completed': { required: ['artifact'], optional: ['round'] }
|
|
118
119
|
};
|
|
119
120
|
|
|
120
|
-
function localArtifactValidationConfig(repoRoot: string, family: LocalArtifactFamily) {
|
|
121
|
-
const fallback = {
|
|
122
|
-
requiredSections: LOCAL_ARTIFACT_REQUIRED_SECTIONS[family],
|
|
123
|
-
requiredPatterns: LOCAL_ARTIFACT_REQUIRED_PATTERNS
|
|
124
|
-
};
|
|
125
|
-
const skillName = family === 'analysis' ? 'analyze-task' : family === 'plan' ? 'plan-task' : 'code-task';
|
|
126
|
-
try {
|
|
127
|
-
const artifact = loadVerificationConfig(repoRoot, skillName).checks.artifact;
|
|
128
|
-
if (!artifact || typeof artifact !== 'object' || Array.isArray(artifact)) return fallback;
|
|
129
|
-
const sections = artifact.required_sections;
|
|
130
|
-
const patterns = artifact.required_patterns;
|
|
131
|
-
return {
|
|
132
|
-
requiredSections: Array.isArray(sections)
|
|
133
|
-
? sections.filter((value): value is string => typeof value === 'string')
|
|
134
|
-
: fallback.requiredSections,
|
|
135
|
-
requiredPatterns: Array.isArray(patterns)
|
|
136
|
-
? patterns.filter((value): value is string => typeof value === 'string')
|
|
137
|
-
: fallback.requiredPatterns
|
|
138
|
-
};
|
|
139
|
-
} catch {
|
|
140
|
-
return fallback;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
121
|
function validateTaskEventRequest(request: TaskEventRequest): TaskEventError | null {
|
|
145
122
|
if (!eventCatalog.includes(request.event as TaskEventName)) return { code: 'EVENT_UNKNOWN', message: `unknown task event '${request.event}'` };
|
|
146
123
|
if (!request.taskRef || !request.agent) return { code: 'EVENT_PAYLOAD_INVALID', message: 'taskRef and agent are required' };
|
|
@@ -347,6 +324,25 @@ function reviewInputFamily(family: EventFamily): ArtifactFamily {
|
|
|
347
324
|
return family === 'review-analysis' ? 'analysis' : family === 'review-plan' ? 'plan' : 'code';
|
|
348
325
|
}
|
|
349
326
|
|
|
327
|
+
function relationForStartedInput(family: EventFamily, input: ArtifactIdentity): UpstreamRelation['relation'] {
|
|
328
|
+
if (family.startsWith('review-')) {
|
|
329
|
+
return input.family === reviewInputFamily(family) ? 'reviewed-input' : 'approval-context';
|
|
330
|
+
}
|
|
331
|
+
const consumer = family === 'analyze' ? 'analysis' : family;
|
|
332
|
+
if ((consumer === 'plan' && input.family === 'analysis') || (consumer === 'code' && input.family === 'plan')) return 'required-input';
|
|
333
|
+
return 'review-context';
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function qualificationRelationsForStarted(family: EventFamily, inputs: readonly ArtifactIdentity[]): UpstreamRelation[] {
|
|
337
|
+
return inputs.map((input) => ({
|
|
338
|
+
upstreamFamily: input.family as UpstreamRelation['upstreamFamily'],
|
|
339
|
+
upstreamArtifact: input.name,
|
|
340
|
+
upstreamRound: input.round,
|
|
341
|
+
upstreamSha256: sha256File(input.path),
|
|
342
|
+
relation: relationForStartedInput(family, input)
|
|
343
|
+
}));
|
|
344
|
+
}
|
|
345
|
+
|
|
350
346
|
function lifecycleAction(family: EventFamily): LifecycleAction {
|
|
351
347
|
return family === 'analyze' ? 'analysis' : family;
|
|
352
348
|
}
|
|
@@ -381,49 +377,118 @@ function invalidationMutationForCompletion(
|
|
|
381
377
|
code: ['review-code']
|
|
382
378
|
};
|
|
383
379
|
const sourceFamily = family as 'analyze' | 'plan' | 'code';
|
|
380
|
+
const sourceArtifactFamily = sourceFamily === 'analyze' ? 'analysis' : sourceFamily;
|
|
384
381
|
let receipts: readonly ArtifactReceipt[] = [];
|
|
385
382
|
try {
|
|
386
383
|
receipts = parseArtifactReceipts(content).rows;
|
|
387
384
|
} catch (error) {
|
|
388
385
|
return { error: error instanceof Error ? error.message : String(error) };
|
|
389
386
|
}
|
|
390
|
-
const
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return
|
|
397
|
-
})
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
387
|
+
const inventory = fs.readdirSync(taskDir).flatMap((name) => {
|
|
388
|
+
const identity = parseArtifactName(name);
|
|
389
|
+
if (!identity || !(ARTIFACT_FAMILIES as readonly string[]).includes(identity.family)) return [];
|
|
390
|
+
try {
|
|
391
|
+
const stat = fs.lstatSync(path.join(taskDir, name));
|
|
392
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return [];
|
|
393
|
+
return [{ family: identity.family, name, round: identity.round, sha256: sha256File(path.join(taskDir, name)) }];
|
|
394
|
+
} catch (error) {
|
|
395
|
+
throw new Error(`cannot inspect invalidation artifact '${name}': ${error instanceof Error ? error.message : String(error)}`);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
const taskQualification = parseTaskQualification(content);
|
|
399
|
+
if (!taskQualification.ok) return { error: taskQualification.message };
|
|
400
|
+
const nodeMap = new Map(inventory.map((node) => [`${node.family}/${node.name}`, node]));
|
|
401
|
+
const audits = new Map<string, QualificationAudit>();
|
|
402
|
+
let taskInputChanged = false;
|
|
403
|
+
let graphUsable = taskQualification.qualification.present;
|
|
404
|
+
if (graphUsable) {
|
|
405
|
+
for (const node of inventory) {
|
|
406
|
+
const artifactContent = fs.readFileSync(path.join(taskDir, node.name), 'utf8');
|
|
407
|
+
const parsedAudit = parseQualificationAudit(artifactContent);
|
|
408
|
+
if (!parsedAudit.ok || !parsedAudit.audit.present || !parsedAudit.audit.snapshot) { graphUsable = false; break; }
|
|
409
|
+
audits.set(`${node.family}/${node.name}`, parsedAudit.audit);
|
|
410
|
+
if (parsedAudit.audit.snapshot.taskInputDigest !== taskQualification.qualification.taskInputDigest) taskInputChanged = true;
|
|
411
|
+
if (parsedAudit.audit.snapshot.nonConstraintInputDigest !== taskQualification.qualification.nonConstraintInputDigest) {
|
|
412
|
+
graphUsable = false;
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
if (parsedAudit.audit.snapshot.upstreamArtifactDigest !== upstreamArtifactDigest(parsedAudit.audit.upstreamRelations)) {
|
|
416
|
+
graphUsable = false;
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
for (const relation of parsedAudit.audit.upstreamRelations) {
|
|
420
|
+
const upstream = nodeMap.get(`${relation.upstreamFamily}/${relation.upstreamArtifact}`);
|
|
421
|
+
if (!upstream || upstream.round !== relation.upstreamRound || upstream.sha256 !== relation.upstreamSha256) { graphUsable = false; break; }
|
|
422
|
+
}
|
|
423
|
+
if (!graphUsable) break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const selected = new Set<string>();
|
|
427
|
+
if (graphUsable) {
|
|
428
|
+
const changedConstraints = new Set<string>();
|
|
429
|
+
for (const audit of audits.values()) {
|
|
430
|
+
for (const dependency of audit.constraintDependencies) {
|
|
431
|
+
const current = taskQualification.qualification.constraints.find((row) => row.constraintId === dependency.constraintId);
|
|
432
|
+
if (!current || current.digest !== dependency.constraintDigest) changedConstraints.add(dependency.constraintId);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const currentCandidates = new Map(taskQualification.qualification.candidates.map((candidate) => [candidate.candidateId, candidate]));
|
|
436
|
+
const candidateSnapshotMatches = [...audits.values()].every((audit) => audit.candidateQualifications.length === currentCandidates.size && audit.candidateQualifications.every((row) => {
|
|
437
|
+
const current = currentCandidates.get(row.candidateId);
|
|
438
|
+
return Boolean(current && current.status === row.status && current.impact === row.impact
|
|
439
|
+
&& current.evidence === row.evidence && current.constraintIds.join(',') === row.constraintIds.join(','));
|
|
440
|
+
}));
|
|
441
|
+
// A task-input digest also covers candidates. A narrowed invalidation graph
|
|
442
|
+
// is safe only when the old audit rows show that the candidate projection
|
|
443
|
+
// stayed unchanged and the change is explained by at least one constraint.
|
|
444
|
+
if (taskInputChanged && (changedConstraints.size === 0 || !candidateSnapshotMatches)) graphUsable = false;
|
|
445
|
+
for (const node of inventory) {
|
|
446
|
+
const audit = audits.get(`${node.family}/${node.name}`)!;
|
|
447
|
+
if (audit.constraintDependencies.some((dependency) => changedConstraints.has(dependency.constraintId))) selected.add(`${node.family}/${node.name}`);
|
|
448
|
+
if (audit.upstreamRelations.some((relation) => relation.upstreamFamily === sourceArtifactFamily)) selected.add(`${node.family}/${node.name}`);
|
|
449
|
+
}
|
|
450
|
+
// Relation rows point from a consumer to its actual upstream artifact. Walk
|
|
451
|
+
// that reverse edge so review-only seeds and multi-hop consumers receive the
|
|
452
|
+
// same derived targets as ordinary executor seeds.
|
|
453
|
+
let changed = true;
|
|
454
|
+
while (changed) {
|
|
455
|
+
changed = false;
|
|
456
|
+
for (const node of inventory) {
|
|
457
|
+
const key = `${node.family}/${node.name}`;
|
|
458
|
+
const audit = audits.get(key)!;
|
|
459
|
+
if (audit.upstreamRelations.some((relation) => selected.has(`${relation.upstreamFamily}/${relation.upstreamArtifact}`)) && !selected.has(key)) {
|
|
460
|
+
selected.add(key);
|
|
461
|
+
changed = true;
|
|
417
462
|
}
|
|
418
|
-
return shapes.map((targetShape) => ({
|
|
419
|
-
...targetShape,
|
|
420
|
-
targetId: targetIdFor('pending', targetShape), operationId: 'pending', status: 'pending' as const,
|
|
421
|
-
reasonCode: 'upstream-replaced', updatedAt: timestamp
|
|
422
|
-
}));
|
|
423
|
-
} catch (error) {
|
|
424
|
-
throw new Error(`cannot inspect invalidation target '${name}': ${error instanceof Error ? error.message : String(error)}`);
|
|
425
463
|
}
|
|
426
|
-
}
|
|
464
|
+
}
|
|
465
|
+
// A relation cycle cannot establish a safe downstream closure.
|
|
466
|
+
const visiting = new Set<string>();
|
|
467
|
+
const visited = new Set<string>();
|
|
468
|
+
const hasCycle = (key: string): boolean => {
|
|
469
|
+
if (visiting.has(key)) return true;
|
|
470
|
+
if (visited.has(key)) return false;
|
|
471
|
+
visiting.add(key);
|
|
472
|
+
const cycle = audits.get(key)?.upstreamRelations.some((relation) => hasCycle(`${relation.upstreamFamily}/${relation.upstreamArtifact}`)) ?? false;
|
|
473
|
+
visiting.delete(key); visited.add(key);
|
|
474
|
+
return cycle;
|
|
475
|
+
};
|
|
476
|
+
if ([...nodeMap.keys()].some(hasCycle)) graphUsable = false;
|
|
477
|
+
}
|
|
478
|
+
const reasonCode = graphUsable ? 'qualification-changed' : 'upstream-replaced';
|
|
479
|
+
const targetNodes = (graphUsable
|
|
480
|
+
? inventory.filter((node) => selected.has(`${node.family}/${node.name}`))
|
|
481
|
+
: inventory.filter((node) => downstream[sourceFamily].includes(node.family)))
|
|
482
|
+
.filter((node) => !(node.family === FAMILY[family].artifact && node.name === artifact.name));
|
|
483
|
+
const targets = targetNodes.flatMap((node) => {
|
|
484
|
+
const shapes: Array<{ targetKind: InvalidationTargetKind; targetFamily: string; targetArtifact: string; targetRound: number; targetSha256: string }> = [
|
|
485
|
+
{ targetKind: 'artifact', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 }
|
|
486
|
+
];
|
|
487
|
+
const receipt = receipts.find((candidate) => candidate.output === node.name);
|
|
488
|
+
if (receipt) shapes.push({ targetKind: 'receipt', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: receipt.inputSha256 });
|
|
489
|
+
if (node.family.startsWith('review-')) shapes.push({ targetKind: 'approval', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 });
|
|
490
|
+
if (node.family === 'review-code') shapes.push({ targetKind: 'reviewed-snapshot', targetFamily: node.family, targetArtifact: node.name, targetRound: node.round, targetSha256: node.sha256 });
|
|
491
|
+
return shapes.map((targetShape) => ({ ...targetShape, targetId: targetIdFor('pending', targetShape), operationId: 'pending', status: 'pending' as const, reasonCode, updatedAt: timestamp }));
|
|
427
492
|
});
|
|
428
493
|
if (targets.length === 0) return { mutation: null };
|
|
429
494
|
const source = {
|
|
@@ -598,6 +663,30 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
|
|
|
598
663
|
const validated = validateCompletedArtifact(resolved.taskDir, FAMILY[eventIdentity.family].artifact, normalized.artifact!, normalized.round);
|
|
599
664
|
if (!validated.ok) return failed(normalized, validated.error, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
600
665
|
completedArtifact = validated.artifact;
|
|
666
|
+
if (eventIdentity.family.startsWith('review-')) {
|
|
667
|
+
let reviewContent: string;
|
|
668
|
+
try { reviewContent = fs.readFileSync(completedArtifact.path, 'utf8'); }
|
|
669
|
+
catch (error) {
|
|
670
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot read qualification audit from ${completedArtifact.name}: ${error instanceof Error ? error.message : String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
671
|
+
}
|
|
672
|
+
const schema = getArtifactSchema(eventIdentity.family);
|
|
673
|
+
const structure = schema ? inspectArtifactContract(reviewContent, schema) : null;
|
|
674
|
+
if (structure && !structure.ok) {
|
|
675
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `shared artifact structure invalid: ${structure.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
676
|
+
}
|
|
677
|
+
const expected = expectedQualificationRelations(content, eventIdentity.family as 'review-analysis' | 'review-plan' | 'review-code');
|
|
678
|
+
if (!expected.ok) {
|
|
679
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `${expected.code}: ${expected.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
680
|
+
}
|
|
681
|
+
const qualification = validateQualificationAudit(content, reviewContent, {
|
|
682
|
+
family: eventIdentity.family as 'review-analysis' | 'review-plan' | 'review-code',
|
|
683
|
+
artifact: completedArtifact.name,
|
|
684
|
+
expectedUpstreamRelations: expected.relations
|
|
685
|
+
});
|
|
686
|
+
if (!qualification.ok) {
|
|
687
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `${qualification.code}: ${qualification.message}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
688
|
+
}
|
|
689
|
+
}
|
|
601
690
|
if (eventIdentity.family === 'analyze' || eventIdentity.family === 'plan' || eventIdentity.family === 'code') {
|
|
602
691
|
const localFamily = eventIdentity.family === 'analyze'
|
|
603
692
|
? 'analysis'
|
|
@@ -607,11 +696,10 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
|
|
|
607
696
|
catch (error) {
|
|
608
697
|
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot read ${completedArtifact.name}: ${String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
|
|
609
698
|
}
|
|
610
|
-
const validationConfig = localArtifactValidationConfig(resolved.repoRoot, localFamily);
|
|
611
699
|
const local = validateLocalArtifact(artifactContent, {
|
|
612
700
|
family: localFamily,
|
|
613
|
-
|
|
614
|
-
|
|
701
|
+
taskContent: content,
|
|
702
|
+
artifact: completedArtifact.name
|
|
615
703
|
});
|
|
616
704
|
if (!local.ok) {
|
|
617
705
|
return failed(normalized, {
|
|
@@ -730,6 +818,13 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
|
|
|
730
818
|
const body = appendActivityEntry(section, { time: metadata.timestamp, step: logStep, agent: normalized.agent, note: eventIdentity.note });
|
|
731
819
|
const frontmatterSet: Record<string, string> = { current_step: step, assigned_to: normalized.agent };
|
|
732
820
|
let frontmatterRemove: string[] | undefined;
|
|
821
|
+
if (eventIdentity.phase === 'started' && artifactContext) {
|
|
822
|
+
try {
|
|
823
|
+
frontmatterSet.qualification_input_relations = JSON.stringify(qualificationRelationsForStarted(eventIdentity.family, artifactContext.inputs));
|
|
824
|
+
} catch (error) {
|
|
825
|
+
return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: `cannot capture qualification input relations: ${error instanceof Error ? error.message : String(error)}` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
|
|
826
|
+
}
|
|
827
|
+
}
|
|
733
828
|
if (eventIdentity.phase === 'started' && eventIdentity.family === 'code') {
|
|
734
829
|
const planInput = artifactContext?.inputs.find((input) => input.family === 'plan');
|
|
735
830
|
if (!planInput) return failed(normalized, { code: 'EVENT_ARTIFACT_CONFLICT', message: 'code.started plan input context is unavailable' }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
|
|
@@ -754,6 +849,7 @@ function applyTaskEventUnlocked(request: TaskEventRequest, options: TaskEventOpt
|
|
|
754
849
|
} else if (eventIdentity.phase === 'completed' && eventIdentity.family.startsWith('review-')) {
|
|
755
850
|
frontmatterRemove = ['review_input_artifact', 'review_input_sha256'];
|
|
756
851
|
}
|
|
852
|
+
if (eventIdentity.phase === 'completed') frontmatterRemove = [...(frontmatterRemove ?? []), 'qualification_input_relations'];
|
|
757
853
|
if (eventIdentity.phase === 'started' && normalized.implementationInput) frontmatterSet.last_reviewed_commit = '';
|
|
758
854
|
const mutations: Parameters<typeof writeTask>[0]['mutations'][number][] = [
|
|
759
855
|
{ kind: 'frontmatter', set: frontmatterSet, remove: frontmatterRemove }
|
package/lib/task/index.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PUBLIC_CLI_ROUTE_SELECTORS,
|
|
3
|
+
PUBLIC_CLI_SELECTOR_ALIASES
|
|
4
|
+
} from '../internal/cli-route-inventory.ts';
|
|
5
|
+
|
|
1
6
|
const USAGE = `Usage: ai task <command> [options]
|
|
2
7
|
|
|
3
8
|
Commands:
|
|
@@ -30,6 +35,7 @@ Examples:
|
|
|
30
35
|
ai task status --task 11
|
|
31
36
|
|
|
32
37
|
Run 'ai task <command> --help' for details.`;
|
|
38
|
+
const TASK_OPERATIONS = PUBLIC_CLI_ROUTE_SELECTORS.task;
|
|
33
39
|
|
|
34
40
|
export async function runTask(args: string[]): Promise<void> {
|
|
35
41
|
const [subcommand, ...rest] = args;
|
|
@@ -45,14 +51,21 @@ export async function runTask(args: string[]): Promise<void> {
|
|
|
45
51
|
return;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
|
|
54
|
+
const routeSelector: string = PUBLIC_CLI_SELECTOR_ALIASES.task[subcommand as keyof typeof PUBLIC_CLI_SELECTOR_ALIASES.task] ?? subcommand;
|
|
55
|
+
if (!TASK_OPERATIONS.includes(routeSelector as typeof TASK_OPERATIONS[number])) {
|
|
56
|
+
process.stderr.write(`Unknown task command: ${subcommand}\n\n`);
|
|
57
|
+
process.stdout.write(`${USAGE}\n`);
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
switch (routeSelector) {
|
|
49
63
|
case 'cat': {
|
|
50
64
|
const { cat } = await import('./commands/cat.ts');
|
|
51
65
|
cat(rest);
|
|
52
66
|
break;
|
|
53
67
|
}
|
|
54
|
-
case 'decisions':
|
|
55
|
-
case 'd': {
|
|
68
|
+
case 'decisions': {
|
|
56
69
|
const { decisions } = await import('./commands/decisions.ts');
|
|
57
70
|
decisions(rest);
|
|
58
71
|
break;
|