lee-spec-kit 0.6.5 → 0.6.7

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.
Files changed (2) hide show
  1. package/dist/index.js +64 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7,8 +7,8 @@ import prompts from 'prompts';
7
7
  import chalk6 from 'chalk';
8
8
  import { glob } from 'glob';
9
9
  import { spawn, execSync, spawnSync, execFileSync } from 'child_process';
10
- import { createHash } from 'crypto';
11
10
  import os from 'os';
11
+ import { createHash } from 'crypto';
12
12
 
13
13
  var getFilename = () => fileURLToPath(import.meta.url);
14
14
  var getDirname = () => path18.dirname(getFilename());
@@ -396,8 +396,8 @@ var I18N = {
396
396
  issueCreateAndWrite: "`npx lee-spec-kit docs get create-issue --json`\uC73C\uB85C \uC808\uCC28\uB97C \uD655\uC778\uD55C \uB4A4, `npx lee-spec-kit github issue {featureRef} --json`\uC73C\uB85C \uCD08\uC548\uC744 \uC0DD\uC131\uD558\uC138\uC694. \uBAA9\uD45C/\uC644\uB8CC \uAE30\uC900\uC744 \uAC80\uD1A0\xB7\uBCF4\uC644\uD558\uACE0 \uC0AC\uC6A9\uC790 \uC2B9\uC778(OK) \uD6C4 `--create --confirm OK`\uB85C \uC0DD\uC131\uD55C \uB2E4\uC74C, spec.md/tasks.md\uC758 \uC774\uC288 \uBC88\uD638\uB97C \uCC44\uC6B0\uACE0 \uBB38\uC11C \uCEE4\uBC0B\uC744 \uC900\uBE44\uD558\uC138\uC694.",
397
397
  docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
398
398
  docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8"',
399
- projectCommitIssueUpdate: 'cd "{projectGitCwd}" && git add -A && git commit -m "feat(#{issueNumber}): {folderName} \uAD6C\uD604 \uC5C5\uB370\uC774\uD2B8"',
400
- projectCommitUpdate: 'cd "{projectGitCwd}" && git add -A && git commit -m "feat: {folderName} \uAD6C\uD604 \uC5C5\uB370\uC774\uD2B8"',
399
+ projectCommitIssueUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "\uC2A4\uD14C\uC774\uC9D5\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774\uBC88 \uD0DC\uC2A4\uD06C\uC5D0\uC11C \uC218\uC815\uD55C \uD30C\uC77C\uB9CC \uC120\uD0DD\uD574 git add [files] \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694." && exit 1 || git commit -m "feat(#{issueNumber}): {commitTopic}")',
400
+ projectCommitUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "\uC2A4\uD14C\uC774\uC9D5\uB41C \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774\uBC88 \uD0DC\uC2A4\uD06C\uC5D0\uC11C \uC218\uC815\uD55C \uD30C\uC77C\uB9CC \uC120\uD0DD\uD574 git add [files] \uD6C4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694." && exit 1 || git commit -m "feat({folderName}): {commitTopic}")',
401
401
  standaloneNeedsProjectRoot: "standalone \uBAA8\uB4DC\uC5D0\uC11C\uB294 projectRoot \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4. (npx lee-spec-kit config --project-root ...)",
402
402
  createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
403
403
  tasksAllDoneButNoChecklist: '\uBAA8\uB4E0 \uD0DC\uC2A4\uD06C\uAC00 DONE\uC774\uC9C0\uB9CC \uC644\uB8CC \uC870\uAC74 \uCCB4\uD06C\uB9AC\uC2A4\uD2B8 \uC139\uC158\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. tasks.md\uC758 "\uC644\uB8CC \uC870\uAC74" \uC139\uC158\uC744 \uCD94\uAC00/\uD655\uC778\uD558\uC138\uC694.',
@@ -772,8 +772,8 @@ var I18N = {
772
772
  issueCreateAndWrite: "Review procedure with `npx lee-spec-kit docs get create-issue --json`, then generate a draft via `npx lee-spec-kit github issue {featureRef} --json`. Refine goals/completion criteria, get explicit user OK, run `--create --confirm OK`, then update issue number in spec.md/tasks.md and prepare a docs commit.",
773
773
  docsCommitIssueUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs(#{issueNumber}): {folderName} docs update"',
774
774
  docsCommitUpdate: 'cd "{docsGitCwd}" && git add "{featurePath}" && git commit -m "docs: {folderName} docs update"',
775
- projectCommitIssueUpdate: 'cd "{projectGitCwd}" && git add -A && git commit -m "feat(#{issueNumber}): {folderName} implementation update"',
776
- projectCommitUpdate: 'cd "{projectGitCwd}" && git add -A && git commit -m "feat: {folderName} implementation update"',
775
+ projectCommitIssueUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "No staged files. Stage only files changed in this task with git add [files], then run again." && exit 1 || git commit -m "feat(#{issueNumber}): {commitTopic}")',
776
+ projectCommitUpdate: 'cd "{projectGitCwd}" && (git diff --cached --quiet && echo "No staged files. Stage only files changed in this task with git add [files], then run again." && exit 1 || git commit -m "feat({folderName}): {commitTopic}")',
777
777
  standaloneNeedsProjectRoot: "Standalone mode requires projectRoot. (npx lee-spec-kit config --project-root ...)",
778
778
  createBranch: 'cd "{projectGitCwd}" && git checkout -b feat/{issueNumber}-{slug}',
779
779
  tasksAllDoneButNoChecklist: 'All tasks are DONE, but no completion checklist section was found. Add/verify the "Completion Criteria" section in tasks.md.',
@@ -1211,6 +1211,27 @@ function getInitLockPath(targetDir) {
1211
1211
  `.lee-spec-kit.${path18.basename(targetDir)}.lock`
1212
1212
  );
1213
1213
  }
1214
+ function getTempProjectLockPath(cwd) {
1215
+ const key = createHash("sha1").update(path18.resolve(cwd)).digest("hex");
1216
+ return path18.join(os.tmpdir(), "lee-spec-kit-locks", `${key}.project.lock`);
1217
+ }
1218
+ function getProjectExecutionLockPath(cwd) {
1219
+ try {
1220
+ const out = execFileSync(
1221
+ "git",
1222
+ ["rev-parse", "--git-path", "lee-spec-kit.project.lock"],
1223
+ {
1224
+ cwd,
1225
+ encoding: "utf-8",
1226
+ stdio: ["ignore", "pipe", "ignore"]
1227
+ }
1228
+ ).trim();
1229
+ if (!out) return getTempProjectLockPath(cwd);
1230
+ return path18.isAbsolute(out) ? out : path18.resolve(cwd, out);
1231
+ } catch {
1232
+ return getTempProjectLockPath(cwd);
1233
+ }
1234
+ }
1214
1235
  async function isStaleLock(lockPath, staleMs) {
1215
1236
  try {
1216
1237
  const stat = await fs14.stat(lockPath);
@@ -2473,6 +2494,21 @@ function formatSkillList(skills) {
2473
2494
  function getFindingsPolicyText(lang, blockOnFindings) {
2474
2495
  return blockOnFindings ? tr(lang, "messages", "prePrReviewFindingsBlock") : tr(lang, "messages", "prePrReviewFindingsWarn");
2475
2496
  }
2497
+ function normalizeCommitTopicText(value) {
2498
+ return value.replace(/\s+/g, " ").trim();
2499
+ }
2500
+ function toShellSafeCommitTopic(value) {
2501
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\$/g, "\\$").replace(/`/g, "\\`");
2502
+ }
2503
+ function resolveProjectCommitTopic(feature) {
2504
+ const raw = feature.activeTask?.title || feature.lastDoneTask?.title || feature.nextTodoTask?.title || feature.folderName;
2505
+ const withoutTaskId = normalizeCommitTopicText(raw).replace(
2506
+ /^T-[A-Za-z0-9-]+\s+/,
2507
+ ""
2508
+ );
2509
+ const topic = withoutTaskId || normalizeCommitTopicText(feature.folderName);
2510
+ return toShellSafeCommitTopic(topic);
2511
+ }
2476
2512
  function getStepDefinitions(lang, workflow) {
2477
2513
  const workflowPolicy = resolveWorkflowPolicy(workflow);
2478
2514
  const prePrReviewPolicy = resolvePrePrReviewPolicy(workflow);
@@ -2796,10 +2832,12 @@ function getStepDefinitions(lang, workflow) {
2796
2832
  cmd: f.issueNumber ? tr(lang, "messages", "projectCommitIssueUpdate", {
2797
2833
  projectGitCwd: f.git.projectGitCwd,
2798
2834
  issueNumber: f.issueNumber,
2799
- folderName: f.folderName
2835
+ folderName: f.folderName,
2836
+ commitTopic: resolveProjectCommitTopic(f)
2800
2837
  }) : tr(lang, "messages", "projectCommitUpdate", {
2801
2838
  projectGitCwd: f.git.projectGitCwd,
2802
- folderName: f.folderName
2839
+ folderName: f.folderName,
2840
+ commitTopic: resolveProjectCommitTopic(f)
2803
2841
  })
2804
2842
  }
2805
2843
  ];
@@ -2880,10 +2918,12 @@ function getStepDefinitions(lang, workflow) {
2880
2918
  cmd: f.issueNumber ? tr(lang, "messages", "projectCommitIssueUpdate", {
2881
2919
  projectGitCwd: f.git.projectGitCwd,
2882
2920
  issueNumber: f.issueNumber,
2883
- folderName: f.folderName
2921
+ folderName: f.folderName,
2922
+ commitTopic: resolveProjectCommitTopic(f)
2884
2923
  }) : tr(lang, "messages", "projectCommitUpdate", {
2885
2924
  projectGitCwd: f.git.projectGitCwd,
2886
- folderName: f.folderName
2925
+ folderName: f.folderName,
2926
+ commitTopic: resolveProjectCommitTopic(f)
2887
2927
  })
2888
2928
  }
2889
2929
  ];
@@ -3399,6 +3439,7 @@ async function resolveComponentStatusPaths(projectGitCwd, component, workflow) {
3399
3439
  function parseTasks(content) {
3400
3440
  const summary = { total: 0, todo: 0, doing: 0, done: 0 };
3401
3441
  let activeTask;
3442
+ let lastDoneTask;
3402
3443
  let nextTodoTask;
3403
3444
  const lines = content.split("\n");
3404
3445
  let inCodeBlock = false;
@@ -3419,11 +3460,14 @@ function parseTasks(content) {
3419
3460
  if (!activeTask && (status === "DOING" || status === "REVIEW")) {
3420
3461
  activeTask = { status, title };
3421
3462
  }
3463
+ if (status === "DONE") {
3464
+ lastDoneTask = { status: "DONE", title };
3465
+ }
3422
3466
  if (!nextTodoTask && status === "TODO") {
3423
3467
  nextTodoTask = { status: "TODO", title };
3424
3468
  }
3425
3469
  }
3426
- return { summary, activeTask, nextTodoTask };
3470
+ return { summary, activeTask, lastDoneTask, nextTodoTask };
3427
3471
  }
3428
3472
  function parseCompletionChecklist(content) {
3429
3473
  const lines = content.split("\n");
@@ -3480,6 +3524,7 @@ async function parseFeature(featurePath, type, context, options) {
3480
3524
  const tasksExists = await fs14.pathExists(tasksPath);
3481
3525
  const tasksSummary = { total: 0, todo: 0, doing: 0, done: 0 };
3482
3526
  let activeTask;
3527
+ let lastDoneTask;
3483
3528
  let nextTodoTask;
3484
3529
  let tasksDocStatus;
3485
3530
  let tasksDocStatusFieldExists = false;
@@ -3492,12 +3537,18 @@ async function parseFeature(featurePath, type, context, options) {
3492
3537
  let prePrReviewFieldExists = false;
3493
3538
  if (tasksExists) {
3494
3539
  const content = await fs14.readFile(tasksPath, "utf-8");
3495
- const { summary, activeTask: active, nextTodoTask: nextTodo } = parseTasks(content);
3540
+ const {
3541
+ summary,
3542
+ activeTask: active,
3543
+ lastDoneTask: lastDone,
3544
+ nextTodoTask: nextTodo
3545
+ } = parseTasks(content);
3496
3546
  tasksSummary.total = summary.total;
3497
3547
  tasksSummary.todo = summary.todo;
3498
3548
  tasksSummary.doing = summary.doing;
3499
3549
  tasksSummary.done = summary.done;
3500
3550
  activeTask = active;
3551
+ lastDoneTask = lastDone;
3501
3552
  nextTodoTask = nextTodo;
3502
3553
  completionChecklist = parseCompletionChecklist(content);
3503
3554
  if (!issueNumber) {
@@ -3671,6 +3722,7 @@ async function parseFeature(featurePath, type, context, options) {
3671
3722
  tasksDocStatus,
3672
3723
  tasks: tasksSummary,
3673
3724
  activeTask,
3725
+ lastDoneTask,
3674
3726
  nextTodoTask,
3675
3727
  completionChecklist,
3676
3728
  prePrReview: {
@@ -4936,7 +4988,7 @@ function getCommandExecutionLockPath(action, config) {
4936
4988
  if (action.scope === "docs") {
4937
4989
  return getDocsLockPath(config.docsDir);
4938
4990
  }
4939
- return path18.join(action.cwd, ".lee-spec-kit.project.lock");
4991
+ return getProjectExecutionLockPath(action.cwd);
4940
4992
  }
4941
4993
  function contextCommand(program2) {
4942
4994
  program2.command("context [feature-name]").description("Show current feature context and next actions").option("--json", "Output in JSON format for agents").option("--repo <repo>", "Component name for multi projects").option("--component <component>", "Component name for multi projects").option("--all", "Include completed features when auto-detecting").option("--done", "Show completed (workflow-done) features only").option("--approve <reply>", "Approve one labeled option: A or A OK").option("--execute", "Execute approved option when it is a command").option(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lee-spec-kit",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "description": "Project documentation structure generator for AI-assisted development",
5
5
  "type": "module",
6
6
  "bin": {