@litfamily/litclaude 1.0.18 → 1.0.19
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 +5 -0
- package/README.md +8 -8
- package/README_ko-KR.md +8 -8
- package/bin/install-ownership.mjs +7 -2
- package/docs/assets/readme/badge-version.svg +1 -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/auto-handoff.mjs +15 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.19 - 2026-10-01
|
|
4
|
+
|
|
5
|
+
- Automatic handoff now finds the handoff it asked for after compaction even when the model formats the marker line, for example as a bullet, in backticks or in bold. A handoff from another session is still ignored.
|
|
6
|
+
- An upgrade no longer stops with an ownership conflict when a bundled Python script left a `__pycache__` folder in the installed plugin.
|
|
7
|
+
|
|
3
8
|
## 1.0.18 - 2026-09-30
|
|
4
9
|
|
|
5
10
|
- `gpt-6.1-sol` is now the recommended coding-lead alternative, since OpenAI lists `gpt-6-sol` as the previous generation. `gpt-6-sol` still works for anyone who already chose it. Claude Code picks the model and LitClaude sets no OpenAI route of its own, so this shows only in the model notes in the README (English and Korean) and in `docs/agents.md`.
|
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.19/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/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">Plan, build, and check your work in Claude Code. Leave the next session a place to begin.</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.19/docs/assets/readme/badge-version.svg" alt="1.0.19" />
|
|
8
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/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.19/README_ko-KR.md">한국어</a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
LitClaude is a Claude Code plugin. Add `lit` to a request and Claude pins the goal, writes a
|
|
@@ -125,7 +125,7 @@ changed by hand or doesn't look like one LitClaude made, it refuses to touch it.
|
|
|
125
125
|
## More
|
|
126
126
|
|
|
127
127
|
- [Full guide and skills gallery on GitHub](https://github.com/wjgoarxiv/litclaude#readme)
|
|
128
|
-
- [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
129
|
-
- [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
130
|
-
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
131
|
-
- [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
128
|
+
- [Privacy and network behavior](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/docs/privacy.md)
|
|
129
|
+
- [Migration and ownership conflicts](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/docs/migration.md)
|
|
130
|
+
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/CHANGELOG.md)
|
|
131
|
+
- [MIT license](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/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.19/docs/assets/cover-motion-still.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/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.19/docs/assets/readme/badge-version.svg" alt="1.0.19" />
|
|
8
|
+
<a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/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.19/README.md">English</a>
|
|
12
12
|
</p>
|
|
13
13
|
|
|
14
14
|
LitClaude는 Claude Code 플러그인입니다. 요청 끝에 `lit`을 붙이면 Claude가 목표를 먼저
|
|
@@ -119,7 +119,7 @@ npm exec --yes --package @litfamily/litclaude@latest -- litclaude uninstall
|
|
|
119
119
|
## 더 보기
|
|
120
120
|
|
|
121
121
|
- [전체 안내와 스킬 갤러리 (GitHub)](https://github.com/wjgoarxiv/litclaude/blob/main/README_ko-KR.md)
|
|
122
|
-
- [개인정보와 네트워크](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
123
|
-
- [이전 안내와 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
124
|
-
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
125
|
-
- [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
122
|
+
- [개인정보와 네트워크](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/docs/privacy.md)
|
|
123
|
+
- [이전 안내와 소유권 충돌](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/docs/migration.md)
|
|
124
|
+
- [Release history](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/CHANGELOG.md)
|
|
125
|
+
- [MIT 라이선스](https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.19/LICENSE)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, renameSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
|
|
3
|
-
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
4
|
import { compareStableSemver } from "./update-notifier.mjs";
|
|
5
5
|
|
|
6
6
|
const stableVersion = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u;
|
|
@@ -20,6 +20,9 @@ const legacyVendorPathMap = [
|
|
|
20
20
|
["060_autoresearch-skill", "autoresearch", "25ce45fe792de02e04019e6d0c871738e6a1b8b6cb9a91cd2486b3d4cbb715b9"],
|
|
21
21
|
["064_autoconference-skill", "autoconference", "d305d2d41721c0196cc5aaa09610f1eb4499f7ba53504bd72bdbefdd21ca7da1"],
|
|
22
22
|
];
|
|
23
|
+
// Python writes bytecode next to the scripts it runs. That cache is generated, never user data, so ownership
|
|
24
|
+
// checks skip it. A symlink or a plain file named __pycache__ is not a cache and is still reported.
|
|
25
|
+
const isBytecodeCache = (name, value) => (value.isDirectory() && name === "__pycache__") || (value.isFile() && name.endsWith(".pyc"));
|
|
23
26
|
const conflict = (path, detail = "") => { throw new Error(`INSTALL_OWNERSHIP_CONFLICT: ${path}; use a compatible CLI or preserve this modified, foreign, or unsupported state before retrying${detail ? `. ${detail}` : ""}`); };
|
|
24
27
|
const stat = (path) => {
|
|
25
28
|
try { return lstatSync(path); } catch (error) { if (error.code === "ENOENT") return null; throw error; }
|
|
@@ -45,6 +48,7 @@ function treeHash(root) {
|
|
|
45
48
|
for (const name of readdirSync(path).sort()) {
|
|
46
49
|
if (!prefix && name === receiptName) continue;
|
|
47
50
|
const next = join(path, name), rel = prefix ? `${prefix}/${name}` : name, value = lstatSync(next);
|
|
51
|
+
if (isBytecodeCache(name, value)) continue;
|
|
48
52
|
if (!prefix && name === hostUseMarker && value.isDirectory() && readdirSync(next).length === 0) continue;
|
|
49
53
|
if (value.isDirectory()) { entries.push([rel, "directory"]); walk(next, rel); }
|
|
50
54
|
else if (value.isFile() && value.nlink === 1) entries.push([rel, "file", createHash("sha256").update(readFileSync(next)).digest("hex")]);
|
|
@@ -59,6 +63,7 @@ function detailedTree(root, { receipt = false } = {}) {
|
|
|
59
63
|
const rows = [];
|
|
60
64
|
function walk(path, prefix = "") {
|
|
61
65
|
const value = lstatSync(path);
|
|
66
|
+
if (prefix && isBytecodeCache(prefix.split("/").at(-1), value)) return;
|
|
62
67
|
if (value.isSymbolicLink()) conflict(path, "A preserved skill tree cannot contain symlinks");
|
|
63
68
|
if (value.isDirectory()) {
|
|
64
69
|
rows.push([prefix, "directory", value.mode & 0o777]);
|
|
@@ -169,7 +174,7 @@ export function preserveModifiedLegacySkill(plan, litHome) {
|
|
|
169
174
|
try {
|
|
170
175
|
const currentRows = detailedTree(plan.skillPath, { receipt: true });
|
|
171
176
|
if (!sameRowList(currentRows, plan.skillRows)) conflict(plan.skillPath, "The legacy skill changed after the ownership preflight");
|
|
172
|
-
cpSync(plan.skillPath, join(staging, "skill"), { recursive: true, errorOnExist: true, force: false });
|
|
177
|
+
cpSync(plan.skillPath, join(staging, "skill"), { recursive: true, errorOnExist: true, force: false, filter: (source) => !isBytecodeCache(basename(source), lstatSync(source)) });
|
|
173
178
|
if (!sameRowList(detailedTree(join(staging, "skill"), { receipt: true }), plan.skillRows)) {
|
|
174
179
|
conflict(plan.skillPath, "The staged preservation copy does not match the source");
|
|
175
180
|
}
|
|
@@ -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.19"><title>release: 1.0.19</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.19</text></g></svg>
|
package/package.json
CHANGED
|
@@ -243,6 +243,20 @@ const candidateFiles = (cwd, stateRoot) => {
|
|
|
243
243
|
return files;
|
|
244
244
|
};
|
|
245
245
|
|
|
246
|
+
// A model often dresses the marker up (bullet, bold label, backticks, an HTML comment). Each line is read
|
|
247
|
+
// with that Markdown decoration removed, then must hold the label and this exact id with a boundary after it.
|
|
248
|
+
const markerOnLine = (line, nonce) => {
|
|
249
|
+
const plain = line.replace(/<!--|-->|[*_`]/gu, "").replace(/\s+/gu, " ");
|
|
250
|
+
const label = "Auto-handoff id: ";
|
|
251
|
+
for (let at = plain.indexOf(label); at !== -1; at = plain.indexOf(label, at + 1)) {
|
|
252
|
+
const start = at + label.length;
|
|
253
|
+
if (plain.startsWith(nonce, start) && !/^[0-9a-f]/iu.test(plain.slice(start + nonce.length, start + nonce.length + 1))) return true;
|
|
254
|
+
}
|
|
255
|
+
return false;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const hasMarker = (text, nonce) => text.split(/\r?\n/u).some((line) => markerOnLine(line, nonce));
|
|
259
|
+
|
|
246
260
|
const readHandoff = (path, { nonce, firedAt }) => {
|
|
247
261
|
let fd;
|
|
248
262
|
try {
|
|
@@ -251,7 +265,7 @@ const readHandoff = (path, { nonce, firedAt }) => {
|
|
|
251
265
|
fd = openSync(path, constants.O_RDONLY | NO_FOLLOW);
|
|
252
266
|
if (!fstatSync(fd).isFile()) return null;
|
|
253
267
|
const text = readFileSync(fd, "utf8");
|
|
254
|
-
return text
|
|
268
|
+
return hasMarker(text, nonce) ? text : null;
|
|
255
269
|
} catch {
|
|
256
270
|
return null;
|
|
257
271
|
} finally {
|