@litfamily/litclaude 1.0.30 → 1.0.32
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 +8 -0
- package/README.md +8 -8
- package/README_ko-KR.md +8 -8
- package/docs/assets/readme/badge-version.svg +1 -1
- package/docs/hooks.md +5 -1
- package/package.json +1 -1
- package/plugins/litclaude/.claude-plugin/plugin.json +1 -1
- package/plugins/litclaude/bin/litclaude-mcp.js +1 -1
- package/plugins/litclaude/lib/mod/svg-card.mjs +17 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.32 - 2026-10-17
|
|
4
|
+
|
|
5
|
+
- The desktop mod card has its look and motion back. 1.0.31 drew it with the app's plain boxes and text to stop it blinking, but that also took away its design and all of its animation. This release restores the animated card from 1.0.30. Its animations now start already visible, so when the app reloads the card after a real change, the card no longer fades in from blank or restarts its border light from the corner. The clock stays off the desktop card, so a running tool alone does not reload it. The terminal and phone cards are unchanged.
|
|
6
|
+
|
|
7
|
+
## 1.0.31 - 2026-10-17
|
|
8
|
+
|
|
9
|
+
- In the Claude Code desktop app, the mod card used to blink: every real change, such as a new step, tool or skill, swapped in a whole new page, so the card went blank for a moment and its animations started over. The desktop card is now built from the app's own boxes and text, and a change updates only what moved. It looks the same but no longer animates. The terminal and phone cards are unchanged.
|
|
10
|
+
|
|
3
11
|
## 1.0.30 - 2026-10-16
|
|
4
12
|
|
|
5
13
|
- The pre-write guard now refuses more of the lines that tell a reader what a document is not for, such as `This table is not a ranking.` or `이 문서는 제품을 비교하려는 것이 아닙니다.` These forms came from real sessions. Bold-label callouts such as `> **주의:** ...` are now read too, while ordinary quoted text is still skipped. Lines from manuals and lab reports that only look similar stay allowed, and a large flood of matches can no longer push the scan past its limit into an allowed write.
|
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.
|
|
1
|
+
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/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.
|
|
8
|
-
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
7
|
+
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/assets/readme/badge-version.svg" alt="1.0.32" />
|
|
8
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/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.
|
|
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.32/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.
|
|
77
|
-
- [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
78
|
-
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
79
|
-
- [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
76
|
+
- [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/privacy.md)
|
|
77
|
+
- [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/migration.md)
|
|
78
|
+
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/CHANGELOG.md)
|
|
79
|
+
- [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/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.
|
|
1
|
+
<p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/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.
|
|
8
|
-
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
7
|
+
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/assets/readme/badge-version.svg" alt="1.0.32" />
|
|
8
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/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.
|
|
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.32/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.
|
|
75
|
-
- [이전과 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
76
|
-
- [변경 이력](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
77
|
-
- [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
74
|
+
- [개인정보와 네트워크 동작](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/privacy.md)
|
|
75
|
+
- [이전과 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/docs/migration.md)
|
|
76
|
+
- [변경 이력](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/CHANGELOG.md)
|
|
77
|
+
- [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.32/LICENSE)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.32"><title>release: 1.0.32</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.32</text></g></svg>
|
package/docs/hooks.md
CHANGED
|
@@ -470,7 +470,11 @@ pill and the border breathe and the step's spinner turns, and on `full` a light
|
|
|
470
470
|
current stage and the current chips, a head runs the rail leaving it, the count bar's head
|
|
471
471
|
shimmers and a comet runs around the border. An idle card is a still image. The app loads each new
|
|
472
472
|
drawing from scratch and restarts its animation, so this card names the running tool without its
|
|
473
|
-
clock and shows the loop round without its countdown.
|
|
473
|
+
clock and shows the loop round without its countdown. Each animation starts part way through its
|
|
474
|
+
cycle, so a freshly loaded card already looks like the running one: the border and the pill are
|
|
475
|
+
lit, the light sits on its pill and the comet is part way round, not parked at the top-left
|
|
476
|
+
corner. The app still blanks the card for a moment while it loads a new drawing; the mod cannot
|
|
477
|
+
prevent that. It is redrawn only when something you would
|
|
474
478
|
notice changes, such as the stage, the tool, a skill, a usage figure or the goal. While the card
|
|
475
479
|
shows in a terminal and the app at once, the terminal's loop countdown and lane times wait for such
|
|
476
480
|
a change too; its step clock keeps counting on its own.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@litfamily/litclaude",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.32",
|
|
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": {
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
// head shimmers, the step spinner turns and a comet runs around the border (full only). Idle, it is
|
|
14
14
|
// still. The drawing carries no step clock and no loop countdown: the surface loads each new
|
|
15
15
|
// drawing afresh, restarting every animation, so a figure that moves with time alone would make the
|
|
16
|
-
// card blink on every poll.
|
|
16
|
+
// card blink on every poll. Each loop opens mid-cycle (see `loop`), so a fresh load starts on a
|
|
17
|
+
// frame of the running card rather than on a dim border and a comet at the corner.
|
|
17
18
|
//
|
|
18
19
|
// Text is set in a monospace face and placed by counted cells (Hangul and emoji as two), so the
|
|
19
20
|
// layout does not depend on measuring a font the drawing cannot see.
|
|
@@ -50,6 +51,14 @@ const ROW_Y = Object.freeze([28, 58, 86, 114, 142]);
|
|
|
50
51
|
const PILL_H = 20;
|
|
51
52
|
const FONT = "ui-monospace, 'SF Mono', SFMono-Regular, Menlo, 'JetBrains Mono', Consolas, monospace";
|
|
52
53
|
|
|
54
|
+
// Timing of one looping animation, started `phase` of the way into its cycle. The surface loads
|
|
55
|
+
// each new drawing afresh, so every loop would otherwise open on its first frame: the breathing at
|
|
56
|
+
// its dimmest, the light off the pill's left edge, the comet parked at the top-left corner. A
|
|
57
|
+
// negative begin opens each loop mid-cycle, in a frame that looks like the card already running.
|
|
58
|
+
const loop = (ms, phase) => `dur="${ms}ms" begin="-${Math.round(ms * phase)}ms" repeatCount="indefinite"`;
|
|
59
|
+
// The breathing pieces share one phase so the pill, the border and the count bar's head stay in step.
|
|
60
|
+
const BREATH_PHASE = 0.25;
|
|
61
|
+
|
|
53
62
|
const esc = (text) => String(text).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
54
63
|
const widthOf = (text) => textWidth(text) * SVG_CARD.cell;
|
|
55
64
|
const levelColor = (percent) => (percent >= 90 ? C.hudRed : percent >= 70 ? C.hudYellow : C.hudGreen);
|
|
@@ -79,7 +88,7 @@ const pill = (x, y, label, { fill, ink, bold = true, sweep = false, breath = nul
|
|
|
79
88
|
const w = widthOf(label) + 16;
|
|
80
89
|
const top = y - PILL_H + 6;
|
|
81
90
|
const parts = [`<rect x="${x.toFixed(1)}" y="${top}" width="${w.toFixed(1)}" height="${PILL_H}" rx="${PILL_H / 2}" fill="${fill}"/>`];
|
|
82
|
-
if (breath) parts.push(`<rect x="${x.toFixed(1)}" y="${top}" width="${w.toFixed(1)}" height="${PILL_H}" rx="${PILL_H / 2}" fill="${breath}" opacity="0"><animate attributeName="opacity" values="0;${breathPeak};0"
|
|
91
|
+
if (breath) parts.push(`<rect x="${x.toFixed(1)}" y="${top}" width="${w.toFixed(1)}" height="${PILL_H}" rx="${PILL_H / 2}" fill="${breath}" opacity="0"><animate attributeName="opacity" values="0;${breathPeak};0" ${loop(TIMINGS.breath, BREATH_PHASE)}/></rect>`);
|
|
83
92
|
if (sweep) parts.push(`<rect x="${x.toFixed(1)}" y="${top}" width="${w.toFixed(1)}" height="${PILL_H}" rx="${PILL_H / 2}" fill="url(#lit-sweep)"/>`);
|
|
84
93
|
parts.push(text(x + 8, y, label, { fill: ink, bold }));
|
|
85
94
|
return { markup: parts.join(""), end: x + w };
|
|
@@ -197,7 +206,7 @@ const mapRowSvg = (model, accent, animate) => {
|
|
|
197
206
|
out.push(`<line x1="${x1.toFixed(1)}" y1="${y - 4}" x2="${x2.toFixed(1)}" y2="${y - 4}" stroke="${C.rail}" stroke-width="2.5" stroke-linecap="round"/>`);
|
|
198
207
|
const filled = count && count.total > 0 ? Math.min(1, count.done / count.total) : 0;
|
|
199
208
|
if (filled > 0) out.push(`<line x1="${x1.toFixed(1)}" y1="${y - 4}" x2="${(x1 + filled * layout.rail).toFixed(1)}" y2="${y - 4}" stroke="${mapColor(accent, mid)}" stroke-width="2.5" stroke-linecap="round"/>`);
|
|
200
|
-
if (animate.sweep) out.push(`<circle cx="${x1.toFixed(1)}" cy="${y - 4}" r="2.5" fill="#ffffff"><animate attributeName="cx" values="${x1.toFixed(1)};${x2.toFixed(1)}"
|
|
209
|
+
if (animate.sweep) out.push(`<circle cx="${x1.toFixed(1)}" cy="${y - 4}" r="2.5" fill="#ffffff"><animate attributeName="cx" values="${x1.toFixed(1)};${x2.toFixed(1)}" ${loop(TIMINGS.flow, 0.5)}/></circle>`);
|
|
201
210
|
} else {
|
|
202
211
|
out.push(`<line x1="${x1.toFixed(1)}" y1="${y - 4}" x2="${x2.toFixed(1)}" y2="${y - 4}" stroke="${C.rail}" stroke-width="1.5" stroke-linecap="round" stroke-opacity="0.7"/>`);
|
|
203
212
|
}
|
|
@@ -232,7 +241,7 @@ const detailRowSvg = (model, accent, animate) => {
|
|
|
232
241
|
out.push(text(nameEnd, y, model.step.name, { fill: C.white, anchor: "end" }));
|
|
233
242
|
const cx = nameEnd - widthOf(model.step.name) - 10;
|
|
234
243
|
out.push(`<circle cx="${cx.toFixed(1)}" cy="${y - 4}" r="4.5" fill="none" stroke="${accent}" stroke-width="1.8" stroke-dasharray="18 10.3">`
|
|
235
|
-
+ (animate.breath ? `<animateTransform attributeName="transform" type="rotate" values="0 ${cx.toFixed(1)} ${y - 4};360 ${cx.toFixed(1)} ${y - 4}"
|
|
244
|
+
+ (animate.breath ? `<animateTransform attributeName="transform" type="rotate" values="0 ${cx.toFixed(1)} ${y - 4};360 ${cx.toFixed(1)} ${y - 4}" ${loop(TIMINGS.spin * 8, 0.5)}/>` : "")
|
|
236
245
|
+ "</circle>");
|
|
237
246
|
right = width - cx + 10;
|
|
238
247
|
}
|
|
@@ -252,7 +261,7 @@ const detailRowSvg = (model, accent, animate) => {
|
|
|
252
261
|
const cells = barCells(total > 0 ? done / total : 0, 8);
|
|
253
262
|
cells.forEach(({ glyph, color }, index) => out.push(`<rect x="${(x + index * 9).toFixed(1)}" y="${y - 10}" width="7" height="10" rx="1.5" fill="${glyph === "█" ? color : C.empty}"/>`));
|
|
254
263
|
const head = cells.findLastIndex(({ glyph }) => glyph === "█");
|
|
255
|
-
if (head >= 0 && animate.sweep) out.push(`<rect x="${(x + head * 9).toFixed(1)}" y="${y - 10}" width="7" height="10" rx="1.5" fill="#ffffff" opacity="0"><animate attributeName="opacity" values="0;0.6;0"
|
|
264
|
+
if (head >= 0 && animate.sweep) out.push(`<rect x="${(x + head * 9).toFixed(1)}" y="${y - 10}" width="7" height="10" rx="1.5" fill="#ffffff" opacity="0"><animate attributeName="opacity" values="0;0.6;0" ${loop(TIMINGS.breath, BREATH_PHASE)}/></rect>`);
|
|
256
265
|
x += 8 * 9 + 4;
|
|
257
266
|
}
|
|
258
267
|
const pieces = [];
|
|
@@ -389,13 +398,13 @@ export const composeSvgCard = (model, { motion = "full", accent = "#5fd7ff" } =
|
|
|
389
398
|
const edge = borderColor(model, accent);
|
|
390
399
|
const perimeter = 1000;
|
|
391
400
|
const defs = animate.sweep
|
|
392
|
-
? `<defs><linearGradient id="lit-sweep" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset="0.5" stop-color="#fff" stop-opacity="0.55"/><stop offset="1" stop-color="#fff" stop-opacity="0"/><animateTransform attributeName="gradientTransform" type="translate" values="-1.2 0;1.2 0"
|
|
401
|
+
? `<defs><linearGradient id="lit-sweep" x1="0" x2="1" y1="0" y2="0"><stop offset="0" stop-color="#fff" stop-opacity="0"/><stop offset="0.5" stop-color="#fff" stop-opacity="0.55"/><stop offset="1" stop-color="#fff" stop-opacity="0"/><animateTransform attributeName="gradientTransform" type="translate" values="-1.2 0;1.2 0" ${loop(TIMINGS.sweep, 0.5)}/></linearGradient></defs>`
|
|
393
402
|
: "";
|
|
394
403
|
const frame = `<rect x="1" y="1" width="${width - 2}" height="${height - 2}" rx="14" fill="${C.bg}" stroke="${edge}" stroke-width="1.5"${model.idle ? ' stroke-opacity="0.8"' : ""}>`
|
|
395
|
-
+ (animate.breath && !model.warnings.length ? `<animate attributeName="stroke-opacity" values="0.45;1;0.45"
|
|
404
|
+
+ (animate.breath && !model.warnings.length ? `<animate attributeName="stroke-opacity" values="0.45;1;0.45" ${loop(TIMINGS.breath, BREATH_PHASE)}/>` : "")
|
|
396
405
|
+ "</rect>";
|
|
397
406
|
const comet = animate.comet
|
|
398
|
-
? `<rect x="1" y="1" width="${width - 2}" height="${height - 2}" rx="14" fill="none" stroke="url(#lit-comet)" stroke-width="2.5" stroke-linecap="round" pathLength="${perimeter}" stroke-dasharray="70 ${perimeter - 70}"><animate attributeName="stroke-dashoffset" values="0;-${perimeter}"
|
|
407
|
+
? `<rect x="1" y="1" width="${width - 2}" height="${height - 2}" rx="14" fill="none" stroke="url(#lit-comet)" stroke-width="2.5" stroke-linecap="round" pathLength="${perimeter}" stroke-dasharray="70 ${perimeter - 70}"><animate attributeName="stroke-dashoffset" values="0;-${perimeter}" ${loop(TIMINGS.comet * 2, 0.5)}/></rect>`
|
|
399
408
|
+ `<defs><linearGradient id="lit-comet" x1="0" x2="1" y1="0" y2="1"><stop offset="0" stop-color="${C.orange}"/><stop offset="0.6" stop-color="${C.pink}"/><stop offset="1" stop-color="#ffffff"/></linearGradient></defs>`
|
|
400
409
|
: "";
|
|
401
410
|
const body = [
|