@litfamily/litclaude 1.0.27 → 1.0.28

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.28 - 2026-10-14
4
+
5
+ - A new lit-loop no longer shows every stage of the card's workflow map as done when an older goal in the project had already finished. The finished goal now ends the map only when it finished after the current stage was recorded, so the map follows the work you are doing now; a goal that really finishes still shows done.
6
+ - `litclaude-ai` is now on the Bash PATH after a plugin install, so the documented `litclaude-ai litgoal`, `start-work`, `workflow-stage` and similar commands run without the npm package. Other subcommands point you at the npm package.
7
+ - The start-work gate lets its own `start-work pause` through when it names an outside target root. The pause records a pending boundary and grants nothing; forbidden actions are still refused.
8
+
3
9
  ## 1.0.27 - 2026-10-13
4
10
 
5
11
  - The lit-loop map now moves when the work happens in the shell. Writing a test with a shell command (`cat > test/…`, `>>`, `tee` or `sed -i`) turns the map to RED, changing a source file the same way turns it to GREEN, and the next test run turns it to VERIFY. A failing test run while the criterion is still pinned also counts as RED, including a bare `npm test` that exits with an error. The card keeps only the stage, never the command or the file names.
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
- <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion.webp" width="100%" alt="LitFamily motion cover: five armored robots power on one by one, the LitClaude robot wakes with glowing eyes and a lit frame, then LITFAMILY and KEEP THE WORK LIT. light up." /></picture></p>
1
+ <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/cover-motion.webp" width="100%" alt="LitFamily motion cover: five armored robots power on one by one, the LitClaude robot wakes with glowing eyes and a lit frame, then LITFAMILY and KEEP THE WORK LIT. light up." /></picture></p>
2
2
 
3
3
  <h1 align="center">LitClaude</h1>
4
4
  <p align="center"><strong>Keep the work lit.</strong></p>
5
5
  <p align="center">A Claude Code plugin that helps every session plan the work, build it, check it, and leave a note the next session can pick up.</p>
6
6
  <p align="center">
7
- <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-version.svg" alt="1.0.27" />
8
- <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
7
+ <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/readme/badge-version.svg" alt="1.0.28" />
8
+ <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
9
9
  </p>
10
10
  <p align="center">
11
- <a href="https://github.com/wjgoarxiv/litclaude#readme">Full guide and skills gallery on GitHub</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/README_ko-KR.md">한국어</a>
11
+ <a href="https://github.com/wjgoarxiv/litclaude#readme">Full guide and skills gallery on GitHub</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/README_ko-KR.md">한국어</a>
12
12
  </p>
13
13
 
14
14
  Add `lit` to a Claude Code prompt and Claude pins the goal, writes a failing test first,
@@ -73,7 +73,7 @@ the `/plugin` menu.
73
73
  ## More
74
74
 
75
75
  - [Full guide and skills gallery on GitHub](https://github.com/wjgoarxiv/litclaude#readme)
76
- - [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/privacy.md)
77
- - [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/migration.md)
78
- - [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/CHANGELOG.md)
79
- - [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE)
76
+ - [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/privacy.md)
77
+ - [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/migration.md)
78
+ - [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/CHANGELOG.md)
79
+ - [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/LICENSE)
package/README_ko-KR.md CHANGED
@@ -1,14 +1,14 @@
1
- <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/cover-motion.webp" width="100%" alt="LitFamily 모션 커버: 다섯 로봇 패널이 차례로 켜지고, LitClaude 로봇의 눈과 테두리가 빛난 뒤 LITFAMILY와 KEEP THE WORK LIT. 문구가 밝아지는 영상" /></picture></p>
1
+ <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/cover-motion.webp" width="100%" alt="LitFamily 모션 커버: 다섯 로봇 패널이 차례로 켜지고, LitClaude 로봇의 눈과 테두리가 빛난 뒤 LITFAMILY와 KEEP THE WORK LIT. 문구가 밝아지는 영상" /></picture></p>
2
2
 
3
3
  <h1 align="center">LitClaude</h1>
4
4
  <p align="center"><strong>Keep the work lit.</strong></p>
5
5
  <p align="center">Claude Code에서 세션마다 계획하고, 만들고, 확인한 뒤 다음 세션이 이어받을 기록을 남기게 돕는 플러그인입니다.</p>
6
6
  <p align="center">
7
- <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-version.svg" alt="1.0.27" />
8
- <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
7
+ <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/readme/badge-version.svg" alt="1.0.28" />
8
+ <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
9
9
  </p>
10
10
  <p align="center">
11
- <a href="https://github.com/wjgoarxiv/litclaude/blob/main/README_ko-KR.md">전체 안내와 스킬 갤러리는 GitHub에서</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/README.md">English</a>
11
+ <a href="https://github.com/wjgoarxiv/litclaude/blob/main/README_ko-KR.md">전체 안내와 스킬 갤러리는 GitHub에서</a> · <a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/README.md">English</a>
12
12
  </p>
13
13
 
14
14
  Claude Code 프롬프트에 `lit`을 붙이면 Claude가 목표를 고정하고, 실패하는 테스트를 먼저 쓰고,
@@ -71,7 +71,7 @@ LitClaude는 프로젝트 상태를 `.litclaude/`에 두고, 그 안의 `.gitign
71
71
  ## 더 보기
72
72
 
73
73
  - [전체 안내와 스킬 갤러리 (GitHub)](https://github.com/wjgoarxiv/litclaude/blob/main/README_ko-KR.md)
74
- - [개인정보와 네트워크 동작](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/privacy.md)
75
- - [이전과 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/docs/migration.md)
76
- - [변경 이력](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/CHANGELOG.md)
77
- - [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.27/LICENSE)
74
+ - [개인정보와 네트워크 동작](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/privacy.md)
75
+ - [이전과 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/docs/migration.md)
76
+ - [변경 이력](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/CHANGELOG.md)
77
+ - [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.28/LICENSE)
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.27"><title>release: 1.0.27</title><g shape-rendering="crispEdges"><rect width="49" height="20" fill="#080d14"/><rect x="49" width="97" height="20" fill="#ff6337"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="255" y="140" textLength="390" transform="scale(.1)">release</text><text x="965" y="140" textLength="870" transform="scale(.1)" fill="#080D14">1.0.27</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.28"><title>release: 1.0.28</title><g shape-rendering="crispEdges"><rect width="49" height="20" fill="#080d14"/><rect x="49" width="97" height="20" fill="#ff6337"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text x="255" y="140" textLength="390" transform="scale(.1)">release</text><text x="965" y="140" textLength="870" transform="scale(.1)" fill="#080D14">1.0.28</text></g></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litfamily/litclaude",
3
- "version": "1.0.27",
3
+ "version": "1.0.28",
4
4
  "description": "Claude Code plugin: add lit to a prompt and Claude plans, tests, checks and reviews the work, then leaves a handoff for the next session.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "litclaude",
3
3
  "description": "Claude Code-native workflow plugin with a bounded-authority start-work lifecycle.",
4
- "version": "1.0.27",
4
+ "version": "1.0.28",
5
5
  "author": {
6
6
  "name": "LitClaude contributors"
7
7
  },
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ // The `litclaude-ai` the skills and commands name, as the installed plugin serves it. Claude Code
3
+ // puts this bin/ directory on the Bash tool's PATH; the npm CLI (bin/litclaude-ai.js in the
4
+ // package) is usually not there. This entry runs the in-session subcommands from the plugin's own
5
+ // lib/ and sends everything else (install, doctor, update…) to the user's terminal.
6
+ //
7
+ // No file extension, so the bare name resolves on PATH; the code avoids `import`, `require`,
8
+ // `import.meta` and `module` so it runs whether Node loads it as CommonJS or as an ES module.
9
+
10
+ const SUBCOMMANDS = {
11
+ litgoal: async (load, rest) => (await load("../lib/litgoal/cli.mjs")).runLitgoalCli(rest),
12
+ "start-work": async (load, rest) => (await load("../lib/start-work-cli.mjs")).runStartWorkCli(rest, undefined, process.cwd()),
13
+ "start-work-next": async (load, rest) => {
14
+ const { resolveProjectStateRoot } = await load("../lib/project-state-root.mjs");
15
+ return (await load("../lib/start-work-continuation.mjs")).runStartWorkContinuationCli(resolveProjectStateRoot(process.cwd()), rest);
16
+ },
17
+ "workflow-stage": async (load, rest) => (await load("../lib/workflow-stage.mjs")).runWorkflowStageCli(rest, process.cwd()),
18
+ wikify: async (load, rest) => (await load("../lib/wikify-knowledge-cli.mjs")).runWikifyKnowledgeCli(rest, undefined, process.cwd()),
19
+ "motion-runtime": async (load, rest) => (await load("../skills/lit-typographic-motion/scripts/motion-runtime.mjs")).main(rest),
20
+ };
21
+
22
+ const main = async () => {
23
+ const [command, ...rest] = process.argv.slice(2);
24
+ const run = Object.hasOwn(SUBCOMMANDS, command ?? "") ? SUBCOMMANDS[command] : null;
25
+ if (!run) {
26
+ process.stderr.write(
27
+ `litclaude-ai (plugin): ${command ? `"${command}" is not served from the plugin` : "no command given"}. `
28
+ + `In-session commands: ${Object.keys(SUBCOMMANDS).join(", ")}. `
29
+ + `For install, update, doctor and the rest, ask the user to run in their own terminal: npx @litfamily/litclaude ${command ?? "--help"}\n`,
30
+ );
31
+ return 64;
32
+ }
33
+ const { realpathSync } = await import("node:fs");
34
+ const { dirname, join } = await import("node:path");
35
+ const { pathToFileURL } = await import("node:url");
36
+ const here = dirname(realpathSync(process.argv[1]));
37
+ return run((relative) => import(pathToFileURL(join(here, relative)).href), rest);
38
+ };
39
+
40
+ main().then(
41
+ (code) => {
42
+ process.exitCode = Number.isInteger(code) ? code : 0;
43
+ },
44
+ (error) => {
45
+ process.stderr.write(`litclaude-ai (plugin): ${error?.message ?? error}\n`);
46
+ process.exitCode = 1;
47
+ },
48
+ );
@@ -9,7 +9,7 @@ import {
9
9
  } from "../lib/wikify-knowledge.mjs";
10
10
 
11
11
  const protocolVersion = "2024-11-05";
12
- const serverVersion = "1.0.27";
12
+ const serverVersion = "1.0.28";
13
13
 
14
14
  const publicSourceReadTool = {
15
15
  name: "public_source_read",
@@ -233,6 +233,10 @@ export const parseGoals = (state, sessionId) => {
233
233
  .filter(Boolean),
234
234
  lastCheckpoint: str(Array.isArray(state.checkpoints) ? state.checkpoints.at(-1)?.status : null, 40),
235
235
  createdAt: time(state.createdAt),
236
+ // When the goal was finished: its last `complete` checkpoint, else its last update.
237
+ completedAt: state.status === "complete"
238
+ ? time((Array.isArray(state.checkpoints) ? state.checkpoints : []).findLast((entry) => entry?.status === "complete")?.createdAt) ?? time(state.updatedAt)
239
+ : null,
236
240
  };
237
241
  };
238
242
 
@@ -111,6 +111,10 @@ const entryOf = ({ snapshot, skills, now }) => {
111
111
  return candidates.sort((a, b) => b.at - a.at || (a.from === "record" ? -1 : 1))[0] ?? null;
112
112
  };
113
113
 
114
+ // A finished goal ends the map unless a stage record, skill or ignition came after it: that is a
115
+ // new request, and the old finish says nothing about it.
116
+ const goalFinished = (goal, entry) => goal?.status === "complete" && !(Number.isFinite(goal.completedAt) && Number.isFinite(entry?.at) && entry.at > goal.completedAt);
117
+
114
118
  const goalIsOpen = (goal) => Boolean(goal && ["active", "blocked", "review_blocked", "needs_user_decision"].includes(goal.status));
115
119
 
116
120
  // Without a discipline or a record, the durable state that says work is under way.
@@ -173,7 +177,7 @@ export const buildWorkflow = ({ snapshot, skills = [], completion = null, now })
173
177
  const planSaved = stage === "plan" && record?.stage === "plan" && record.done;
174
178
  if (planSaved) stage = "work";
175
179
  const lanes = record?.stage === "review" ? laneVerdicts(record.verdicts) : null;
176
- if (completion || goal?.status === "complete" || stage === "done") stage = "done";
180
+ if (completion || goalFinished(goal, entry) || stage === "done") stage = "done";
177
181
  else if (stage === "work" && !work && !goalIsOpen(goal) && snapshot.completedWorkIds.length > 0) stage = "review";
178
182
  else if (stage === "review" && lanes?.every(({ state }) => state === "pass")) stage = "done";
179
183
  if (planSaved && stage === "work" && !work) items.push("plan saved");
@@ -226,7 +230,7 @@ export const buildWorkflow = ({ snapshot, skills = [], completion = null, now })
226
230
  }
227
231
 
228
232
  const order = WORKFLOW_FAMILIES[family];
229
- const finished = family === "main" ? stage === "done" : completion !== null || (family === "loop" && snapshot.goal?.status === "complete");
233
+ const finished = family === "main" ? stage === "done" : completion !== null || (family === "loop" && goalFinished(snapshot.goal, entry));
230
234
  const current = finished ? -1 : order.indexOf(stage);
231
235
  const wave = sources.research?.wave ?? 0;
232
236
  const stages = order.map((id, index) => {
@@ -990,6 +990,14 @@ const classifyBashWords = (words, cwd) => {
990
990
  if (rest[0] === "start-work" && START_WORK_SELF_MOVES.has(rest[1]) && !rest.includes("--root") && rest.every((word) => !word.includes("/"))) {
991
991
  return canonicalBashTargets(cwd, [cwd, ...cli], "write");
992
992
  }
993
+ // `pause` is how the work asks the user for a new boundary: it records the pending boundary
994
+ // and grants nothing, so the root it names may lie outside the grants, and the lifecycle
995
+ // refuses a forbidden action itself. Only that `--target-root` value may hold a `/`, and only
996
+ // the bare CLI name passes: a `node <path>/litclaude-ai.js` file is checked by name, not content.
997
+ if (cli.length === 0 && rest[0] === "start-work" && rest[1] === "pause" && !rest.includes("--root")
998
+ && rest.every((word, index) => !word.includes("/") || rest[index - 1] === "--target-root")) {
999
+ return canonicalBashTargets(cwd, [cwd, ...cli], "write");
1000
+ }
993
1001
  }
994
1002
  if (head.text === "node") return classifyNodeScriptWords(args, cwd);
995
1003
  return null;