@fitlab-ai/agent-infra 0.12.1 → 0.12.2
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/README.md +0 -2
- package/README.zh-CN.md +0 -2
- package/dist/bin/internal-cli.js +2 -17
- package/dist/lib/agent-clients/adapter.js +0 -13
- package/dist/lib/agent-clients/adapters/antigravity-cli.js +0 -5
- package/dist/lib/agent-clients/adapters/claude-code-credentials.js +0 -17
- package/dist/lib/agent-clients/adapters/claude-code.js +0 -9
- package/dist/lib/agent-clients/adapters/codex.js +0 -52
- package/dist/lib/agent-clients/adapters/opencode.js +0 -5
- package/dist/lib/agent-clients/adapters/traecli.js +0 -5
- package/dist/lib/agent-clients/config.js +19 -54
- package/dist/lib/agent-clients/registry.js +1 -12
- package/dist/lib/agent-clients/schema.js +0 -18
- package/dist/lib/agent-clients/tokens.js +1 -2
- package/dist/lib/agent-clients/types.js +0 -1
- package/dist/lib/decide.js +2 -0
- package/dist/lib/git/worktree-identity.js +1 -9
- package/dist/lib/internal/agent-client.js +2 -62
- package/dist/lib/internal/cli-route-inventory.js +1 -5
- package/dist/lib/internal/manual-validation.js +18 -10
- package/dist/lib/internal/task-create.js +1 -1
- package/dist/lib/internal/task-event.js +1 -8
- package/dist/lib/internal/task-finalization.js +0 -1
- package/dist/lib/internal/task-lifecycle.js +2 -2
- package/dist/lib/internal/task-operation-registry.js +4 -20
- package/dist/lib/internal/task-review.js +4 -4
- package/dist/lib/platform/comment-safety.js +1 -7
- package/dist/lib/platform/in-label-sync.js +1 -14
- package/dist/lib/platform/issue-comments.js +1 -16
- package/dist/lib/platform/issues.js +1 -1
- package/dist/lib/platform/operation-coordinator.js +4 -2
- package/dist/lib/platform/pr-change-report.js +1 -4
- package/dist/lib/platform/pr-checks.js +2 -8
- package/dist/lib/platform/provider-validation.js +0 -20
- package/dist/lib/platform/pull-requests.js +73 -84
- package/dist/lib/platform/releases.js +1 -43
- package/dist/lib/platform/verification-required.js +0 -2
- package/dist/lib/platform/verification-sync.js +1 -79
- package/dist/lib/process-data/normalize.js +1 -185
- package/dist/lib/process-data/privacy.js +1 -16
- package/dist/lib/process-data/sources.js +2 -279
- package/dist/lib/render.js +0 -12
- package/dist/lib/run/index.js +15 -10
- package/dist/lib/run/skills.js +0 -3
- package/dist/lib/sandbox/commands/create.js +40 -53
- package/dist/lib/sandbox/commands/list-running.js +0 -18
- package/dist/lib/sandbox/commands/start.js +7 -8
- package/dist/lib/sandbox/constants.js +0 -6
- package/dist/lib/sandbox/control/client.js +0 -1
- package/dist/lib/sandbox/control/container-identity.js +1 -16
- package/dist/lib/sandbox/control/executor.js +0 -4
- package/dist/lib/sandbox/control/identity-sentinel.js +0 -7
- package/dist/lib/sandbox/control/lifecycle.js +21 -37
- package/dist/lib/sandbox/control/native-file-lock.js +0 -3
- package/dist/lib/sandbox/control/server.js +18 -38
- package/dist/lib/sandbox/control/state.js +1 -9
- package/dist/lib/sandbox/dockerfile.js +0 -6
- package/dist/lib/sandbox/engine.js +0 -14
- package/dist/lib/sandbox/engines/docker-exact-discovery.js +1 -4
- package/dist/lib/sandbox/engines/wsl2-paths.js +0 -3
- package/dist/lib/sandbox/recovery.js +24 -26
- package/dist/lib/sandbox/removal.js +11 -519
- package/dist/lib/sandbox/task-resolver.js +0 -41
- package/dist/lib/sandbox/tools.js +1 -4
- package/dist/lib/sandbox/workspace-view.js +1 -2
- package/dist/lib/server/display.js +0 -6
- package/dist/lib/task/activity-intent.js +45 -40
- package/dist/lib/task/activity-log.js +9 -16
- package/dist/lib/task/artifact-command.js +1 -1
- package/dist/lib/task/artifact-lifecycle.js +61 -63
- package/dist/lib/task/artifact-name.js +0 -6
- package/dist/lib/task/artifact-operations.js +3 -3
- package/dist/lib/task/capabilities.js +4 -5
- package/dist/lib/task/commands/log.js +0 -6
- package/dist/lib/task/commands/status.js +17 -60
- package/dist/lib/task/commit-operation.js +28 -39
- package/dist/lib/task/completion-facts.js +56 -43
- package/dist/lib/task/control-authority.js +23 -256
- package/dist/lib/task/control-recovery.js +3 -5
- package/dist/lib/task/create.js +2 -4
- package/dist/lib/task/decision-intents.js +8 -9
- package/dist/lib/task/delivery-target.js +1 -40
- package/dist/lib/task/events.js +84 -107
- package/dist/lib/task/finalization.js +44 -8
- package/dist/lib/task/ledger-intents.js +1 -1
- package/dist/lib/task/lifecycle-execution.js +38 -33
- package/dist/lib/task/lifecycle.js +49 -41
- package/dist/lib/task/local-artifact-finalization.js +1 -4
- package/dist/lib/task/manual-validation-evidence.js +1 -37
- package/dist/lib/task/platform-operation-recovery.js +67 -24
- package/dist/lib/task/pr-delivery-fact.js +2 -5
- package/dist/lib/task/qualification-confirmation.js +5 -7
- package/dist/lib/task/resolve-ref.js +1 -25
- package/dist/lib/task/review-command.js +2 -2
- package/dist/lib/task/review-finalization.js +1 -21
- package/dist/lib/task/review-fingerprint.js +0 -4
- package/dist/lib/task/secure-fs.js +0 -56
- package/dist/lib/task/short-id.js +1 -39
- package/dist/lib/task/skill-scope.js +0 -1
- package/dist/lib/task/verification-engine.js +58 -282
- package/dist/lib/task/verification.js +6 -3
- package/dist/lib/task/write.js +11 -1
- package/lib/agent-clients/adapter.ts +0 -76
- package/lib/agent-clients/adapters/antigravity-cli.ts +0 -5
- package/lib/agent-clients/adapters/claude-code-credentials.ts +0 -19
- package/lib/agent-clients/adapters/claude-code.ts +0 -9
- package/lib/agent-clients/adapters/codex.ts +0 -56
- package/lib/agent-clients/adapters/opencode.ts +0 -5
- package/lib/agent-clients/adapters/traecli.ts +0 -5
- package/lib/agent-clients/config.ts +20 -61
- package/lib/agent-clients/registry.ts +1 -34
- package/lib/agent-clients/schema.ts +0 -18
- package/lib/agent-clients/tokens.ts +1 -2
- package/lib/agent-clients/types.ts +0 -15
- package/lib/decide.ts +1 -0
- package/lib/git/worktree-identity.ts +0 -10
- package/lib/internal/agent-client.ts +2 -70
- package/lib/internal/cli-route-inventory.ts +1 -4
- package/lib/internal/manual-validation.ts +16 -9
- package/lib/internal/task-create.ts +0 -1
- package/lib/internal/task-event.ts +1 -5
- package/lib/internal/task-finalization.ts +0 -1
- package/lib/internal/task-lifecycle.ts +3 -5
- package/lib/internal/task-operation-registry.ts +3 -19
- package/lib/internal/task-review.ts +4 -4
- package/lib/platform/comment-safety.ts +0 -10
- package/lib/platform/github-provider.ts +0 -2
- package/lib/platform/in-label-sync.ts +0 -16
- package/lib/platform/issue-comments.ts +0 -21
- package/lib/platform/issues.ts +0 -2
- package/lib/platform/operation-coordinator.ts +4 -2
- package/lib/platform/pr-change-report.ts +0 -5
- package/lib/platform/pr-checks.ts +1 -10
- package/lib/platform/pr-review.ts +1 -1
- package/lib/platform/provider-bridge.ts +0 -1
- package/lib/platform/provider-loader.ts +1 -5
- package/lib/platform/provider-validation.ts +1 -49
- package/lib/platform/pull-requests.ts +64 -99
- package/lib/platform/releases.ts +1 -40
- package/lib/platform/verification-required.ts +0 -2
- package/lib/platform/verification-sync.ts +0 -94
- package/lib/process-data/normalize.ts +1 -186
- package/lib/process-data/privacy.ts +2 -19
- package/lib/process-data/sources.ts +3 -283
- package/lib/render.ts +0 -15
- package/lib/run/index.ts +13 -7
- package/lib/run/skills.ts +0 -4
- package/lib/sandbox/commands/create.ts +37 -74
- package/lib/sandbox/commands/list-running.ts +0 -19
- package/lib/sandbox/commands/start.ts +7 -10
- package/lib/sandbox/constants.ts +0 -8
- package/lib/sandbox/control/client.ts +0 -1
- package/lib/sandbox/control/container-identity.ts +1 -16
- package/lib/sandbox/control/executor.ts +1 -5
- package/lib/sandbox/control/identity-sentinel.ts +0 -8
- package/lib/sandbox/control/lifecycle.ts +18 -51
- package/lib/sandbox/control/native-file-lock.ts +0 -8
- package/lib/sandbox/control/protocol.ts +0 -2
- package/lib/sandbox/control/server.ts +13 -39
- package/lib/sandbox/control/state.ts +1 -10
- package/lib/sandbox/dockerfile.ts +0 -11
- package/lib/sandbox/engine.ts +0 -17
- package/lib/sandbox/engines/docker-exact-discovery.ts +1 -5
- package/lib/sandbox/engines/wsl2-paths.ts +0 -4
- package/lib/sandbox/recovery.ts +24 -26
- package/lib/sandbox/removal.ts +11 -696
- package/lib/sandbox/shell.ts +1 -1
- package/lib/sandbox/task-resolver.ts +0 -48
- package/lib/sandbox/tools.ts +1 -5
- package/lib/sandbox/workspace-view.ts +2 -4
- package/lib/server/display.ts +0 -14
- package/lib/server/process-control.ts +1 -1
- package/lib/task/activity-intent.ts +36 -44
- package/lib/task/activity-log.ts +9 -22
- package/lib/task/artifact-command.ts +1 -1
- package/lib/task/artifact-lifecycle.ts +58 -67
- package/lib/task/artifact-name.ts +0 -7
- package/lib/task/artifact-operations.ts +3 -3
- package/lib/task/capabilities.ts +5 -6
- package/lib/task/commands/log.ts +0 -7
- package/lib/task/commands/status.ts +14 -79
- package/lib/task/commit-operation.ts +29 -51
- package/lib/task/completion-facts.ts +45 -42
- package/lib/task/control-authority.ts +27 -317
- package/lib/task/control-recovery.ts +2 -5
- package/lib/task/create.ts +2 -5
- package/lib/task/decision-intents.ts +5 -5
- package/lib/task/delivery-target.ts +0 -40
- package/lib/task/events.ts +89 -123
- package/lib/task/finalization.ts +41 -9
- package/lib/task/ledger-intents.ts +1 -1
- package/lib/task/lifecycle-execution.ts +37 -89
- package/lib/task/lifecycle.ts +48 -44
- package/lib/task/local-artifact-finalization.ts +0 -7
- package/lib/task/manual-validation-evidence.ts +1 -47
- package/lib/task/platform-operation-recovery.ts +50 -26
- package/lib/task/pr-delivery-fact.ts +2 -11
- package/lib/task/qualification-confirmation.ts +6 -6
- package/lib/task/resolve-ref.ts +0 -23
- package/lib/task/review-command.ts +2 -2
- package/lib/task/review-finalization.ts +1 -27
- package/lib/task/review-fingerprint.ts +0 -8
- package/lib/task/secure-fs.ts +0 -42
- package/lib/task/short-id.ts +0 -43
- package/lib/task/skill-scope.ts +0 -1
- package/lib/task/verification-engine.ts +56 -287
- package/lib/task/verification.ts +5 -5
- package/lib/task/write.ts +12 -1
- package/package.json +2 -2
- package/templates/.agents/README.en.md +1 -3
- package/templates/.agents/README.zh-CN.md +0 -2
- package/templates/.agents/rules/README.en.md +0 -1
- package/templates/.agents/rules/README.zh-CN.md +0 -1
- package/templates/.agents/rules/commit-and-pr.en.md +1 -1
- package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -1
- package/templates/.agents/rules/no-mid-flow-questions.en.md +0 -10
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +0 -10
- package/templates/.agents/rules/pr-sync.en.md +1 -1
- package/templates/.agents/rules/pr-sync.zh-CN.md +1 -1
- package/templates/.agents/rules/task-management.en.md +3 -3
- package/templates/.agents/rules/task-management.zh-CN.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.en.md +3 -3
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/cancel-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/code-task/SKILL.zh-CN.md +4 -4
- package/templates/.agents/skills/commit/SKILL.en.md +2 -2
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/commit/reference/commit-orchestration.en.md +6 -6
- package/templates/.agents/skills/commit/reference/commit-orchestration.zh-CN.md +6 -6
- package/templates/.agents/skills/plan-task/SKILL.en.md +2 -2
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +2 -2
- package/templates/.agents/skills/review-analysis/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-code/SKILL.en.md +5 -5
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +5 -5
- package/templates/.agents/skills/review-plan/SKILL.en.md +3 -3
- package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +3 -3
- package/templates/.agents/skills/review-pr/SKILL.en.md +4 -4
- package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +4 -4
- 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/update-agent-infra/scripts/sync-templates.js +3 -75
- package/templates/.agents/templates/task.en.md +1 -0
- package/templates/.agents/templates/task.zh-CN.md +1 -0
- package/templates/.claude/settings.json +0 -24
- package/templates/.codex/hooks.json +0 -50
- package/dist/lib/agent-clients/adapters/codex-lifecycle/app-server.js +0 -582
- package/dist/lib/agent-clients/adapters/codex-lifecycle/binding.js +0 -114
- package/dist/lib/agent-clients/adapters/codex-lifecycle/build-identity.js +0 -237
- package/dist/lib/agent-clients/adapters/codex-lifecycle/cli.js +0 -443
- package/dist/lib/agent-clients/adapters/codex-lifecycle/evidence.js +0 -236
- package/dist/lib/agent-clients/adapters/codex-lifecycle/recovery.js +0 -292
- package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +0 -267
- package/dist/lib/agent-clients/adapters/codex-orchestration.js +0 -466
- package/dist/lib/internal/task-orchestration.js +0 -71
- package/dist/lib/platform/verification.js +0 -6
- package/dist/lib/run/prompt.js +0 -2
- package/dist/lib/sandbox/engines/authority.js +0 -289
- package/dist/lib/task/delegation-receipts.js +0 -410
- package/dist/lib/task/orchestration.js +0 -1233
- package/dist/lib/task/verification-checks.js +0 -9
- package/dist/lib/task/workspace-snapshot.js +0 -121
- package/dist/lifecycle-build-manifest.json +0 -6
- package/lib/agent-clients/adapters/codex-lifecycle/app-server.ts +0 -688
- package/lib/agent-clients/adapters/codex-lifecycle/binding.ts +0 -147
- package/lib/agent-clients/adapters/codex-lifecycle/build-identity.ts +0 -349
- package/lib/agent-clients/adapters/codex-lifecycle/cli.ts +0 -506
- package/lib/agent-clients/adapters/codex-lifecycle/evidence.ts +0 -385
- package/lib/agent-clients/adapters/codex-lifecycle/manifest-files.json +0 -41
- package/lib/agent-clients/adapters/codex-lifecycle/recovery.ts +0 -418
- package/lib/agent-clients/adapters/codex-lifecycle/store.ts +0 -354
- package/lib/agent-clients/adapters/codex-orchestration.ts +0 -630
- package/lib/internal/task-orchestration.ts +0 -74
- package/lib/platform/verification.ts +0 -11
- package/lib/run/prompt.ts +0 -1
- package/lib/sandbox/engines/authority.ts +0 -365
- package/lib/task/delegation-receipts.ts +0 -547
- package/lib/task/orchestration.ts +0 -1651
- package/lib/task/verification-checks.ts +0 -10
- package/lib/task/workspace-snapshot.ts +0 -144
- package/templates/.agents/hooks/lifecycle-delegation.js +0 -140
- package/templates/.agents/rules/lifecycle-orchestration.en.md +0 -44
- package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +0 -44
- package/templates/.agents/skills/run-task/SKILL.en.md +0 -29
- package/templates/.agents/skills/run-task/SKILL.zh-CN.md +0 -29
- package/templates/.agents/skills/run-task/config/verify.en.json +0 -10
- package/templates/.agents/skills/run-task/config/verify.zh-CN.json +0 -10
- package/templates/.agents/skills/run-task/reference/host-validation.en.md +0 -24
- package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +0 -24
- package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +0 -6
- package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +0 -6
- package/templates/.claude/commands/run-task.en.md +0 -8
- package/templates/.claude/commands/run-task.zh-CN.md +0 -8
- package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +0 -3
- package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +0 -3
- package/templates/.opencode/commands/run-task.en.md +0 -11
- package/templates/.opencode/commands/run-task.zh-CN.md +0 -11
|
@@ -124,7 +124,7 @@ function diagnostic(
|
|
|
124
124
|
return { code, message, sectionId, line };
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
function sectionHeadings(
|
|
127
|
+
function sectionHeadings(section: ArtifactSection): readonly string[] {
|
|
128
128
|
return [section.headings.zh, section.headings.en];
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -152,7 +152,7 @@ function inspectArtifactStructure(
|
|
|
152
152
|
|
|
153
153
|
const headingsBySection = new Map<string, typeof scanned.headings>();
|
|
154
154
|
for (const section of schema.sections) {
|
|
155
|
-
const aliases = sectionHeadings(
|
|
155
|
+
const aliases = sectionHeadings(section);
|
|
156
156
|
const exact = scanned.headings.filter((heading) => heading.level === 2 && aliases.includes(heading.text));
|
|
157
157
|
const punctuated = scanned.headings.filter((heading) => heading.level === 2 && aliases.some((alias) => heading.text === `${alias}:` || heading.text === `${alias}:`));
|
|
158
158
|
headingsBySection.set(section.id, exact.length > 0 ? exact : punctuated);
|
|
@@ -283,7 +283,7 @@ function inspectArtifactStateCheck(
|
|
|
283
283
|
|
|
284
284
|
const scanned = scanVisibleMarkdown(content);
|
|
285
285
|
const headings = scanned.headings.filter((heading) => (
|
|
286
|
-
heading.level === 2 && sectionHeadings(
|
|
286
|
+
heading.level === 2 && sectionHeadings(stateCheck).includes(heading.text)
|
|
287
287
|
));
|
|
288
288
|
if (headings.length !== 1) {
|
|
289
289
|
return { ok: true, family: schema.family, semanticDigest: canonicalSemanticDigest(content), diagnostics: [] };
|
package/lib/task/capabilities.ts
CHANGED
|
@@ -9,13 +9,13 @@ import { parseReviewSummary, resolveCanonicalVerdict } from './review-artifacts.
|
|
|
9
9
|
import { parseReworkIntentDocument } from './rework-intent.ts';
|
|
10
10
|
import type { ReworkIntent, ReworkTarget } from './rework-intent.ts';
|
|
11
11
|
import { sha256File } from './artifact-receipts.ts';
|
|
12
|
-
import {
|
|
12
|
+
import { lifecycleExecutions } from './lifecycle-execution.ts';
|
|
13
13
|
import { parseQualificationAudit, parseTaskQualification } from './qualification-audit.ts';
|
|
14
14
|
import type { QualificationAudit, TaskQualification } from './qualification-audit.ts';
|
|
15
15
|
import { parseLifecyclePathDecision, pathIncludes } from './lifecycle-path.ts';
|
|
16
16
|
import type { LifecyclePathState } from './lifecycle-path.ts';
|
|
17
17
|
import { parseImplementationInputs } from './implementation-inputs.ts';
|
|
18
|
-
import {
|
|
18
|
+
import { hasValidArtifactCompletion } from './completion-facts.ts';
|
|
19
19
|
import { inspectReviewIdentity } from './review-identity.ts';
|
|
20
20
|
import { inspectArtifactDirectory } from './artifact-lifecycle.ts';
|
|
21
21
|
import { executionInputsMatchLatest as executionReceiptsMatchLatest } from './execution-inputs.ts';
|
|
@@ -25,7 +25,7 @@ const ARTIFACT_AUDIT_FAMILIES = new Set(['analysis', 'review-analysis', 'plan',
|
|
|
25
25
|
type LifecycleAction =
|
|
26
26
|
| 'analysis' | 'review-analysis' | 'plan' | 'review-plan'
|
|
27
27
|
| 'code' | 'review-code' | 'manual-validation' | 'validation-run';
|
|
28
|
-
type TriggerInitiator = 'human' | 'model'
|
|
28
|
+
type TriggerInitiator = 'human' | 'model';
|
|
29
29
|
type TriggerReason = 'user-request' | 'new-requirement' | 'upstream-fact-doubt' | 'review-finding' | 'manual-review-supplement' | 'retry' | 'validation-rerun';
|
|
30
30
|
type ExplicitTrigger = {
|
|
31
31
|
initiator: TriggerInitiator;
|
|
@@ -395,8 +395,7 @@ function buildLifecycleFacts(taskDir: string, content: string, taskState = 'acti
|
|
|
395
395
|
if (family === 'review-code') {
|
|
396
396
|
const identity = inspectReviewIdentity(taskDir, reviewContent, repositoryRoot);
|
|
397
397
|
reviewCodeIdentityValid = identity.status === 'matched'
|
|
398
|
-
&&
|
|
399
|
-
&& hasArtifactCompletionLog(content, latest, 'review-code.completed');
|
|
398
|
+
&& hasValidArtifactCompletion(content, taskDir, latest, 'review-code.completed');
|
|
400
399
|
}
|
|
401
400
|
const parsed = parseReviewSummary(reviewContent);
|
|
402
401
|
if (!parsed.ok) continue;
|
|
@@ -455,7 +454,7 @@ function buildLifecycleFacts(taskDir: string, content: string, taskState = 'acti
|
|
|
455
454
|
reviewedInputs, executionInputs, artifactHashes,
|
|
456
455
|
reworkIntents: rework.intents,
|
|
457
456
|
unresolvedLedger,
|
|
458
|
-
executionBusy:
|
|
457
|
+
executionBusy: lifecycleExecutions(content).some((item) => item.family !== 'other') || executionBusy,
|
|
459
458
|
recommendedAction: null,
|
|
460
459
|
qualificationStale: qualificationStaleArtifacts.length > 0,
|
|
461
460
|
qualificationStaleArtifacts
|
package/lib/task/commands/log.ts
CHANGED
|
@@ -91,13 +91,6 @@ function isHumanCountField(field: string): boolean {
|
|
|
91
91
|
return fieldNumber(field, 'manual-validation') !== undefined || fieldNumber(field, 'human-decision') !== undefined;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
// A step is human-executed when its agent token is not a known AI token.
|
|
95
|
-
// Known long names classify as AI; empty or unknown tokens classify as non-AI
|
|
96
|
-
// (human).
|
|
97
|
-
export function isHumanAgent(agent: string): boolean {
|
|
98
|
-
return classifyAgent(agent).status !== 'ai';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
94
|
// Fold the two human counts into a review row's verdict NOTE: comma-joined, right
|
|
102
95
|
// after the blockers/major/minor list and before the ` → artifact` link, mirroring
|
|
103
96
|
// the review count line. Review done notes already carry `Manual-validation` as a
|
|
@@ -9,8 +9,8 @@ import { parseTaskFrontmatter, extractTitle, type Frontmatter } from '../frontma
|
|
|
9
9
|
import { loadShortIdByTaskId } from '../short-id.ts';
|
|
10
10
|
import { getOpenWorkflowWarnings, formatWorkflowWarningSummary, type WorkflowWarning } from '../workflow-warnings.ts';
|
|
11
11
|
import { parseActivityLog, pairEntries, startedBackedRows } from '../activity-log.ts';
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
12
|
+
import { lifecycleExecutions } from '../lifecycle-execution.ts';
|
|
13
|
+
import { parseTypedTaskFrontmatter } from '../frontmatter.ts';
|
|
14
14
|
import { statusCard, type DisplayMessage } from '../../server/display.ts';
|
|
15
15
|
import { buildLifecycleFacts, recommendNext } from '../capabilities.ts';
|
|
16
16
|
|
|
@@ -181,6 +181,15 @@ function parseActivityTime(value: string): number {
|
|
|
181
181
|
return Number.isFinite(epoch) ? epoch : Number.NaN;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
function collectStructuredWorkflow(content: string, now: Date): WorkflowInfo {
|
|
185
|
+
try {
|
|
186
|
+
const current = lifecycleExecutions(content).filter((row) => row.family !== 'other').at(-1);
|
|
187
|
+
if (!current) return { state: 'idle', step: DASH, agent: DASH, startedAt: DASH, doneAt: DASH, stale: DASH };
|
|
188
|
+
const started = parseActivityTime(current.startedAt);
|
|
189
|
+
return { state: 'in-progress', step: current.family, agent: current.agent, startedAt: current.startedAt, doneAt: DASH, stale: Number.isFinite(started) ? (now.getTime() - started > STALE_MS ? 'yes' : 'no') : 'unknown' };
|
|
190
|
+
} catch { return { state: 'unknown', step: DASH, agent: DASH, startedAt: DASH, doneAt: DASH, stale: DASH }; }
|
|
191
|
+
}
|
|
192
|
+
|
|
184
193
|
function collectWorkflow(content: string, now: Date = new Date()): WorkflowInfo {
|
|
185
194
|
const parsed = parseActivityLog(content);
|
|
186
195
|
if (!parsed.sectionFound || parsed.entries.length === 0) {
|
|
@@ -222,19 +231,6 @@ type RuntimeInfo = {
|
|
|
222
231
|
log: string;
|
|
223
232
|
};
|
|
224
233
|
|
|
225
|
-
type PendingDelegationInfo = Readonly<Pick<
|
|
226
|
-
DelegationReceipt,
|
|
227
|
-
'id' | 'role' | 'stage' | 'round' | 'artifact' | 'client' | 'status'
|
|
228
|
-
>>;
|
|
229
|
-
|
|
230
|
-
type OrchestrationInfo = Readonly<{
|
|
231
|
-
status: 'absent' | OrchestrationRun['status'];
|
|
232
|
-
runId: string;
|
|
233
|
-
nextStage: string;
|
|
234
|
-
pause: Readonly<{ code: string; message: string; recoverable: boolean }> | null;
|
|
235
|
-
pendingDelegation: PendingDelegationInfo | null;
|
|
236
|
-
}>;
|
|
237
|
-
|
|
238
234
|
type ManagedRunRecord = {
|
|
239
235
|
run_id: string;
|
|
240
236
|
engine: string;
|
|
@@ -339,39 +335,6 @@ function collectRuntime(taskDir: string, workflow: WorkflowInfo, run: Runner): R
|
|
|
339
335
|
};
|
|
340
336
|
}
|
|
341
337
|
|
|
342
|
-
function pendingDelegationInfo(receipt: DelegationReceipt | null): PendingDelegationInfo | null {
|
|
343
|
-
if (!receipt) return null;
|
|
344
|
-
return {
|
|
345
|
-
id: receipt.id,
|
|
346
|
-
role: receipt.role,
|
|
347
|
-
stage: receipt.stage,
|
|
348
|
-
round: receipt.round,
|
|
349
|
-
artifact: receipt.artifact,
|
|
350
|
-
client: receipt.client,
|
|
351
|
-
status: receipt.status
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
function collectOrchestration(taskDir: string): OrchestrationInfo {
|
|
356
|
-
const run = readRun(taskDir);
|
|
357
|
-
if (!run) {
|
|
358
|
-
return {
|
|
359
|
-
status: 'absent',
|
|
360
|
-
runId: DASH,
|
|
361
|
-
nextStage: DASH,
|
|
362
|
-
pause: null,
|
|
363
|
-
pendingDelegation: null
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
return {
|
|
367
|
-
status: run.status,
|
|
368
|
-
runId: run.runId,
|
|
369
|
-
nextStage: run.nextStage ?? DASH,
|
|
370
|
-
pause: run.pause,
|
|
371
|
-
pendingDelegation: pendingDelegationInfo(run.pendingDelegation)
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
|
|
375
338
|
type StatusModel = {
|
|
376
339
|
taskId: string;
|
|
377
340
|
shortId: string;
|
|
@@ -381,7 +344,6 @@ type StatusModel = {
|
|
|
381
344
|
artifacts: { count: number; groups: { stage: string; files: string[] }[] };
|
|
382
345
|
workflow: WorkflowInfo;
|
|
383
346
|
runtime: RuntimeInfo;
|
|
384
|
-
orchestration: OrchestrationInfo;
|
|
385
347
|
recommendation?: string;
|
|
386
348
|
recommendationReason?: string;
|
|
387
349
|
lifecyclePath?: string;
|
|
@@ -439,26 +401,6 @@ function renderStatus(model: StatusModel): string[] {
|
|
|
439
401
|
['reason', model.recommendationReason ?? DASH]
|
|
440
402
|
]));
|
|
441
403
|
|
|
442
|
-
lines.push(
|
|
443
|
-
'',
|
|
444
|
-
'Orchestration',
|
|
445
|
-
...renderPairs([
|
|
446
|
-
['status', model.orchestration.status],
|
|
447
|
-
['run_id', model.orchestration.runId],
|
|
448
|
-
['next_stage', model.orchestration.nextStage],
|
|
449
|
-
['pause_code', model.orchestration.pause?.code ?? DASH],
|
|
450
|
-
['pause_message', model.orchestration.pause?.message ?? DASH],
|
|
451
|
-
['recoverable', model.orchestration.pause ? String(model.orchestration.pause.recoverable) : DASH],
|
|
452
|
-
['pending_id', model.orchestration.pendingDelegation?.id ?? DASH],
|
|
453
|
-
['pending_role', model.orchestration.pendingDelegation?.role ?? DASH],
|
|
454
|
-
['pending_stage', model.orchestration.pendingDelegation?.stage ?? DASH],
|
|
455
|
-
['pending_round', model.orchestration.pendingDelegation ? String(model.orchestration.pendingDelegation.round) : DASH],
|
|
456
|
-
['pending_artifact', model.orchestration.pendingDelegation?.artifact ?? DASH],
|
|
457
|
-
['pending_client', model.orchestration.pendingDelegation?.client ?? DASH],
|
|
458
|
-
['pending_status', model.orchestration.pendingDelegation?.status ?? DASH]
|
|
459
|
-
])
|
|
460
|
-
);
|
|
461
|
-
|
|
462
404
|
lines.push(
|
|
463
405
|
'',
|
|
464
406
|
'Workflow',
|
|
@@ -504,9 +446,6 @@ function renderStatus(model: StatusModel): string[] {
|
|
|
504
446
|
}
|
|
505
447
|
|
|
506
448
|
function modelTone(model: StatusModel): 'info' | 'success' | 'warning' | 'danger' | 'running' {
|
|
507
|
-
if (model.orchestration.status === 'paused') return 'warning';
|
|
508
|
-
if (model.orchestration.status === 'running') return 'running';
|
|
509
|
-
if (model.orchestration.status === 'completed') return 'success';
|
|
510
449
|
if (model.workflow.state === 'in-progress') return model.workflow.stale === 'yes' ? 'warning' : 'running';
|
|
511
450
|
if (model.metadata.some(([key, value]) => key === 'status' && value === 'completed')) return 'success';
|
|
512
451
|
if (model.metadata.some(([key, value]) => key === 'status' && (value === 'blocked' || value === 'cancelled'))) {
|
|
@@ -520,7 +459,8 @@ function buildFromResolved(input: BuildStatusModelInput): StatusModel {
|
|
|
520
459
|
const fm = parseTaskFrontmatter(content);
|
|
521
460
|
const run = input.run ?? makeRunner(input.repoRoot);
|
|
522
461
|
const artifacts = enumerateArtifacts(input.taskDir);
|
|
523
|
-
const workflow =
|
|
462
|
+
const workflow = parseTypedTaskFrontmatter(content).lifecycle_execution !== undefined
|
|
463
|
+
? collectStructuredWorkflow(content, input.now ?? new Date()) : collectWorkflow(content, input.now);
|
|
524
464
|
const facts = buildLifecycleFacts(input.taskDir, content, fm.status ?? 'active', false, input.repoRoot);
|
|
525
465
|
const next = facts.ok ? recommendNext(facts.facts) : null;
|
|
526
466
|
const recommendation = next?.action ?? DASH;
|
|
@@ -534,7 +474,6 @@ function buildFromResolved(input: BuildStatusModelInput): StatusModel {
|
|
|
534
474
|
artifacts: { count: artifacts.length, groups: groupArtifacts(artifacts) },
|
|
535
475
|
workflow,
|
|
536
476
|
runtime: collectRuntime(input.taskDir, workflow, run),
|
|
537
|
-
orchestration: collectOrchestration(input.taskDir),
|
|
538
477
|
recommendation,
|
|
539
478
|
recommendationReason: next?.reasonCode ?? 'TASK_CAPABILITY_FACTS_INVALID',
|
|
540
479
|
lifecyclePath: facts.ok && facts.facts.pathState?.status === 'valid' ? facts.facts.pathState.decision.path : facts.ok ? facts.facts.pathState?.status ?? DASH : DASH,
|
|
@@ -572,9 +511,6 @@ function statusModelToDisplay(model: StatusModel): DisplayMessage {
|
|
|
572
511
|
`Task ${model.taskId} (${model.shortId})`,
|
|
573
512
|
modelTone(model),
|
|
574
513
|
[
|
|
575
|
-
['orchestration', model.orchestration.status],
|
|
576
|
-
['run', model.orchestration.runId],
|
|
577
|
-
['next', model.orchestration.nextStage],
|
|
578
514
|
['workflow', model.workflow.state],
|
|
579
515
|
['step', model.workflow.step],
|
|
580
516
|
['runtime', model.runtime.status],
|
|
@@ -622,9 +558,8 @@ export {
|
|
|
622
558
|
collectGit,
|
|
623
559
|
collectWorkflow,
|
|
624
560
|
collectRuntime,
|
|
625
|
-
collectOrchestration,
|
|
626
561
|
renderStatus,
|
|
627
562
|
statusModelToDisplay,
|
|
628
563
|
METADATA_KEYS
|
|
629
564
|
};
|
|
630
|
-
export type { Runner, GitInfo, WorkflowInfo, RuntimeInfo,
|
|
565
|
+
export type { Runner, GitInfo, WorkflowInfo, RuntimeInfo, StatusModel, BuildStatusModelInput };
|
|
@@ -8,9 +8,9 @@ import { checkpointCommitMatches } from './commit-identity.ts';
|
|
|
8
8
|
import { resolveTaskContext, resolveTaskRef } from './resolve-ref.ts';
|
|
9
9
|
import { commitPushDecision } from './commit-policy.ts';
|
|
10
10
|
import { mergeOperationWarnings, type OperationWarning } from './operation-outcome.ts';
|
|
11
|
-
import { appendActivityEntry, locateActivityLog } from './activity-log.ts';
|
|
11
|
+
import { activityWarnings, appendActivityEntry, locateActivityLog } from './activity-log.ts';
|
|
12
12
|
import { captureTaskWriteMetadata, writeTask } from './write.ts';
|
|
13
|
-
import type { TaskMutation } from './write.ts';
|
|
13
|
+
import type { TaskMutation, TaskWriteOptions } from './write.ts';
|
|
14
14
|
import {
|
|
15
15
|
checkpointIntentDigest,
|
|
16
16
|
readCheckpointIntent,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
writeCheckpointIntent
|
|
21
21
|
} from './commit-intent.ts';
|
|
22
22
|
|
|
23
|
-
type CommitExecutionMode = 'direct'
|
|
23
|
+
type CommitExecutionMode = 'direct';
|
|
24
24
|
|
|
25
25
|
type CommitOperationInput = Readonly<{
|
|
26
26
|
cwd: string;
|
|
@@ -68,7 +68,7 @@ const HEAD_REF = /^refs\/heads\/(.+)$/;
|
|
|
68
68
|
type CommitDelivery = Readonly<{ mode: 'local' } | { mode: 'push'; remote: string; refs: readonly string[] }>;
|
|
69
69
|
|
|
70
70
|
function isCommitExecutionMode(value: unknown): value is CommitExecutionMode {
|
|
71
|
-
return value === 'direct'
|
|
71
|
+
return value === 'direct';
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
function gitText(repoRoot: string, args: readonly string[]): string {
|
|
@@ -193,55 +193,42 @@ function validateCommon(input: CommitOperationInput, branch: string | null): Rea
|
|
|
193
193
|
return null;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// Log presentation only; checkpoint identity and recovery never depend on this projection.
|
|
197
|
+
function commitLogProjection(activity: ReturnType<typeof locateActivityLog>, timestamp: string, agent: string, commitNote: string): TaskMutation[] {
|
|
198
|
+
if (!activity) return [];
|
|
199
|
+
let lastCommit = -1;
|
|
200
|
+
for (const [index, entry] of activity.entries.entries()) {
|
|
201
|
+
if (entry.step === 'Commit' && entry.note === commitNote) lastCommit = index;
|
|
202
|
+
}
|
|
203
|
+
const reviewedAfter = activity.entries.slice(lastCommit + 1).some((entry) => /^Review Code \(Round \d+\)$/.test(entry.step));
|
|
204
|
+
if (lastCommit >= 0 && !reviewedAfter) return [];
|
|
205
|
+
return [{ kind: 'section', aliases: ['活动日志', 'Activity Log'], heading: activity.heading,
|
|
206
|
+
body: appendActivityEntry(activity, { time: timestamp, step: 'Commit', agent, note: commitNote }) }];
|
|
207
|
+
}
|
|
208
|
+
|
|
196
209
|
function syncTaskCommit(
|
|
197
210
|
input: CommitOperationInput,
|
|
198
211
|
task: BoundTask,
|
|
199
|
-
committedHead: string
|
|
212
|
+
committedHead: string,
|
|
213
|
+
writeOptions: TaskWriteOptions = {}
|
|
200
214
|
): OperationWarning | null {
|
|
201
215
|
let content: string;
|
|
202
216
|
try {
|
|
203
217
|
content = fs.readFileSync(task.taskMdPath, 'utf8');
|
|
204
218
|
const activity = locateActivityLog(content);
|
|
205
|
-
if (!activity) return warning(
|
|
206
|
-
'TASK_STATUS_SYNC_FAILED',
|
|
207
|
-
'task has no unique Activity Log section',
|
|
208
|
-
true,
|
|
209
|
-
'task',
|
|
210
|
-
task.taskId,
|
|
211
|
-
'ACTION_REQUIRED'
|
|
212
|
-
);
|
|
213
219
|
const metadata = captureTaskWriteMetadata();
|
|
214
220
|
const commitNote = gitText(task.repoRoot, ['show', '-s', '--format=%h %s', committedHead]);
|
|
215
|
-
|
|
216
|
-
for (let index = activity.entries.length - 1; index >= 0; index -= 1) {
|
|
217
|
-
const entry = activity.entries[index]!;
|
|
218
|
-
if (entry.step === 'Commit' && entry.note === commitNote) {
|
|
219
|
-
matchingCommitIndex = index;
|
|
220
|
-
break;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
const reviewedAfterCommit = matchingCommitIndex >= 0 && activity.entries
|
|
224
|
-
.slice(matchingCommitIndex + 1)
|
|
225
|
-
.some((entry) => /^Review Code \(Round \d+\)$/.test(entry.step));
|
|
226
|
-
const alreadyLogged = matchingCommitIndex >= 0 && !reviewedAfterCommit;
|
|
227
|
-
const mutations: TaskMutation[] = [];
|
|
228
|
-
if (!alreadyLogged) mutations.push({
|
|
229
|
-
kind: 'section',
|
|
230
|
-
aliases: ['活动日志', 'Activity Log'],
|
|
231
|
-
heading: activity.heading,
|
|
232
|
-
body: appendActivityEntry(activity, { time: metadata.timestamp, step: 'Commit', agent: input.agent!, note: commitNote })
|
|
233
|
-
});
|
|
221
|
+
const mutations = commitLogProjection(activity, metadata.timestamp, input.agent!, commitNote);
|
|
234
222
|
const frontmatter: Record<string, string> = {
|
|
235
223
|
assigned_to: input.agent!,
|
|
236
224
|
checkpoint_commit: committedHead
|
|
237
225
|
};
|
|
238
226
|
mutations.push({ kind: 'frontmatter', set: frontmatter });
|
|
239
|
-
if (mutations.length === 0) return null;
|
|
240
227
|
const written = writeTask({
|
|
241
228
|
taskRef: task.taskId,
|
|
242
229
|
expectedState: 'active',
|
|
243
230
|
mutations
|
|
244
|
-
}, { repoRoot: task.repoRoot, metadataProvider: () => metadata });
|
|
231
|
+
}, { ...writeOptions, repoRoot: task.repoRoot, metadataProvider: () => metadata });
|
|
245
232
|
if (written.status === 'failed') return warning(
|
|
246
233
|
'TASK_STATUS_SYNC_FAILED',
|
|
247
234
|
written.error.message,
|
|
@@ -250,7 +237,8 @@ function syncTaskCommit(
|
|
|
250
237
|
task.taskId,
|
|
251
238
|
'ACTION_REQUIRED'
|
|
252
239
|
);
|
|
253
|
-
|
|
240
|
+
const logWarning = activityWarnings(content)[0];
|
|
241
|
+
return logWarning ? warning(logWarning.code, logWarning.message, true, 'task', task.taskId, 'IMPORTANT') : null;
|
|
254
242
|
} catch (error) {
|
|
255
243
|
return warning(
|
|
256
244
|
'TASK_STATUS_SYNC_FAILED',
|
|
@@ -281,18 +269,9 @@ function checkpointTimestamp(): string {
|
|
|
281
269
|
return new Date().toISOString();
|
|
282
270
|
}
|
|
283
271
|
|
|
284
|
-
function executeCommitOperationCore(input: CommitOperationInput, task: BoundTask | null, mode: CommitExecutionMode): CommitOperationResult {
|
|
272
|
+
function executeCommitOperationCore(input: CommitOperationInput, task: BoundTask | null, mode: CommitExecutionMode, writeOptions: TaskWriteOptions): CommitOperationResult {
|
|
285
273
|
const inspected = inspectGitWorkflow(input.cwd);
|
|
286
274
|
if (!inspected.snapshot) return failure(input, mode, task?.taskId ?? null, 'GIT_INSPECT_FAILED', 'Unable to inspect Git repository');
|
|
287
|
-
if (mode === 'orchestrated') return failure(
|
|
288
|
-
input,
|
|
289
|
-
mode,
|
|
290
|
-
task?.taskId ?? null,
|
|
291
|
-
'ORCHESTRATED_COMMIT_REMOVED',
|
|
292
|
-
'Orchestrated commit is no longer a lifecycle stage; use local checkpoint delivery from code-task',
|
|
293
|
-
'blocked',
|
|
294
|
-
inspected.snapshot
|
|
295
|
-
);
|
|
296
275
|
const branch = inspected.snapshot.branch;
|
|
297
276
|
const commonError = validateCommon(input, branch);
|
|
298
277
|
if (commonError) return failure(input, mode, task?.taskId ?? null, commonError.code, commonError.message, 'blocked', inspected.snapshot);
|
|
@@ -466,13 +445,13 @@ function executeCommitOperationCore(input: CommitOperationInput, task: BoundTask
|
|
|
466
445
|
}
|
|
467
446
|
if (task && (committed.status === 'applied' || committed.status === 'no-op')) {
|
|
468
447
|
const committedHead = checkpointCommittedHead ?? committed.snapshot?.head ?? gitText(task.repoRoot, ['rev-parse', 'HEAD']);
|
|
469
|
-
const taskWarning = syncTaskCommit(input, task, committedHead);
|
|
448
|
+
const taskWarning = syncTaskCommit(input, task, committedHead, writeOptions);
|
|
470
449
|
if (taskWarning) {
|
|
471
450
|
warnings.push(taskWarning);
|
|
472
451
|
status = 'applied';
|
|
473
452
|
result = 'committed_with_warnings';
|
|
474
453
|
}
|
|
475
|
-
if (delivery.mode === 'local' &&
|
|
454
|
+
if (delivery.mode === 'local' && taskWarning?.code !== 'TASK_STATUS_SYNC_FAILED' && pendingIntent && checkpointCommittedHead) {
|
|
476
455
|
const synced = updateCheckpointIntent(pendingIntent, {
|
|
477
456
|
state: 'synced', committedHead: checkpointCommittedHead, updatedAt: checkpointTimestamp()
|
|
478
457
|
});
|
|
@@ -493,7 +472,7 @@ function executeCommitOperationCore(input: CommitOperationInput, task: BoundTask
|
|
|
493
472
|
};
|
|
494
473
|
}
|
|
495
474
|
|
|
496
|
-
function executeCommitOperation(input: CommitOperationInput): CommitOperationResult {
|
|
475
|
+
function executeCommitOperation(input: CommitOperationInput, writeOptions: TaskWriteOptions = {}): CommitOperationResult {
|
|
497
476
|
if (input.mode !== undefined && !isCommitExecutionMode(input.mode)) return {
|
|
498
477
|
status: 'blocked',
|
|
499
478
|
changed: false,
|
|
@@ -503,7 +482,7 @@ function executeCommitOperation(input: CommitOperationInput): CommitOperationRes
|
|
|
503
482
|
warnings: [],
|
|
504
483
|
snapshot: null,
|
|
505
484
|
operations: [],
|
|
506
|
-
error: { code: 'COMMIT_MODE_INVALID', message: 'commit mode must be direct
|
|
485
|
+
error: { code: 'COMMIT_MODE_INVALID', message: 'commit mode must be direct' }
|
|
507
486
|
};
|
|
508
487
|
const mode: CommitExecutionMode = input.mode ?? 'direct';
|
|
509
488
|
let normalizedInput: CommitOperationInput;
|
|
@@ -515,9 +494,8 @@ function executeCommitOperation(input: CommitOperationInput): CommitOperationRes
|
|
|
515
494
|
const resolved = resolveBoundTask(normalizedInput);
|
|
516
495
|
if (resolved.kind === 'error') return resolved.result;
|
|
517
496
|
const task = resolved.kind === 'bound' ? resolved.task : null;
|
|
518
|
-
if (mode === 'orchestrated' && !task) return failure(normalizedInput, mode, null, 'ORCHESTRATION_TASK_REQUIRED', 'orchestrated commit requires a task context', 'blocked');
|
|
519
497
|
try {
|
|
520
|
-
return executeCommitOperationCore(normalizedInput, task, mode);
|
|
498
|
+
return executeCommitOperationCore(normalizedInput, task, mode, writeOptions);
|
|
521
499
|
} catch (error) {
|
|
522
500
|
const code = 'COMMIT_OPERATION_FAILED';
|
|
523
501
|
return failure(normalizedInput, mode, task?.taskId ?? null, code, error instanceof Error ? error.message : String(error), 'blocked');
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
|
|
3
4
|
import { canonicalSemanticDigest } from './artifact-operations.ts';
|
|
4
|
-
import { inspectActivityLog, pairEntries } from './activity-log.ts';
|
|
5
5
|
import { parseTypedTaskFrontmatter } from './frontmatter.ts';
|
|
6
6
|
import { parseArtifactName } from './artifact-name.ts';
|
|
7
7
|
import { sha256File } from './artifact-receipts.ts';
|
|
@@ -35,54 +35,57 @@ export function parseCompletionFacts(value: unknown): CompletionFact[] {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
function completionEvent(family: string): string | null {
|
|
39
|
+
if (family === 'validation-run') return 'validation-run.completed';
|
|
40
|
+
if (family === 'analysis') return 'analyze.completed';
|
|
41
|
+
if (family === 'review-analysis') return 'review-analysis.completed';
|
|
42
|
+
if (family === 'plan') return 'plan.completed';
|
|
43
|
+
if (family === 'review-plan') return 'review-plan.completed';
|
|
44
|
+
if (family === 'code') return 'code.completed';
|
|
45
|
+
if (family === 'review-code') return 'review-code.completed';
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Validates an artifact's own completion fact and output evidence. */
|
|
50
|
+
export function hasValidArtifactCompletion(taskContent: string, taskDir: string, artifact: string, event: string): boolean {
|
|
39
51
|
try {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
const content = fs.readFileSync(artifactPath, 'utf8');
|
|
43
|
-
const outputSha256 = sha256File(artifactPath);
|
|
44
|
-
const semanticDigest = canonicalSemanticDigest(content);
|
|
45
|
-
return parseCompletionFacts(frontmatter.completion_facts).some((fact) =>
|
|
46
|
-
fact.event === event && fact.output === output
|
|
47
|
-
&& fact.outputSha256 === outputSha256 && fact.semanticDigest === semanticDigest
|
|
48
|
-
&& fact.requestId.length > 0
|
|
49
|
-
);
|
|
52
|
+
const fact = findCompletionFact(taskContent, artifact, event);
|
|
53
|
+
return Boolean(fact && validateOutput(taskDir, artifact, fact));
|
|
50
54
|
} catch {
|
|
51
55
|
return false;
|
|
52
56
|
}
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
/** Distinguishes an invalidated completion fact from a round that has never completed. */
|
|
60
|
+
export function hasArtifactCompletionRecord(taskContent: string, artifact: string, event: string): boolean {
|
|
61
|
+
try {
|
|
62
|
+
const raw = parseTypedTaskFrontmatter(taskContent).completion_facts;
|
|
63
|
+
if (raw === undefined) return false;
|
|
64
|
+
if (typeof raw !== 'string') return true;
|
|
65
|
+
if (raw.trim() === '') return false;
|
|
66
|
+
const parsed: unknown = JSON.parse(raw);
|
|
67
|
+
if (!Array.isArray(parsed)) return true;
|
|
68
|
+
return parsed.some((fact) => fact && typeof fact === 'object' && !Array.isArray(fact)
|
|
69
|
+
&& (fact as { event?: unknown }).event === event
|
|
70
|
+
&& (fact as { output?: unknown }).output === artifact);
|
|
71
|
+
} catch {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
57
74
|
}
|
|
58
75
|
|
|
59
|
-
|
|
60
|
-
export function artifactCompletionOrder(taskContent: string, artifact: string, event: string): number | null {
|
|
76
|
+
function findCompletionFact(taskContent: string, artifact: string, event: string): CompletionFact | null {
|
|
61
77
|
const identity = parseArtifactName(artifact);
|
|
62
|
-
if (!identity) return null;
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const { section, invalidEntries } = inspectActivityLog(taskContent);
|
|
76
|
-
if (!section || invalidEntries.length > 0) return null;
|
|
77
|
-
const ordered = section.entries.map((entry, sourceOrder) => ({ entry, sourceOrder }))
|
|
78
|
-
.sort((left, right) => Date.parse(left.entry.time.replace(' ', 'T')) - Date.parse(right.entry.time.replace(' ', 'T')) || left.sourceOrder - right.sourceOrder);
|
|
79
|
-
const entries = ordered.map(({ entry }) => entry);
|
|
80
|
-
const roundPattern = new RegExp(`^${action} \\(Round ${identity.round}(?:, [^)]+)?\\)$`);
|
|
81
|
-
const row = pairEntries(entries).find((candidate) => candidate.started !== ''
|
|
82
|
-
&& candidate.done !== '' && roundPattern.test(candidate.step)
|
|
83
|
-
&& candidate.note.includes(`→ ${artifact}`));
|
|
84
|
-
if (!row) return null;
|
|
85
|
-
const doneIndex = ordered.findIndex(({ entry }) => entry.time === row.done
|
|
86
|
-
&& entry.step === row.step && entry.note === row.note);
|
|
87
|
-
return doneIndex < 0 ? null : doneIndex;
|
|
78
|
+
if (!identity || completionEvent(identity.family) !== event) return null;
|
|
79
|
+
const fact = parseCompletionFacts(parseTypedTaskFrontmatter(taskContent).completion_facts)
|
|
80
|
+
.find((candidate) => candidate.event === event && candidate.output === artifact);
|
|
81
|
+
return fact && fact.requestId.length > 0 ? fact : null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function validateOutput(taskDir: string, artifact: string, fact: CompletionFact): boolean {
|
|
85
|
+
const outputPath = path.join(taskDir, artifact);
|
|
86
|
+
const stat = fs.lstatSync(outputPath);
|
|
87
|
+
if (!stat.isFile() || stat.isSymbolicLink()) return false;
|
|
88
|
+
const content = fs.readFileSync(outputPath, 'utf8');
|
|
89
|
+
return sha256File(outputPath) === fact.outputSha256
|
|
90
|
+
&& canonicalSemanticDigest(content) === fact.semanticDigest;
|
|
88
91
|
}
|