ai-delivery-workflow 0.2.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/LICENSE +21 -0
- package/README.md +112 -0
- package/bin/ai-delivery.mjs +138 -0
- package/bin/validate-skills.mjs +12 -0
- package/docs/DUAL-REPOSITORY-WORKSPACE.zh-CN.md +125 -0
- package/docs/EVOLUTION-MAINTENANCE.zh-CN.md +75 -0
- package/docs/EVOLUTION-USER-GUIDE.zh-CN.md +160 -0
- package/docs/FILE-REFERENCE.zh-CN.md +503 -0
- package/docs/PROJECT-MANUAL.zh-CN.md +931 -0
- package/docs/STATE-CLI-MAINTENANCE.zh-CN.md +135 -0
- package/docs/STATE-CLI-USER-GUIDE.zh-CN.md +186 -0
- package/docs/VIEWER-MAINTENANCE.zh-CN.md +373 -0
- package/docs/VIEWER-USER-GUIDE.zh-CN.md +235 -0
- package/lib/delivery-state.mjs +1220 -0
- package/lib/evolution.mjs +971 -0
- package/lib/project-bootstrap.mjs +927 -0
- package/lib/project-installer.mjs +1184 -0
- package/lib/skill-validator.mjs +154 -0
- package/lib/toml-hooks.mjs +97 -0
- package/lib/workspace.mjs +302 -0
- package/lib/yaml-runtime.mjs +18 -0
- package/package.json +39 -0
- package/skills/ai-delivery-assemble-release/SKILL.md +27 -0
- package/skills/ai-delivery-assemble-release/agents/openai.yaml +4 -0
- package/skills/ai-delivery-assemble-release/assets/release-candidate-manifest.yaml +22 -0
- package/skills/ai-delivery-assemble-release/assets/release-git-plan.yaml +9 -0
- package/skills/ai-delivery-assemble-release/assets/release-material-index.csv +2 -0
- package/skills/ai-delivery-assemble-release/assets/version-inclusion.csv +2 -0
- package/skills/ai-delivery-assemble-release/references/release-assembly-contract.md +7 -0
- package/skills/ai-delivery-assemble-release/scripts/plan-release.mjs +298 -0
- package/skills/ai-delivery-bootstrap/SKILL.md +59 -0
- package/skills/ai-delivery-bootstrap/agents/openai.yaml +4 -0
- package/skills/ai-delivery-bootstrap/references/bootstrap-contract.md +70 -0
- package/skills/ai-delivery-checkpoint-task/SKILL.md +63 -0
- package/skills/ai-delivery-checkpoint-task/agents/openai.yaml +4 -0
- package/skills/ai-delivery-checkpoint-task/assets/codex-hook-config.toml +92 -0
- package/skills/ai-delivery-checkpoint-task/assets/runtime-template/resume.md +15 -0
- package/skills/ai-delivery-checkpoint-task/assets/runtime-template/task.json +30 -0
- package/skills/ai-delivery-checkpoint-task/assets/runtime-template/version-archive.json +10 -0
- package/skills/ai-delivery-checkpoint-task/references/checkpoint-contract.md +95 -0
- package/skills/ai-delivery-checkpoint-task/references/checkpoint-recovery.zh-CN.md +111 -0
- package/skills/ai-delivery-checkpoint-task/scripts/hook-event.mjs +131 -0
- package/skills/ai-delivery-checkpoint-task/scripts/task-state.mjs +1073 -0
- package/skills/ai-delivery-close-version/SKILL.md +33 -0
- package/skills/ai-delivery-close-version/agents/openai.yaml +4 -0
- package/skills/ai-delivery-close-version/assets/line-advance-record.yaml +12 -0
- package/skills/ai-delivery-close-version/assets/version-lineage.yaml +12 -0
- package/skills/ai-delivery-close-version/assets/version-manifest.yaml +20 -0
- package/skills/ai-delivery-close-version/references/version-closeout-contract.md +20 -0
- package/skills/ai-delivery-define-product/SKILL.md +76 -0
- package/skills/ai-delivery-define-product/agents/openai.yaml +4 -0
- package/skills/ai-delivery-define-product/assets/product-template/acceptance-criteria.csv +1 -0
- package/skills/ai-delivery-define-product/assets/product-template/discovery-baseline.md +19 -0
- package/skills/ai-delivery-define-product/assets/product-template/feature-detail.md +19 -0
- package/skills/ai-delivery-define-product/assets/product-template/feature-terminals.csv +1 -0
- package/skills/ai-delivery-define-product/assets/product-template/features.csv +1 -0
- package/skills/ai-delivery-define-product/assets/product-template/product-baseline.yaml +8 -0
- package/skills/ai-delivery-define-product/assets/product-template/product-manual.md +24 -0
- package/skills/ai-delivery-define-product/assets/product-template/terminals.csv +1 -0
- package/skills/ai-delivery-define-product/assets/product-template/user-stories.csv +1 -0
- package/skills/ai-delivery-define-product/references/product-contract.md +57 -0
- package/skills/ai-delivery-deploy-production/SKILL.md +45 -0
- package/skills/ai-delivery-deploy-production/agents/openai.yaml +4 -0
- package/skills/ai-delivery-deploy-production/references/deployment-contract.md +7 -0
- package/skills/ai-delivery-design-architecture/SKILL.md +67 -0
- package/skills/ai-delivery-design-architecture/agents/openai.yaml +4 -0
- package/skills/ai-delivery-design-architecture/assets/architecture-template/architecture-baseline.md +25 -0
- package/skills/ai-delivery-design-architecture/assets/architecture-template/architecture-gate.yaml +15 -0
- package/skills/ai-delivery-design-architecture/assets/architecture-template/prototype-architecture-validation.yaml +58 -0
- package/skills/ai-delivery-design-architecture/references/architecture-contract.md +32 -0
- package/skills/ai-delivery-design-experience/SKILL.md +71 -0
- package/skills/ai-delivery-design-experience/agents/openai.yaml +4 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/canvas-catalog.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/canvas-pages.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/component-state-matrix.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/design-tokens.json +19 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/experience-baseline.yaml +17 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/experience-change-domains.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/experience-change-set.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/feature-screen-coverage.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/formal-ui-confirmation.yaml +33 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/interaction-contract.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/low-fidelity-confirmation.yaml +32 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/page-catalog.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/page-component-map.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/product-prototype-reconciliation.yaml +28 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-adjustment-log.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-confirmation.yaml +99 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-file-terminals.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-files.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-impact-assessment.yaml +25 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-manifest.yaml +74 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-product-coverage.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-comments.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-decision.yaml +29 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-review-sessions.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-set.yaml +22 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-tool-candidates.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-tool-selection.yaml +22 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-traceability.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/requirement-change-set.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/screen-states.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/ui-framework-candidates.csv +1 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/ui-framework-selection.yaml +18 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/ui-handoff.yaml +44 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/visual-direction.yaml +16 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/visual-system-confirmation.yaml +31 -0
- package/skills/ai-delivery-design-experience/references/experience-contract.md +82 -0
- package/skills/ai-delivery-design-experience/references/prototype-management-contract.md +68 -0
- package/skills/ai-delivery-design-tests/SKILL.md +56 -0
- package/skills/ai-delivery-design-tests/agents/openai.yaml +4 -0
- package/skills/ai-delivery-design-tests/assets/test-design-template/iteration-test-contract.md +19 -0
- package/skills/ai-delivery-design-tests/assets/test-design-template/prototype-test-scope.csv +1 -0
- package/skills/ai-delivery-design-tests/assets/test-design-template/prototype-test-validation.yaml +73 -0
- package/skills/ai-delivery-design-tests/references/test-design-contract.md +31 -0
- package/skills/ai-delivery-develop-iteration/SKILL.md +66 -0
- package/skills/ai-delivery-develop-iteration/agents/openai.yaml +4 -0
- package/skills/ai-delivery-develop-iteration/assets/development-template/task-experience-change-traceability.csv +1 -0
- package/skills/ai-delivery-develop-iteration/assets/development-template/task-prototype-traceability.csv +1 -0
- package/skills/ai-delivery-develop-iteration/references/development-contract.md +39 -0
- package/skills/ai-delivery-evolve-workflow/SKILL.md +57 -0
- package/skills/ai-delivery-evolve-workflow/agents/openai.yaml +4 -0
- package/skills/ai-delivery-evolve-workflow/references/evolution-contract.md +42 -0
- package/skills/ai-delivery-execute-test/SKILL.md +34 -0
- package/skills/ai-delivery-execute-test/agents/openai.yaml +4 -0
- package/skills/ai-delivery-execute-test/references/test-execution-contract.md +7 -0
- package/skills/ai-delivery-execute-work-package/SKILL.md +53 -0
- package/skills/ai-delivery-execute-work-package/agents/openai.yaml +4 -0
- package/skills/ai-delivery-execute-work-package/references/work-package-contract.md +20 -0
- package/skills/ai-delivery-manage-git/SKILL.md +60 -0
- package/skills/ai-delivery-manage-git/agents/openai.yaml +4 -0
- package/skills/ai-delivery-manage-git/references/git-policy.md +42 -0
- package/skills/ai-delivery-manage-standards/SKILL.md +44 -0
- package/skills/ai-delivery-manage-standards/agents/openai.yaml +4 -0
- package/skills/ai-delivery-manage-standards/assets/standards-template/standard.md +25 -0
- package/skills/ai-delivery-manage-standards/references/standards-contract.md +20 -0
- package/skills/ai-delivery-orchestrate/SKILL.md +105 -0
- package/skills/ai-delivery-orchestrate/agents/openai.yaml +4 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.codex/config.toml +92 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.gitattributes +6 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/artifact-registry.yaml +3 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/project.yaml +6 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/standards-baseline.yaml +8 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/delivery/workflow-state.yaml +34 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/evolution/decisions/.gitkeep +0 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/evolution/experiments/.gitkeep +0 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/evolution/feedback/.gitkeep +0 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/evolution/index.yaml +7 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/evolution/promotion/.gitkeep +0 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/evolution/proposals/.gitkeep +0 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/extensions/.gitkeep +0 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/standards/STD-ARTIFACT-PATH-001.md +47 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/standards/STD-DOC-LANG-001.md +62 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/standards/STD-TEST-LOCATION-001.md +23 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/standards/index.yaml +36 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/bootstrap/bootstrap.mjs +33 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/evolution/evolve.mjs +15 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/hooks/hook-event.mjs +131 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/state/state.mjs +21 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/app.js +546 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/index.html +199 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/public/styles.css +529 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/server.mjs +780 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/start.cmd +4 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/start.ps1 +2 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/viewer/start.sh +4 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/AGENTS.md +44 -0
- package/skills/ai-delivery-orchestrate/references/formal-state-contract.md +64 -0
- package/skills/ai-delivery-orchestrate/references/workflow-model.md +29 -0
- package/skills/ai-delivery-orchestrate-release/SKILL.md +33 -0
- package/skills/ai-delivery-orchestrate-release/agents/openai.yaml +4 -0
- package/skills/ai-delivery-orchestrate-release/assets/release-request.yaml +9 -0
- package/skills/ai-delivery-orchestrate-release/assets/version-selection.yaml +16 -0
- package/skills/ai-delivery-orchestrate-release/references/release-workflow-contract.md +11 -0
- package/skills/ai-delivery-plan-iteration/SKILL.md +57 -0
- package/skills/ai-delivery-plan-iteration/agents/openai.yaml +4 -0
- package/skills/ai-delivery-plan-iteration/assets/planning-template/backlog.csv +1 -0
- package/skills/ai-delivery-plan-iteration/assets/planning-template/slice-dependencies.csv +1 -0
- package/skills/ai-delivery-plan-iteration/assets/planning-template/slice-experience-change-traceability.csv +1 -0
- package/skills/ai-delivery-plan-iteration/assets/planning-template/slice-prototype-traceability.csv +1 -0
- package/skills/ai-delivery-plan-iteration/assets/planning-template/slice-sources.csv +1 -0
- package/skills/ai-delivery-plan-iteration/assets/planning-template/vertical-slices.csv +1 -0
- package/skills/ai-delivery-plan-iteration/references/planning-contract.md +40 -0
- package/skills/ai-delivery-prepare-platform/SKILL.md +49 -0
- package/skills/ai-delivery-prepare-platform/agents/openai.yaml +4 -0
- package/skills/ai-delivery-prepare-platform/assets/platform-template/environment-ledger.csv +1 -0
- package/skills/ai-delivery-prepare-platform/references/platform-contract.md +18 -0
- package/skills/ai-delivery-prepare-release/SKILL.md +47 -0
- package/skills/ai-delivery-prepare-release/agents/openai.yaml +4 -0
- package/skills/ai-delivery-prepare-release/assets/release-template/delivery-items.csv +1 -0
- package/skills/ai-delivery-prepare-release/assets/release-template/release-manifest.yaml +18 -0
- package/skills/ai-delivery-prepare-release/references/release-contract.md +21 -0
- package/skills/ai-delivery-review-change/SKILL.md +40 -0
- package/skills/ai-delivery-review-change/agents/openai.yaml +4 -0
- package/skills/ai-delivery-review-change/references/review-contract.md +20 -0
- package/skills/ai-delivery-triage-failure/SKILL.md +45 -0
- package/skills/ai-delivery-triage-failure/agents/openai.yaml +4 -0
- package/skills/ai-delivery-triage-failure/references/failure-routing-contract.md +13 -0
- package/skills/ai-delivery-validate-artifacts/SKILL.md +37 -0
- package/skills/ai-delivery-validate-artifacts/agents/openai.yaml +4 -0
- package/skills/ai-delivery-validate-artifacts/references/artifact-contract.md +44 -0
- package/skills/ai-delivery-verify-candidate/SKILL.md +56 -0
- package/skills/ai-delivery-verify-candidate/agents/openai.yaml +4 -0
- package/skills/ai-delivery-verify-candidate/assets/verification-template/defect-artifacts.csv +1 -0
- package/skills/ai-delivery-verify-candidate/assets/verification-template/defects.csv +1 -0
- package/skills/ai-delivery-verify-candidate/assets/verification-template/test-work-packages.csv +1 -0
- package/skills/ai-delivery-verify-candidate/references/candidate-verification-contract.md +23 -0
- package/skills/ai-delivery-verify-production/SKILL.md +50 -0
- package/skills/ai-delivery-verify-production/agents/openai.yaml +4 -0
- package/skills/ai-delivery-verify-production/assets/production-verification-template/production-verification.md +15 -0
- package/skills/ai-delivery-verify-production/references/production-verification-contract.md +14 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
item_id,category,source_version_id,artifact_id,repo_id,code_commit,code_tag,source_path,original_workflow_path,sha256,target_environment,apply_order,verification,rollback_or_recovery
|
|
2
|
+
ITEM-0001,container-image,VER-0001,ART-IMAGE-0001,app,<git-sha>,version-ready/VER-0001/r1,code,.workflow/iterations/VER-0001/12-version-closeout/version-manifest.yaml,<sha256>,production,10,verify image digest,deploy previous immutable image digest
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
sequence,version_id,predecessor_version_id,candidate_id,candidate_commit,version_ready_tag,manifest_path,manifest_sha256,inclusion_type
|
|
2
|
+
1,VER-0001,,CAND-0001,<git-sha>,version-ready/VER-0001/r1,.workflow/iterations/VER-0001/12-version-closeout/version-manifest.yaml,<sha256>,dependency-closure
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Release Assembly Contract
|
|
2
|
+
|
|
3
|
+
Treat the target version tag as the only code source for a release candidate. Never assemble code by merging every intermediate tag and never use a movable branch head as the source.
|
|
4
|
+
|
|
5
|
+
The material index is exhaustive for actual changes and contains stable item ID, category, source version, source artifact ID/path/checksum, target environment, application order, verification, and rollback/recovery action. Do not record secret values.
|
|
6
|
+
|
|
7
|
+
Require every adjacent version in the full dependency closure through the target, including already produced history, to descend from its predecessor in both the code repository (`candidate_commit`) and workflow repository (`workflow_commit`). Production-to-target reachability alone cannot prove that an intermediate version is included. Repeat the full closure check for same-version redeploy. A production hotfix must first be synchronized into `line/<product-id>`; candidates that do not contain it are `stale`. When current production equals target, emit `same-version-redeploy`, an empty newly included range, and a fresh release identity.
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { spawnSync } from "node:child_process";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const ELIGIBLE_STATUSES = new Set(["release-ready", "released", "included-in-release"]);
|
|
10
|
+
|
|
11
|
+
function parseArgs(argv) {
|
|
12
|
+
const options = new Map();
|
|
13
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
14
|
+
const key = argv[index];
|
|
15
|
+
if (!key.startsWith("--")) throw new Error(`Unexpected argument: ${key}`);
|
|
16
|
+
const next = argv[index + 1];
|
|
17
|
+
if (!next || next.startsWith("--")) {
|
|
18
|
+
options.set(key, true);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
options.set(key, next);
|
|
22
|
+
index += 1;
|
|
23
|
+
}
|
|
24
|
+
return options;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function required(options, name) {
|
|
28
|
+
const value = options.get(name);
|
|
29
|
+
if (value === undefined || value === true || String(value).trim() === "") {
|
|
30
|
+
throw new Error(`Missing required option: ${name}`);
|
|
31
|
+
}
|
|
32
|
+
return String(value).trim();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function readLineage(file) {
|
|
36
|
+
let parsed;
|
|
37
|
+
try {
|
|
38
|
+
parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
39
|
+
} catch (error) {
|
|
40
|
+
throw new Error(`Cannot read lineage JSON ${file}: ${error.message}`);
|
|
41
|
+
}
|
|
42
|
+
if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.versions) || !parsed.versions.length) {
|
|
43
|
+
throw new Error("Lineage must contain a non-empty versions array.");
|
|
44
|
+
}
|
|
45
|
+
return parsed;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function repositoriesFromWorkspace(workspaceRoot) {
|
|
49
|
+
const root = path.resolve(workspaceRoot);
|
|
50
|
+
const file = path.join(root, ".workflow", "config", "workspace.yaml");
|
|
51
|
+
const text = fs.readFileSync(file, "utf8");
|
|
52
|
+
const section = (name) => text.match(new RegExp(`^${name}:\\s*\\r?\\n((?:[ \\t]+.*(?:\\r?\\n|$))*)`, "m"))?.[1] || "";
|
|
53
|
+
const value = (body, name) => {
|
|
54
|
+
const raw = body.match(new RegExp(`^\\s+${name}:\\s*(.+?)\\s*$`, "m"))?.[1]?.replace(/^['"]|['"]$/g, "");
|
|
55
|
+
return raw && raw !== "null" ? raw : null;
|
|
56
|
+
};
|
|
57
|
+
const codeSection = section("code_repository");
|
|
58
|
+
const workflowSection = section("workflow_repository");
|
|
59
|
+
const rawPath = value(codeSection, "path");
|
|
60
|
+
if (!rawPath) throw new Error(`Workspace configuration is missing code_repository.path: ${file}`);
|
|
61
|
+
const codePath = rawPath;
|
|
62
|
+
const codeRepo = path.resolve(root, codePath);
|
|
63
|
+
const relative = path.relative(root, codeRepo);
|
|
64
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
65
|
+
throw new Error(`Workspace code repository path is invalid: ${codePath}`);
|
|
66
|
+
}
|
|
67
|
+
const repoId = value(codeSection, "repo_id");
|
|
68
|
+
return {
|
|
69
|
+
codeRepo,
|
|
70
|
+
workflowRepo: root,
|
|
71
|
+
repoId,
|
|
72
|
+
codeRemote: value(codeSection, "remote"),
|
|
73
|
+
workflowRemote: value(workflowSection, "remote"),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function orderedVersions(versions) {
|
|
78
|
+
const byId = new Map();
|
|
79
|
+
const successor = new Map();
|
|
80
|
+
for (const version of versions) {
|
|
81
|
+
if (!version?.version_id) throw new Error("Every lineage entry requires version_id.");
|
|
82
|
+
if (byId.has(version.version_id)) throw new Error(`Duplicate version ID: ${version.version_id}`);
|
|
83
|
+
byId.set(version.version_id, version);
|
|
84
|
+
}
|
|
85
|
+
for (const version of versions) {
|
|
86
|
+
if (version.predecessor_id !== null && version.predecessor_id !== undefined && version.predecessor_id !== "") {
|
|
87
|
+
if (!byId.has(version.predecessor_id)) {
|
|
88
|
+
throw new Error(`Version ${version.version_id} has missing predecessor ${version.predecessor_id}.`);
|
|
89
|
+
}
|
|
90
|
+
if (successor.has(version.predecessor_id)) {
|
|
91
|
+
throw new Error(`Version lineage branches after ${version.predecessor_id}; releases require one cumulative line.`);
|
|
92
|
+
}
|
|
93
|
+
successor.set(version.predecessor_id, version.version_id);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const roots = versions.filter((version) => version.predecessor_id === null
|
|
97
|
+
|| version.predecessor_id === undefined
|
|
98
|
+
|| version.predecessor_id === "");
|
|
99
|
+
if (roots.length !== 1) throw new Error(`Version lineage requires exactly one root; found ${roots.length}.`);
|
|
100
|
+
|
|
101
|
+
const ordered = [];
|
|
102
|
+
const visited = new Set();
|
|
103
|
+
let current = roots[0];
|
|
104
|
+
while (current) {
|
|
105
|
+
if (visited.has(current.version_id)) throw new Error(`Version lineage contains a cycle at ${current.version_id}.`);
|
|
106
|
+
visited.add(current.version_id);
|
|
107
|
+
ordered.push(current);
|
|
108
|
+
current = byId.get(successor.get(current.version_id));
|
|
109
|
+
}
|
|
110
|
+
if (visited.size !== versions.length) throw new Error("Version lineage is disconnected or cyclic.");
|
|
111
|
+
return ordered;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function git(repo, args) {
|
|
115
|
+
const result = spawnSync("git", args, { cwd: repo, encoding: "utf8", windowsHide: true });
|
|
116
|
+
if (result.status !== 0) throw new Error(`Git validation failed: git ${args.join(" ")}: ${result.stderr.trim()}`);
|
|
117
|
+
return result.stdout.trim();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function validateRemoteTag(remote, tag, expectedCommit) {
|
|
121
|
+
if (!remote) return;
|
|
122
|
+
const reference = `refs/tags/${tag}`;
|
|
123
|
+
const result = spawnSync("git", ["ls-remote", "--tags", remote, reference, `${reference}^{}`], {
|
|
124
|
+
encoding: "utf8",
|
|
125
|
+
windowsHide: true,
|
|
126
|
+
});
|
|
127
|
+
if (result.status !== 0) {
|
|
128
|
+
throw new Error(`Remote tag validation failed for ${tag}: ${result.stderr.trim()}`);
|
|
129
|
+
}
|
|
130
|
+
const commits = result.stdout.split(/\r?\n/).filter(Boolean).map((line) => line.split(/\s+/)[0].toLowerCase());
|
|
131
|
+
if (!commits.length) throw new Error(`Remote is missing tag ${tag}: ${remote}`);
|
|
132
|
+
if (!commits.includes(expectedCommit.toLowerCase())) {
|
|
133
|
+
throw new Error(`Remote tag ${tag} does not resolve to expected commit ${expectedCommit}.`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function validateAdjacentAncestry(repo, selected, currentProduction, commitField, label) {
|
|
138
|
+
const chain = currentProduction
|
|
139
|
+
? [currentProduction, ...selected.filter((version) => version.version_id !== currentProduction.version_id)]
|
|
140
|
+
: selected;
|
|
141
|
+
for (let index = 1; index < chain.length; index += 1) {
|
|
142
|
+
const predecessor = chain[index - 1];
|
|
143
|
+
const successor = chain[index];
|
|
144
|
+
const result = spawnSync(
|
|
145
|
+
"git",
|
|
146
|
+
["merge-base", "--is-ancestor", predecessor[commitField], successor[commitField]],
|
|
147
|
+
{ cwd: repo, encoding: "utf8", windowsHide: true },
|
|
148
|
+
);
|
|
149
|
+
if (result.status !== 0) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`${label} ancestry edge ${predecessor.version_id} -> ${successor.version_id} is not cumulative.`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function validateGit(repo, selected, currentProduction, remote) {
|
|
158
|
+
for (const version of selected) {
|
|
159
|
+
const resolved = git(repo, ["rev-list", "-n", "1", version.version_ready_tag]);
|
|
160
|
+
if (resolved.toLowerCase() !== version.candidate_commit.toLowerCase()) {
|
|
161
|
+
throw new Error(`Tag ${version.version_ready_tag} does not resolve to candidate commit ${version.candidate_commit}.`);
|
|
162
|
+
}
|
|
163
|
+
validateRemoteTag(remote, version.version_ready_tag, version.candidate_commit);
|
|
164
|
+
}
|
|
165
|
+
validateAdjacentAncestry(repo, selected, currentProduction, "candidate_commit", "Code");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function validateWorkflowGit(repo, selected, currentProduction, remote) {
|
|
169
|
+
for (const version of selected) {
|
|
170
|
+
const resolved = git(repo, ["rev-list", "-n", "1", version.workflow_ready_tag]);
|
|
171
|
+
if (resolved.toLowerCase() !== version.workflow_commit.toLowerCase()) {
|
|
172
|
+
throw new Error(`Workflow tag ${version.workflow_ready_tag} does not resolve to workflow commit ${version.workflow_commit}.`);
|
|
173
|
+
}
|
|
174
|
+
validateRemoteTag(remote, version.workflow_ready_tag, version.workflow_commit);
|
|
175
|
+
if (path.isAbsolute(version.artifact_manifest) || version.artifact_manifest.replaceAll("\\", "/").split("/").includes("..")) {
|
|
176
|
+
throw new Error(`Version ${version.version_id} has an invalid workflow manifest path.`);
|
|
177
|
+
}
|
|
178
|
+
const manifest = git(repo, ["show", `${version.workflow_ready_tag}:${version.artifact_manifest.replaceAll("\\", "/")}`]);
|
|
179
|
+
const checksum = crypto.createHash("sha256").update(manifest.endsWith("\n") ? manifest : `${manifest}\n`).digest("hex");
|
|
180
|
+
if (checksum.toLowerCase() !== version.artifact_sha256.toLowerCase()) {
|
|
181
|
+
throw new Error(`Workflow manifest checksum mismatch for ${version.version_id}.`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
validateAdjacentAncestry(repo, selected, currentProduction, "workflow_commit", "Workflow");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function planRelease(lineage, request, options = {}) {
|
|
188
|
+
const ordered = orderedVersions(lineage.versions);
|
|
189
|
+
const targetIndex = ordered.findIndex((version) => version.version_id === request.target_version);
|
|
190
|
+
if (targetIndex < 0) throw new Error(`Target version is not in the cumulative line: ${request.target_version}`);
|
|
191
|
+
|
|
192
|
+
const currentId = lineage.current_production_version || null;
|
|
193
|
+
const currentIndex = currentId === null ? -1 : ordered.findIndex((version) => version.version_id === currentId);
|
|
194
|
+
if (currentId !== null && currentIndex < 0) {
|
|
195
|
+
throw new Error(`Current production version is not in the cumulative line: ${currentId}`);
|
|
196
|
+
}
|
|
197
|
+
if (targetIndex < currentIndex) {
|
|
198
|
+
throw new Error(`Target ${request.target_version} is older than current production ${currentId}; use image rollback instead.`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const target = ordered[targetIndex];
|
|
202
|
+
const newlyIncluded = ordered.slice(currentIndex + 1, targetIndex + 1);
|
|
203
|
+
const releaseEvidence = targetIndex === currentIndex ? [target] : newlyIncluded;
|
|
204
|
+
const dependencyClosure = ordered.slice(0, targetIndex + 1);
|
|
205
|
+
for (const version of releaseEvidence) {
|
|
206
|
+
if (!ELIGIBLE_STATUSES.has(version.status)) {
|
|
207
|
+
throw new Error(`Version ${version.version_id} is not eligible for release: ${version.status || "missing status"}.`);
|
|
208
|
+
}
|
|
209
|
+
if (!version.candidate_id || !version.candidate_commit || !version.artifact_manifest || !version.artifact_sha256) {
|
|
210
|
+
throw new Error(`Version ${version.version_id} is missing immutable candidate or material identity.`);
|
|
211
|
+
}
|
|
212
|
+
if (!version.version_ready_tag) {
|
|
213
|
+
throw new Error(`Version ${version.version_id} requires an immutable version-ready tag.`);
|
|
214
|
+
}
|
|
215
|
+
if (!version.workflow_commit || !version.workflow_ready_tag) {
|
|
216
|
+
throw new Error(`Version ${version.version_id} requires an immutable workflow-ready tag and commit.`);
|
|
217
|
+
}
|
|
218
|
+
if (options.repoId && version.repo_id !== options.repoId) {
|
|
219
|
+
throw new Error(`Version ${version.version_id} references repository ${version.repo_id || "missing"}; expected ${options.repoId}.`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (!options.skipGit) {
|
|
224
|
+
validateGit(
|
|
225
|
+
path.resolve(options.repo || process.cwd()),
|
|
226
|
+
dependencyClosure,
|
|
227
|
+
null,
|
|
228
|
+
options.codeRemote || null,
|
|
229
|
+
);
|
|
230
|
+
validateWorkflowGit(
|
|
231
|
+
path.resolve(options.workflowRepo || process.cwd()),
|
|
232
|
+
dependencyClosure,
|
|
233
|
+
null,
|
|
234
|
+
options.workflowRemote || null,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return {
|
|
239
|
+
schema_version: 1,
|
|
240
|
+
release_id: request.release_id,
|
|
241
|
+
product_id: lineage.product_id,
|
|
242
|
+
requested_by: request.requested_by,
|
|
243
|
+
rationale: request.rationale,
|
|
244
|
+
target_environment: "production",
|
|
245
|
+
current_production_version: currentId,
|
|
246
|
+
target_version: target.version_id,
|
|
247
|
+
mode: targetIndex === currentIndex ? "same-version-redeploy" : "incremental",
|
|
248
|
+
newly_included_versions: newlyIncluded.map((version) => version.version_id),
|
|
249
|
+
dependency_closure: dependencyClosure.map((version) => version.version_id),
|
|
250
|
+
target: {
|
|
251
|
+
version_id: target.version_id,
|
|
252
|
+
candidate_id: target.candidate_id,
|
|
253
|
+
candidate_commit: target.candidate_commit,
|
|
254
|
+
version_ready_tag: target.version_ready_tag,
|
|
255
|
+
workflow_commit: target.workflow_commit,
|
|
256
|
+
workflow_ready_tag: target.workflow_ready_tag,
|
|
257
|
+
artifact_manifest: target.artifact_manifest,
|
|
258
|
+
artifact_sha256: target.artifact_sha256,
|
|
259
|
+
repo_id: target.repo_id || options.repoId || null,
|
|
260
|
+
},
|
|
261
|
+
requires_fresh_environment_snapshot: true,
|
|
262
|
+
requires_fresh_verification: true,
|
|
263
|
+
requires_fresh_approval: true,
|
|
264
|
+
rollback_strategy: "previous-immutable-image-digest",
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function main(argv) {
|
|
269
|
+
const options = parseArgs(argv);
|
|
270
|
+
const lineageFile = path.resolve(required(options, "--lineage"));
|
|
271
|
+
const configured = options.get("--workspace")
|
|
272
|
+
? repositoriesFromWorkspace(options.get("--workspace"))
|
|
273
|
+
: { codeRepo: process.cwd(), workflowRepo: process.cwd(), repoId: null, codeRemote: null, workflowRemote: null };
|
|
274
|
+
const result = planRelease(readLineage(lineageFile), {
|
|
275
|
+
release_id: required(options, "--release-id"),
|
|
276
|
+
target_version: required(options, "--target"),
|
|
277
|
+
requested_by: required(options, "--requested-by"),
|
|
278
|
+
rationale: required(options, "--rationale"),
|
|
279
|
+
}, {
|
|
280
|
+
repo: options.get("--repo") || configured.codeRepo,
|
|
281
|
+
workflowRepo: options.get("--workflow-repo") || configured.workflowRepo,
|
|
282
|
+
repoId: configured.repoId,
|
|
283
|
+
codeRemote: configured.codeRemote,
|
|
284
|
+
workflowRemote: configured.workflowRemote,
|
|
285
|
+
skipGit: options.get("--skip-git") === true,
|
|
286
|
+
});
|
|
287
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
291
|
+
if (isMain) {
|
|
292
|
+
try {
|
|
293
|
+
main(process.argv.slice(2));
|
|
294
|
+
} catch (error) {
|
|
295
|
+
process.stderr.write(`${error.message}\n`);
|
|
296
|
+
process.exitCode = 1;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ai-delivery-bootstrap
|
|
3
|
+
description: Inspect a project before normal AI delivery execution, classify empty, brownfield, initialized, interrupted, and inconsistent states, safely install missing project-scoped workflow files, generate draft repository context, and route the next skill or recoverable task. Use at the beginning of a new conversation, in an unfamiliar repository, after a restart or interruption, when delivery tracking files may be absent, or when the correct next workflow node is unknown.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Bootstrap AI Delivery
|
|
7
|
+
|
|
8
|
+
Establish enough verified project context to resume or begin work without relying on chat history.
|
|
9
|
+
|
|
10
|
+
## Dual-Repository Workspace
|
|
11
|
+
|
|
12
|
+
Treat the directory containing `.workflow/config/workspace.yaml` as the workflow repository and resolve the single code repository only from `code_repository.path`. Never infer a second code root or run code Git commands from the workflow root. Require the workflow Git root to ignore the exact code child path while keeping `.workflow/` tracked. On restart, prefer `.workflow/control/tasks/*.yaml` and the newest shared checkpoint when local runtime is absent; stop when local and shared revisions disagree.
|
|
13
|
+
|
|
14
|
+
## Artifact Location
|
|
15
|
+
|
|
16
|
+
Write every workflow document produced by this skill under project `.workflow/`. Place version-scoped node outputs in `.workflow/iterations/<iteration-id>/<node-id>/` unless an approved contract assigns `.workflow/delivery/`, `.workflow/standards/`, `.workflow/product/`, `.workflow/architecture/`, or `.workflow/experience/`. Do not relocate source code, automated test source, repository configuration, or non-document build artifacts.
|
|
17
|
+
|
|
18
|
+
## Inspect First
|
|
19
|
+
|
|
20
|
+
1. Locate the project root without creating files.
|
|
21
|
+
2. After `init`, run `node .workflow/tools/bootstrap/bootstrap.mjs inspect` from the project root. Use packaged `ai-delivery inspect <project-root>` only before a project-local runtime exists.
|
|
22
|
+
3. Read the returned `state`, errors, runtime recommendation, codebase summary, both Git states, shared checkpoint state, sync warnings, and recommended skill.
|
|
23
|
+
4. Do not mutate the project before this classification.
|
|
24
|
+
|
|
25
|
+
## Natural-Language Entry
|
|
26
|
+
|
|
27
|
+
Treat ordinary user messages such as “开始”, “继续”, “下一步”, “现在做到哪了”, a direct product idea, or an explicit release request as sufficient intent. Select and invoke every required project Skill and CLI internally. Never ask the user to type a Skill name or run a workflow command. Ask the user only for business facts, material review, an explicit Gate decision, or authority for an external side effect.
|
|
28
|
+
|
|
29
|
+
## First Task Identity
|
|
30
|
+
|
|
31
|
+
When inspection returns `workflow-ready`, there are no task shards, and the formal registry has no delivery artifact:
|
|
32
|
+
|
|
33
|
+
1. Run `node .workflow/tools/bootstrap/bootstrap.mjs bootstrap` to create the observed bootstrap context.
|
|
34
|
+
2. Start development scope `INIT-0001` through the formal state CLI.
|
|
35
|
+
3. Register `TASK-INIT-0001-00` for `00-bootstrap` and `TASK-INIT-0001-01` for `01-product-discovery`, with the latter depending on the former.
|
|
36
|
+
4. Finish the bootstrap task only after its report and handoff evidence are registered, then activate the discovery task.
|
|
37
|
+
5. Let `task-state.mjs` resolve `code_branch` and `code_commit` from the authoritative `.workflow/config/workspace.yaml`; never use the install manifest copy or record the workflow Git identity as code identity.
|
|
38
|
+
|
|
39
|
+
The first product question is the safe stopping point. Do not invent the initial business need and do not leave product artifacts outside an initialized task.
|
|
40
|
+
|
|
41
|
+
## Route By State
|
|
42
|
+
|
|
43
|
+
- `empty-uninitialized`: use packaged `ai-delivery bootstrap` because no project-local runtime exists, read the generated report, then invoke `$ai-delivery-define-product`. Ask one business question at a time; do not invent the initial need.
|
|
44
|
+
- `codebase-uninitialized`: use packaged `ai-delivery bootstrap`, review the repository baseline, inventory, context index, and adoption assessment, then invoke `$ai-delivery-define-product` to distinguish observed behavior from intended product behavior.
|
|
45
|
+
- `workflow-interrupted`: do not write bootstrap artifacts. If `runtime.next_action_owner` is `user`, return the recorded `next_action` as the single business question and perform no recovery, activation, checkpoint, task, artifact, or Git mutation. If it is `external`, report the recorded wait condition without mutation. Only an `agent`-owned next action may invoke `$ai-delivery-checkpoint-task recover`, reconcile reality, inspect the pending Evolution queue without applying changes mid-task, and continue `recommended_task_id`. When required input arrives, transfer ownership with both `--next-action-owner agent` and a new idempotent `--next-action`.
|
|
46
|
+
- `workflow-ready`: when a queued task is recommended, first apply the same `next_action_owner` boundary; activate it through `$ai-delivery-checkpoint-task` only when the owner is `agent`. Otherwise use the reported specialist skill or `$ai-delivery-orchestrate` to derive the next development node. Treat `release-ready` versions as completed development evidence, not implicit release intent. Route to `$ai-delivery-orchestrate-release` only when the user explicitly requests a release.
|
|
47
|
+
- `workflow-inconsistent`: stop automatic mutation, run the available project/package doctor internally, report exact conflicts, and obtain a repair decision. Never use `--force` unless the user explicitly approves replacing the reported managed files.
|
|
48
|
+
|
|
49
|
+
## Brownfield Rules
|
|
50
|
+
|
|
51
|
+
Treat repository scans as observations, not approved product or architecture truth. Keep generated artifacts `draft`. Exclude secrets, dependency/build directories, workflow internals, and files outside the project. Verify inferred commands before recording them as supported.
|
|
52
|
+
|
|
53
|
+
Do not replace existing product, architecture, test, or release baselines. Register the project-state report, preserve every timestamped bootstrap run, and update only the `.workflow/delivery/bootstrap/latest.yaml` pointer.
|
|
54
|
+
|
|
55
|
+
## Resume Boundary
|
|
56
|
+
|
|
57
|
+
Codex lifecycle Hooks provide audit and heartbeat data only. Versioned Evolution Hooks may return `pass`, `warn`, or an approved `block`, but they never select or complete tasks and never mutate formal workflow state. A bootstrap report may recommend recovery, but `$ai-delivery-checkpoint-task` remains authoritative for task order, dependency readiness, worktree reconciliation, and idempotent continuation. Route pending feedback and extension evaluation to `$ai-delivery-evolve-workflow` only at a task, version, or explicit review safe point.
|
|
58
|
+
|
|
59
|
+
Read [bootstrap-contract.md](references/bootstrap-contract.md) for classifications, generated artifacts, safety constraints, and handoff requirements.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
interface:
|
|
2
|
+
display_name: "Bootstrap AI Delivery"
|
|
3
|
+
short_description: "Inspect project state and route the next workflow action"
|
|
4
|
+
default_prompt: "Use $ai-delivery-bootstrap to inspect the dual-repository workspace, recover shared checkpoints, or initialize the minimum delivery context."
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Bootstrap Contract
|
|
2
|
+
|
|
3
|
+
## Classification
|
|
4
|
+
|
|
5
|
+
Return exactly one state:
|
|
6
|
+
|
|
7
|
+
- `empty-uninitialized`: no complete workflow installation and no source, test, manifest, build, deployment, or infrastructure evidence;
|
|
8
|
+
- `codebase-uninitialized`: no complete workflow installation and at least one codebase evidence file;
|
|
9
|
+
- `workflow-ready`: complete, parseable project-scoped installation with no resumable task;
|
|
10
|
+
- `workflow-interrupted`: complete installation with a preparing, running, checkpointed, pending-review, blocked, or interrupted task;
|
|
11
|
+
- `workflow-inconsistent`: partial installation, malformed required file, project identity mismatch, missing installed skill, or missing task dependency.
|
|
12
|
+
|
|
13
|
+
Ignore `.git`, project workflow directories, dependency caches, generated builds, coverage, virtual environments, and vendor directories when deciding whether product code exists. Exclude secret and private-key files from context artifacts.
|
|
14
|
+
|
|
15
|
+
## Read-Only Inspection
|
|
16
|
+
|
|
17
|
+
After installation, `node .workflow/tools/bootstrap/bootstrap.mjs inspect` is the self-contained entrypoint and must not write project files. Before installation, the packaged `ai-delivery inspect <project-root>` provides the same contract. Report:
|
|
18
|
+
|
|
19
|
+
- installation presence and missing required files;
|
|
20
|
+
- project and iteration identity;
|
|
21
|
+
- artifact, active-node, blocked-node, and pending-Gate counts;
|
|
22
|
+
- active, queued, dependency-ready, and recommended task identity, including `next_action_owner`;
|
|
23
|
+
- code evidence, technologies, file categories, and sensitive-file exclusion count;
|
|
24
|
+
- Git repository, branch, HEAD, and dirty paths when available;
|
|
25
|
+
- errors, warnings, recommended skill, action, and whether user input is required.
|
|
26
|
+
|
|
27
|
+
## Bootstrap Mutation
|
|
28
|
+
|
|
29
|
+
`ai-delivery bootstrap <project-root>` may initialize only `empty-uninitialized` and `codebase-uninitialized` projects through the project-scoped installer. Preserve existing code and configuration. On partial or conflicting installation, return `workflow-inconsistent` without writes. `--force` is allowed only after explicit user approval.
|
|
30
|
+
|
|
31
|
+
For an uninitialized project, generate repository inventory and context artifacts from the first read-only scan snapshot. Do not let installer-generated `AGENTS.md`, `.gitignore`, Hook, skill, standard, or delivery files contaminate the observed pre-install codebase baseline.
|
|
32
|
+
|
|
33
|
+
When an active or dependency-ready runtime task exists, defer to its task contract and write no bootstrap artifacts. An `agent`-owned next action routes to checkpoint recovery. A `user`-owned next action returns the recorded question verbatim and forbids all task, checkpoint, artifact, formal-state, and Git mutation until the user answers. An `external`-owned next action reports the wait condition and also forbids mutation. Read-only inspection must return `mutation_allowed: false` for the latter two cases.
|
|
34
|
+
|
|
35
|
+
For a newly initialized project or a ready project without a recoverable task, create one timestamped run under:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
.workflow/delivery/bootstrap/
|
|
39
|
+
latest.yaml
|
|
40
|
+
runs/<bootstrap-run-id>/
|
|
41
|
+
project-state-report.yaml
|
|
42
|
+
repository-baseline.yaml
|
|
43
|
+
codebase-inventory.csv
|
|
44
|
+
context-index.csv
|
|
45
|
+
adoption-assessment.md
|
|
46
|
+
bootstrap-plan.yaml
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Register `project-state-report.yaml` through `.workflow/tools/state/state.mjs artifact register`. Keep every generated artifact `draft`. Bootstrap code must call the shared formal-state module and must not parse and rewrite the registry itself.
|
|
50
|
+
|
|
51
|
+
## Artifact Meaning
|
|
52
|
+
|
|
53
|
+
- `project-state-report.yaml`: classification inputs, result, runtime state, errors, and recommendation.
|
|
54
|
+
- `repository-baseline.yaml`: observed Git identity, technologies, file categories, and candidate commands.
|
|
55
|
+
- `codebase-inventory.csv`: normalized observed manifests, source, tests, build, configuration, deployment, and infrastructure files.
|
|
56
|
+
- `context-index.csv`: path, category, technology, purpose, size, checksum, read priority, and scan status.
|
|
57
|
+
- `adoption-assessment.md`: Chinese human-readable gaps and the boundary between observed behavior and approved intent.
|
|
58
|
+
- `bootstrap-plan.yaml`: proposed next tasks, sequence, dependencies, and owning skills. It is planning input, not registered runtime state.
|
|
59
|
+
|
|
60
|
+
## Handoff
|
|
61
|
+
|
|
62
|
+
Natural-language startup is the public user interface. The AI must translate “开始”, “继续”, “下一步”, status questions, product ideas, and release intent into internal Skill and CLI calls; it must never delegate workflow command selection or execution to the user.
|
|
63
|
+
|
|
64
|
+
For a ready installation with no formal delivery artifact and no task shard, initialize the deterministic `INIT-0001` bootstrap/discovery task pair before writing product material. This is runtime state, unlike the draft tasks in `bootstrap-plan.yaml`. Resolve every shared task's code identity from the nested repository configured by `.workflow/config/workspace.yaml`, never from the install manifest or workflow repository.
|
|
65
|
+
|
|
66
|
+
For an empty project, hand off to `$ai-delivery-define-product` and ask for the problem to solve, target users, and success measure one decision at a time.
|
|
67
|
+
|
|
68
|
+
For a brownfield project, first let the user correct the observed repository context, then use product discovery to establish intended behavior. Do not route directly to development because code exists.
|
|
69
|
+
|
|
70
|
+
For a ready project without runtime tasks, use formal artifact and Gate state. A bootstrap diagnostic artifact does not count as delivery progress and must not prevent routing an otherwise empty project to product discovery.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ai-delivery-checkpoint-task
|
|
3
|
+
description: Persist, checkpoint, finish, recover, and archive version-scoped AI delivery task state independently of chat history, while correlating Codex lifecycle Hook events with the active task. Use before and after every delivery-stage execution, at meaningful milestones, before compaction or interruption, after a crash or restart, when a release-ready, released, or abandoned planned version must be archived, and whenever recorded state must be reconciled with Git and workspace reality.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Checkpoint Delivery Task
|
|
7
|
+
|
|
8
|
+
Treat explicit task snapshots as authoritative. Treat Hook events as an audit trail and heartbeat, never as proof that a stage completed.
|
|
9
|
+
|
|
10
|
+
## Artifact Location
|
|
11
|
+
|
|
12
|
+
Write portable task state to `.workflow/control/tasks/<task-id>.yaml` and `.workflow/control/checkpoints/<task-id>/<checkpoint-id>.yaml`. Keep only PID, heartbeat, temporary locks, raw Hook events, and unshared context under ignored `.workflow/delivery/runtime/`. Keep durable node documents under `.workflow/iterations/<iteration-id>/<node-id>/`; runtime snapshots never replace registered delivery artifacts. Resolve code branch and commit from `.workflow/config/workspace.yaml` and the nested code repository.
|
|
13
|
+
|
|
14
|
+
## Start Or Resume
|
|
15
|
+
|
|
16
|
+
1. Locate the project root and shared state root.
|
|
17
|
+
2. At iteration planning, register every known iteration task as `queued`, including its stable `sequence` and `depends_on` task IDs. When a later node derives a dynamic task group, register that complete group before executing its first task. This lets a restart distinguish completed work from work that has not started.
|
|
18
|
+
3. Read Bootstrap's `next_action_owner` before any recovery. Only when it is `agent`, run `scripts/task-state.mjs recover --iteration-id <iteration-id>` if runtime state exists and use `iterations[].recommended_task_id`; do not infer the next task from chat history. For `user` or `external`, apply the zero-mutation boundary in step 6 instead.
|
|
19
|
+
4. Compare the recommended task, branch, worktree, dirty paths, artifacts, dependencies, and evidence with reality.
|
|
20
|
+
5. Mark a stale `running` task `interrupted` only after reconciliation.
|
|
21
|
+
6. Read `next_action_owner` before activation. Activate a recommended `queued`, `preparing`, `checkpointed`, `blocked`, or `interrupted` task only when the owner is `agent`. When it is `user`, ask exactly the recorded question and make no workflow, task, checkpoint, artifact, or Git mutation. When it is `external`, report the recorded wait condition without mutation. After the required input arrives, transfer ownership through `activate` with `--next-action-owner agent` and a new idempotent `--next-action`; this command atomically hydrates a missing local runtime snapshot from the shared shard before continuing.
|
|
22
|
+
7. Create or update the task snapshot before any stage mutation. Include goal, scope, input artifact versions, standards, branch, worktree, planned outputs, completed steps, blockers, and next action.
|
|
23
|
+
8. Refuse to start when the snapshot cannot be written atomically.
|
|
24
|
+
9. Publish one task with `task-state.mjs publish --task-id <id>`. It may commit only that task shard, its checkpoints, and task-owned artifacts; refuse unrelated dirty paths. Push only when the user explicitly supplies `--push`.
|
|
25
|
+
|
|
26
|
+
Use statuses `queued`, `preparing`, `running`, `checkpointed`, `pending-review`, `blocked`, `interrupted`, `completed`, `failed`, and `abandoned`.
|
|
27
|
+
|
|
28
|
+
## Checkpoint
|
|
29
|
+
|
|
30
|
+
Checkpoint after every externally meaningful milestone, before a long command, after test or review evidence, before context compaction, and before returning control. Keep `next_action` concrete and idempotent and set `next_action_owner` to `agent`, `user`, or `external`. Store decisions in their owning product, architecture, design, standard, or release artifact rather than in runtime notes alone. Repeated evidence references are idempotent and must remain unique.
|
|
31
|
+
|
|
32
|
+
## Finish
|
|
33
|
+
|
|
34
|
+
1. Validate expected outputs and update the artifact registry through `.workflow/tools/state/state.mjs`.
|
|
35
|
+
2. Record evidence, actual outputs, residual blockers, and the next workflow action.
|
|
36
|
+
3. Atomically set `completed`, `blocked`, `failed`, `interrupted`, or explicitly `abandoned`. Treat `completed`, `failed`, and `abandoned` as closed tasks and omit them from default recovery output without archiving them individually.
|
|
37
|
+
4. After the task snapshot succeeds, update formal workflow state only through `.workflow/tools/state/state.mjs`, then run its `verify` command.
|
|
38
|
+
5. Invoke `$ai-delivery-evolve-workflow evaluate --safe-point task` after the task and formal-state writes are complete. Apply any newly eligible extension only to the next task; do not change the task that just finished.
|
|
39
|
+
6. Never mark production deployment complete from a Hook event.
|
|
40
|
+
|
|
41
|
+
## Archive A Version
|
|
42
|
+
|
|
43
|
+
1. Use the iteration version as the archive unit; never archive one completed task independently.
|
|
44
|
+
2. Require version status `release-ready`, `released`, or `abandoned` and at least one completion evidence reference. Require `candidate_id` for `release-ready`; require `release_id` for `released`.
|
|
45
|
+
3. Refuse archival while any version task is queued, preparing, running, checkpointed, pending review, blocked, or interrupted.
|
|
46
|
+
4. Write the portable archive manifest, task snapshots, and shared checkpoints under `.workflow/control/archives/versions/<version-id>/`. Retain detailed local event, heartbeat, and recovery copies under ignored runtime by default; use `--portable-only` to omit that disposable, non-authoritative copy.
|
|
47
|
+
5. Only after the portable archive is complete, remove the version's shards from `.workflow/control/tasks/` and `.workflow/control/checkpoints/` and remove local active records. Normal recovery scans active collections only and must not load archived details, even with `--include-closed`.
|
|
48
|
+
|
|
49
|
+
## Recover
|
|
50
|
+
|
|
51
|
+
Use shared shards and the newest shared checkpoint as the portable recovery source. If local runtime is absent and `next_action_owner` is `agent`, `recover` restores it from shared state. For `user` or `external`, report the wait state without hydration; after the input arrives, `activate` performs the atomic hydration and owner transfer. If local and shared revisions or semantic checksums differ, stop for reconciliation. Inspect both Git repositories before resuming. Report pending `.workflow/delivery/runtime/evolution/pending/` events, but defer their evaluation until the recovered task reaches a safe point.
|
|
52
|
+
|
|
53
|
+
Generate a compact recovery report from snapshots, checkpoints, Hook events, Git, and workspace state. Return only non-closed tasks by default; use `--include-closed` only for an explicit audit. For each iteration, report total, completed, closed, remaining, active, queued, dependency-ready, and waiting tasks plus one deterministic `recommended_task_id`. Prefer an interrupted or active task; otherwise choose the lowest-sequence queued task whose dependencies are all `completed`. Resume only idempotent steps. Re-read production and external systems before any deployment recovery; never replay production deployment automatically.
|
|
54
|
+
|
|
55
|
+
## Hook Boundary
|
|
56
|
+
|
|
57
|
+
Use `scripts/hook-event.mjs` for redacted lifecycle events and heartbeats. It also dispatches schema 1 Evolution events to the guarded Evolution CLI. Copy it into `.workflow/tools/hooks/` and merge `assets/codex-hook-config.toml` into project `.codex/config.toml`. Require normal Codex Hook trust review; never bypass Hook trust. Trial warnings fail open; only checksum-approved blocking extensions may stop a transition.
|
|
58
|
+
|
|
59
|
+
## Writer Boundary
|
|
60
|
+
|
|
61
|
+
Use `scripts/task-state.mjs` as the only writer for runtime task snapshots, checkpoints, recovery state, active-task markers, and version archives. Use `.workflow/tools/state/state.mjs` as the only writer for formal workflow, artifact, and Gate state. Use `.workflow/tools/evolution/evolve.mjs` as the only writer for feedback, proposal, extension, experiment, and evolution-decision state. Never hand-edit controlled files or let a Hook mutate formal state. If a script fails, stop and repair the cause.
|
|
62
|
+
|
|
63
|
+
Read [checkpoint-contract.md](references/checkpoint-contract.md) for commands, state fields, recovery rules, and the verified Codex 0.144.2 event set. Read [checkpoint-recovery.zh-CN.md](references/checkpoint-recovery.zh-CN.md) for the ten-task interruption example and file responsibilities. Use the templates in `assets/runtime-template/`.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
[features]
|
|
2
|
+
hooks = true
|
|
3
|
+
|
|
4
|
+
[[hooks.SessionStart]]
|
|
5
|
+
matcher = ""
|
|
6
|
+
[[hooks.SessionStart.hooks]]
|
|
7
|
+
type = "command"
|
|
8
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
9
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
10
|
+
timeout = 5
|
|
11
|
+
async = false
|
|
12
|
+
|
|
13
|
+
[[hooks.UserPromptSubmit]]
|
|
14
|
+
matcher = ""
|
|
15
|
+
[[hooks.UserPromptSubmit.hooks]]
|
|
16
|
+
type = "command"
|
|
17
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
18
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
19
|
+
timeout = 5
|
|
20
|
+
async = false
|
|
21
|
+
|
|
22
|
+
[[hooks.PreToolUse]]
|
|
23
|
+
matcher = ""
|
|
24
|
+
[[hooks.PreToolUse.hooks]]
|
|
25
|
+
type = "command"
|
|
26
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
27
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
28
|
+
timeout = 5
|
|
29
|
+
async = false
|
|
30
|
+
|
|
31
|
+
[[hooks.PermissionRequest]]
|
|
32
|
+
matcher = ""
|
|
33
|
+
[[hooks.PermissionRequest.hooks]]
|
|
34
|
+
type = "command"
|
|
35
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
36
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
37
|
+
timeout = 5
|
|
38
|
+
async = false
|
|
39
|
+
|
|
40
|
+
[[hooks.PostToolUse]]
|
|
41
|
+
matcher = ""
|
|
42
|
+
[[hooks.PostToolUse.hooks]]
|
|
43
|
+
type = "command"
|
|
44
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
45
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
46
|
+
timeout = 5
|
|
47
|
+
async = false
|
|
48
|
+
|
|
49
|
+
[[hooks.PreCompact]]
|
|
50
|
+
matcher = ""
|
|
51
|
+
[[hooks.PreCompact.hooks]]
|
|
52
|
+
type = "command"
|
|
53
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
54
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
55
|
+
timeout = 5
|
|
56
|
+
async = false
|
|
57
|
+
|
|
58
|
+
[[hooks.PostCompact]]
|
|
59
|
+
matcher = ""
|
|
60
|
+
[[hooks.PostCompact.hooks]]
|
|
61
|
+
type = "command"
|
|
62
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
63
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
64
|
+
timeout = 5
|
|
65
|
+
async = false
|
|
66
|
+
|
|
67
|
+
[[hooks.SubagentStart]]
|
|
68
|
+
matcher = ""
|
|
69
|
+
[[hooks.SubagentStart.hooks]]
|
|
70
|
+
type = "command"
|
|
71
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
72
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
73
|
+
timeout = 5
|
|
74
|
+
async = false
|
|
75
|
+
|
|
76
|
+
[[hooks.SubagentStop]]
|
|
77
|
+
matcher = ""
|
|
78
|
+
[[hooks.SubagentStop.hooks]]
|
|
79
|
+
type = "command"
|
|
80
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
81
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
82
|
+
timeout = 5
|
|
83
|
+
async = false
|
|
84
|
+
|
|
85
|
+
[[hooks.Stop]]
|
|
86
|
+
matcher = ""
|
|
87
|
+
[[hooks.Stop.hooks]]
|
|
88
|
+
type = "command"
|
|
89
|
+
command = "node .workflow/tools/hooks/hook-event.mjs"
|
|
90
|
+
commandWindows = "node .workflow/tools/hooks/hook-event.mjs"
|
|
91
|
+
timeout = 5
|
|
92
|
+
async = false
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Task Recovery
|
|
2
|
+
|
|
3
|
+
## Objective
|
|
4
|
+
|
|
5
|
+
## Recorded State
|
|
6
|
+
|
|
7
|
+
## Reconciled Workspace And Git State
|
|
8
|
+
|
|
9
|
+
## Completed Work And Evidence
|
|
10
|
+
|
|
11
|
+
## Blockers And Risks
|
|
12
|
+
|
|
13
|
+
## Next Idempotent Action
|
|
14
|
+
|
|
15
|
+
## Actions Requiring Fresh Readback Or Human Authority
|