lee-spec-kit 0.8.4 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +55 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1299,7 +1299,7 @@ Before taking the next workflow step:
|
|
|
1299
1299
|
9. In standalone mode, use the project repo through its managed feature worktree under the shared workspace \`.worktrees/\` root instead of checking the feature branch out in the main project repo
|
|
1300
1300
|
10. In standalone mode, do not hand-write \`git worktree add\`; run the exact \`nextAction.command\` from \`workflow-stage\` so the managed workspace path, stale directory cleanup, and \`.env\` / \`.env.*\` copy step stay consistent
|
|
1301
1301
|
11. Keep docs and code synchronized; if code changes materially, update the active feature docs in the same turn before stopping
|
|
1302
|
-
12. When docs are synced to code,
|
|
1302
|
+
12. When docs are synced to code, keep exactly one explicit marker like \`<!-- lee-spec-kit:workflow-sync 2026-04-16T12:34:56.789Z -->\` in a single active feature doc (prefer \`tasks.md\` or \`decisions.md\`): replace an existing marker timestamp or remove duplicates instead of appending another marker, so \`workflow-audit\` can prove the sync happened after the latest code change
|
|
1303
1303
|
|
|
1304
1304
|
Approval and remote actions:
|
|
1305
1305
|
|
|
@@ -1314,7 +1314,7 @@ Approval and remote actions:
|
|
|
1314
1314
|
Validation:
|
|
1315
1315
|
|
|
1316
1316
|
- Prefer \`npx lee-spec-kit commit-audit --json\` for commit-time staged docs path validation
|
|
1317
|
-
- Prefer \`npx lee-spec-kit workflow-audit --json\` as the default docs-sync validator for Codex hooks and end-of-turn checks; it expects the active feature docs to carry
|
|
1317
|
+
- Prefer \`npx lee-spec-kit workflow-audit --json\` as the default docs-sync validator for Codex hooks and end-of-turn checks; it expects the active feature docs to carry one fresh \`lee-spec-kit:workflow-sync\` marker after meaningful code/doc sync
|
|
1318
1318
|
`;
|
|
1319
1319
|
function renderManagedSegment(lang, docsRepo) {
|
|
1320
1320
|
return `${LEE_SPEC_KIT_AGENTS_BEGIN}
|
|
@@ -7887,7 +7887,7 @@ function buildPostMergeCleanupCommand(state) {
|
|
|
7887
7887
|
}
|
|
7888
7888
|
if (state.worktreePath) {
|
|
7889
7889
|
commandParts.push(
|
|
7890
|
-
`if [ -d "${state.worktreePath}" ]; then git -C "${state.projectRootGitCwd}" worktree remove "${state.worktreePath}"; fi`
|
|
7890
|
+
`if [ -d "${state.worktreePath}" ]; then if git -C "${state.worktreePath}" rev-parse --is-inside-work-tree >/dev/null 2>&1; then meaningful_changes=$(git -C "${state.worktreePath}" status --porcelain --untracked-files=normal 2>/dev/null || true); if [ -n "$meaningful_changes" ]; then printf '%s\\n' "Managed worktree has tracked or meaningful untracked changes; refusing cleanup: ${state.worktreePath}" >&2; exit 1; fi; git -C "${state.projectRootGitCwd}" worktree remove --force "${state.worktreePath}" || { git -C "${state.projectRootGitCwd}" worktree prune; rm -rf "${state.worktreePath}"; }; else leftover_meaningful=$(find "${state.worktreePath}" -mindepth 1 \\( -name ".next" -o -name "node_modules" -o -name "storybook-static" -o -name "dist" -o -name "build" -o -name "coverage" -o -name ".turbo" -o -name ".cache" \\) -prune -o -print -quit); if [ -n "$leftover_meaningful" ]; then printf '%s\\n' "Managed worktree leftover has files outside generated artifact directories; refusing cleanup: ${state.worktreePath}" >&2; exit 1; fi; git -C "${state.projectRootGitCwd}" worktree prune; rm -rf "${state.worktreePath}"; fi; fi`
|
|
7891
7891
|
);
|
|
7892
7892
|
}
|
|
7893
7893
|
if (state.headBranch) {
|
|
@@ -7896,7 +7896,7 @@ function buildPostMergeCleanupCommand(state) {
|
|
|
7896
7896
|
);
|
|
7897
7897
|
if (state.hasOriginRemote) {
|
|
7898
7898
|
commandParts.push(
|
|
7899
|
-
`if git -C "${state.projectRootGitCwd}" show-ref --verify --quiet "refs/remotes/origin/${state.headBranch}"; then git -C "${state.projectRootGitCwd}" push origin --delete "${state.headBranch}"; fi`
|
|
7899
|
+
`if git -C "${state.projectRootGitCwd}" show-ref --verify --quiet "refs/remotes/origin/${state.headBranch}"; then HUSKY=0 git -C "${state.projectRootGitCwd}" push origin --delete "${state.headBranch}"; fi`
|
|
7900
7900
|
);
|
|
7901
7901
|
commandParts.push(
|
|
7902
7902
|
`git -C "${state.projectRootGitCwd}" fetch --prune origin`
|
|
@@ -8100,14 +8100,15 @@ function resolveCurrentReviewState(tasks, prDraft, remoteReviewState) {
|
|
|
8100
8100
|
}
|
|
8101
8101
|
return "unknown";
|
|
8102
8102
|
}
|
|
8103
|
-
function buildCodeReviewActionOptions(reviewState) {
|
|
8103
|
+
function buildCodeReviewActionOptions(reviewState, reviewSyncCommand = null) {
|
|
8104
8104
|
if (reviewState === "merged") {
|
|
8105
8105
|
return [
|
|
8106
8106
|
buildStageOption(
|
|
8107
8107
|
"A",
|
|
8108
8108
|
"A",
|
|
8109
8109
|
"review_sync_approved",
|
|
8110
|
-
"Sync the already-merged PR state into tasks.md and pr.md before closing the feature."
|
|
8110
|
+
"Sync the already-merged PR state into tasks.md and pr.md before closing the feature.",
|
|
8111
|
+
reviewSyncCommand
|
|
8111
8112
|
),
|
|
8112
8113
|
buildStageOption(
|
|
8113
8114
|
"B",
|
|
@@ -8123,7 +8124,8 @@ function buildCodeReviewActionOptions(reviewState) {
|
|
|
8123
8124
|
"A",
|
|
8124
8125
|
"A",
|
|
8125
8126
|
"review_sync_approved",
|
|
8126
|
-
"Sync the approved PR review state into tasks.md and pr.md, then continue to the merge gate."
|
|
8127
|
+
"Sync the approved PR review state into tasks.md and pr.md, then continue to the merge gate.",
|
|
8128
|
+
reviewSyncCommand
|
|
8127
8129
|
),
|
|
8128
8130
|
buildStageOption(
|
|
8129
8131
|
"B",
|
|
@@ -8672,7 +8674,8 @@ Task commit boundary warning: ${describeTaskCommitGateFailure(committedTaskGate)
|
|
|
8672
8674
|
if (requirements.requireReview && (!reviewApprovedInDocs || currentReviewState !== "approved")) {
|
|
8673
8675
|
const reviewFixAllowed = currentReviewState === "changes_requested";
|
|
8674
8676
|
const reviewApprovalRequired = !reviewFixAllowed;
|
|
8675
|
-
const
|
|
8677
|
+
const reviewSyncCommand = currentReviewState === "merged" ? `npx lee-spec-kit github pr ${buildFeatureArgs(feature)} --merge --confirm OK` : null;
|
|
8678
|
+
const reviewActionOptions = reviewApprovalRequired ? buildCodeReviewActionOptions(currentReviewState, reviewSyncCommand) : void 0;
|
|
8676
8679
|
const reviewSummary = currentReviewState === "approved" ? "Record the approved PR review state in tasks.md and pr.md before proceeding to merge." : currentReviewState === "merged" ? "Sync the already-merged PR state into tasks.md and pr.md before marking the workflow as complete." : currentReviewState === "changes_requested" ? "Address the requested review changes and update the PR review evidence/decision before continuing." : currentReviewState === "review_pending_latest_commit" ? "Wait for a fresh review on the latest PR commit before taking the next review action." : currentReviewState === "review_rate_limited" ? "Wait for the current CodeRabbit review rate limit to clear, then re-check the latest PR review state before continuing." : currentReviewState === "draft" ? "Resolve the draft PR state before continuing to the merge boundary." : currentReviewState === "merge_blocked" ? "Resolve the current PR merge blocker before continuing to merge." : "Wait for PR review or inspect the current review state before taking the next review action.";
|
|
8677
8680
|
return {
|
|
8678
8681
|
status: "ok",
|
|
@@ -8683,7 +8686,8 @@ Task commit boundary warning: ${describeTaskCommitGateFailure(committedTaskGate)
|
|
|
8683
8686
|
nextAction: buildAction(
|
|
8684
8687
|
"code_review",
|
|
8685
8688
|
reviewSummary,
|
|
8686
|
-
reviewApprovalRequired
|
|
8689
|
+
reviewApprovalRequired,
|
|
8690
|
+
reviewSyncCommand
|
|
8687
8691
|
),
|
|
8688
8692
|
approvalRequired: reviewApprovalRequired,
|
|
8689
8693
|
implementationAllowed: reviewFixAllowed,
|
|
@@ -9105,7 +9109,20 @@ async function collectWorkflowAudit(cwd) {
|
|
|
9105
9109
|
const allMeaningfulFeatureDocPaths = meaningfulChangedFeatureDocPaths;
|
|
9106
9110
|
const latestCodeChangeAt = await getLatestMtimeIso(combinedChangedCodePaths);
|
|
9107
9111
|
const latestFeatureDocSyncAt = await getLatestWorkflowSyncMarkerAt(activeFeature);
|
|
9112
|
+
const duplicateWorkflowSyncMarkerPaths = await collectDuplicateWorkflowSyncMarkerPaths(activeFeature);
|
|
9108
9113
|
if (combinedChangedCodePaths.length === 0) {
|
|
9114
|
+
if (duplicateWorkflowSyncMarkerPaths.length > 0) {
|
|
9115
|
+
return {
|
|
9116
|
+
status: "needs_sync",
|
|
9117
|
+
reasonCode: "DUPLICATE_WORKFLOW_SYNC_MARKERS",
|
|
9118
|
+
docsDir: config.docsDir,
|
|
9119
|
+
activeFeatureRef,
|
|
9120
|
+
changedCodePaths: [],
|
|
9121
|
+
changedFeatureDocPaths: duplicateWorkflowSyncMarkerPaths,
|
|
9122
|
+
latestCodeChangeAt: null,
|
|
9123
|
+
latestFeatureDocSyncAt
|
|
9124
|
+
};
|
|
9125
|
+
}
|
|
9109
9126
|
return {
|
|
9110
9127
|
status: "ok",
|
|
9111
9128
|
reasonCode: "WORKFLOW_IN_SYNC",
|
|
@@ -9117,6 +9134,18 @@ async function collectWorkflowAudit(cwd) {
|
|
|
9117
9134
|
latestFeatureDocSyncAt
|
|
9118
9135
|
};
|
|
9119
9136
|
}
|
|
9137
|
+
if (duplicateWorkflowSyncMarkerPaths.length > 0) {
|
|
9138
|
+
return {
|
|
9139
|
+
status: "needs_sync",
|
|
9140
|
+
reasonCode: "DUPLICATE_WORKFLOW_SYNC_MARKERS",
|
|
9141
|
+
docsDir: config.docsDir,
|
|
9142
|
+
activeFeatureRef,
|
|
9143
|
+
changedCodePaths: combinedChangedCodePaths.map((item) => item.relativeToRepo),
|
|
9144
|
+
changedFeatureDocPaths: duplicateWorkflowSyncMarkerPaths,
|
|
9145
|
+
latestCodeChangeAt,
|
|
9146
|
+
latestFeatureDocSyncAt
|
|
9147
|
+
};
|
|
9148
|
+
}
|
|
9120
9149
|
if (!activeFeatureRef) {
|
|
9121
9150
|
return {
|
|
9122
9151
|
status: "needs_sync",
|
|
@@ -9242,6 +9271,23 @@ async function getLatestWorkflowSyncMarkerAt(activeFeature) {
|
|
|
9242
9271
|
}
|
|
9243
9272
|
return latest > 0 ? new Date(latest).toISOString() : null;
|
|
9244
9273
|
}
|
|
9274
|
+
async function collectDuplicateWorkflowSyncMarkerPaths(activeFeature) {
|
|
9275
|
+
if (!activeFeature) return [];
|
|
9276
|
+
const canonicalFiles = ["spec.md", "plan.md", "tasks.md", "decisions.md", "issue.md", "pr.md"];
|
|
9277
|
+
const markerPaths = [];
|
|
9278
|
+
let markerCount = 0;
|
|
9279
|
+
for (const fileName of canonicalFiles) {
|
|
9280
|
+
const absolutePath = path8.join(activeFeature.path, fileName);
|
|
9281
|
+
if (!await fs.pathExists(absolutePath)) continue;
|
|
9282
|
+
const content = await fs.readFile(absolutePath, "utf-8");
|
|
9283
|
+
const matches = [...content.matchAll(WORKFLOW_SYNC_MARKER_PATTERN)];
|
|
9284
|
+
if (matches.length > 0) {
|
|
9285
|
+
markerCount += matches.length;
|
|
9286
|
+
markerPaths.push(normalizeSlashes2(path8.relative(activeFeature.path, absolutePath)));
|
|
9287
|
+
}
|
|
9288
|
+
}
|
|
9289
|
+
return markerCount > 1 ? markerPaths : [];
|
|
9290
|
+
}
|
|
9245
9291
|
function extractWorkflowSyncMarkerTimes(content, nowMs, fileMtimeMs) {
|
|
9246
9292
|
const values = [];
|
|
9247
9293
|
for (const match of content.matchAll(WORKFLOW_SYNC_MARKER_PATTERN)) {
|