@litfamily/litclaude 1.0.4 → 1.0.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/CHANGELOG.md +5 -0
- package/README.md +8 -8
- package/README_ko-KR.md +8 -8
- 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-hook.js +18 -1
- package/plugins/litclaude/bin/litclaude-mcp.js +1 -1
- package/plugins/litclaude/lib/canonical-skill-resources.mjs +1 -1
- package/plugins/litclaude/scripts/scaffold-plan.mjs +27 -12
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
envelopes and plain-output policy; use flat orange/lime/ivory cell colors with
|
|
8
8
|
fixed 256-color approximations and no background or extrusion.
|
|
9
9
|
|
|
10
|
+
## 1.0.5
|
|
11
|
+
|
|
12
|
+
- Ignore host-generated task notifications and system reminders during prompt activation while preserving routes for genuine user text.
|
|
13
|
+
- Make scaffold-plan's paired-write cleanup tolerate transient sibling-draft churn without reporting refusal after a plan was written, while retaining replacement detection.
|
|
14
|
+
|
|
10
15
|
## 1.0.4
|
|
11
16
|
|
|
12
17
|
- Keep managing a native `litclaude@litclaude-ai` registration after a host rewrite
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
1
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/cover.webp" width="100%" alt="LitClaude v5 armory cover" /></p>
|
|
2
2
|
|
|
3
3
|
<h1 align="center">LitClaude</h1>
|
|
4
4
|
<p align="center"><strong>Keep the work lit.</strong></p>
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
|
|
39
39
|
</details>
|
|
40
40
|
|
|
41
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
42
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
41
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/litclaude-wordmark.svg" width="480" alt="LITCLAUDE display type" /></p>
|
|
42
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/litclaude-clay-icon.png" width="160" alt="LitClaude clay mark" /></p>
|
|
43
43
|
|
|
44
44
|
<p align="center">
|
|
45
|
-
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
46
|
-
<a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
45
|
+
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/readme/badge-version.svg" alt="1.0.5" />
|
|
46
|
+
<a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
|
|
47
47
|
</p>
|
|
48
48
|
|
|
49
49
|
<p align="center">
|
|
@@ -355,13 +355,13 @@ npm exec --yes --package @litfamily/litclaude@latest -- litclaude install
|
|
|
355
355
|
For a reproducible install, pin the current package version:
|
|
356
356
|
|
|
357
357
|
```bash
|
|
358
|
-
npm view @litfamily/litclaude@1.0.
|
|
358
|
+
npm view @litfamily/litclaude@1.0.5 version
|
|
359
359
|
```
|
|
360
360
|
|
|
361
|
-
If that lookup returns `1.0.
|
|
361
|
+
If that lookup returns `1.0.5`, the exact install is available:
|
|
362
362
|
|
|
363
363
|
```bash
|
|
364
|
-
npm exec --yes --package @litfamily/litclaude@1.0.
|
|
364
|
+
npm exec --yes --package @litfamily/litclaude@1.0.5 -- litclaude install
|
|
365
365
|
```
|
|
366
366
|
|
|
367
367
|
Otherwise, wait for explicit human publication before using that pin. Check the
|
package/README_ko-KR.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
1
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/cover.webp" width="100%" alt="LitClaude v5 armory cover" /></p>
|
|
2
2
|
|
|
3
3
|
<h1 align="center">LitClaude</h1>
|
|
4
4
|
<p align="center"><strong>Keep the work lit.</strong></p>
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
|
|
39
39
|
</details>
|
|
40
40
|
|
|
41
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
42
|
-
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
41
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/litclaude-wordmark.svg" width="480" alt="LITCLAUDE 디스플레이 타입" /></p>
|
|
42
|
+
<p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/litclaude-clay-icon.png" width="160" alt="LitClaude 클레이 마크" /></p>
|
|
43
43
|
|
|
44
44
|
<p align="center">
|
|
45
|
-
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
46
|
-
<a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.
|
|
45
|
+
<img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/readme/badge-version.svg" alt="1.0.5" />
|
|
46
|
+
<a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.5/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
|
|
47
47
|
</p>
|
|
48
48
|
|
|
49
49
|
<p align="center">
|
|
@@ -350,13 +350,13 @@ npm exec --yes --package @litfamily/litclaude@latest -- litclaude install
|
|
|
350
350
|
설치를 재현하려면 registry에서 현재 package version을 조회한 뒤 고정합니다.
|
|
351
351
|
|
|
352
352
|
```bash
|
|
353
|
-
npm view @litfamily/litclaude@1.0.
|
|
353
|
+
npm view @litfamily/litclaude@1.0.5 version
|
|
354
354
|
```
|
|
355
355
|
|
|
356
|
-
조회 결과가 `1.0.
|
|
356
|
+
조회 결과가 `1.0.5`이면 exact install을 사용할 수 있습니다.
|
|
357
357
|
|
|
358
358
|
```bash
|
|
359
|
-
npm exec --yes --package @litfamily/litclaude@1.0.
|
|
359
|
+
npm exec --yes --package @litfamily/litclaude@1.0.5 -- litclaude install
|
|
360
360
|
```
|
|
361
361
|
|
|
362
362
|
그렇지 않으면 명시적인 human publication을 기다립니다. Pin은 그 뒤에 사용합니다.
|
|
@@ -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.5"><title>release: 1.0.5</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.5</text></g></svg>
|
package/package.json
CHANGED
|
@@ -466,7 +466,24 @@ const withoutClosedCodeFences = (text) => {
|
|
|
466
466
|
};
|
|
467
467
|
|
|
468
468
|
const withoutCode = (text) => withoutClosedCodeFences(text).replace(/`[^`]*`/gu, " ");
|
|
469
|
-
|
|
469
|
+
|
|
470
|
+
// Claude Code (and herdr, which relays pane events the same way) can deliver a
|
|
471
|
+
// UserPromptSubmit turn whose `prompt` is host-generated background content rather
|
|
472
|
+
// than something the user typed — observed 3x on 2026-09-17 as a `<task-notification>`
|
|
473
|
+
// block reporting a finished background agent, which happened to contain UI-shaped
|
|
474
|
+
// prose ("dashboard", "configure", ...) and fired the frontend-ui-ux route. A
|
|
475
|
+
// `<system-reminder>` block is the same class of host-authored wrapper and is stripped
|
|
476
|
+
// for the same reason, even though only `<task-notification>` has been directly
|
|
477
|
+
// observed here. Only WELL-FORMED, fully-closed blocks are stripped — same rule as
|
|
478
|
+
// `withoutClosedCodeFences` for fences — so a bare, unclosed opening tag (accidental or
|
|
479
|
+
// not) stays visible and eligible rather than silently swallowing real user text.
|
|
480
|
+
// Genuine user prose outside (or between) these blocks is untouched and still routes
|
|
481
|
+
// normally; a prompt that consists ONLY of host-generated blocks reduces to nothing and
|
|
482
|
+
// therefore activates no route, which is the intended fix.
|
|
483
|
+
const withoutHostNotifications = (text) => text
|
|
484
|
+
.replace(/<task-notification>[\s\S]*?<\/task-notification>/gu, " ")
|
|
485
|
+
.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gu, " ");
|
|
486
|
+
const rawTriggerText = (text) => withoutCode(withoutHostNotifications(text)).toLowerCase();
|
|
470
487
|
const normalizedTriggerText = (text) => rawTriggerText(text).replace(/[_-]+/gu, " ");
|
|
471
488
|
|
|
472
489
|
const isPlainWordBoundary = (value) => value === undefined || !plainWordBoundary.test(value);
|
|
@@ -47,7 +47,7 @@ export const canonicalSkillResourceManifest = Object.freeze(
|
|
|
47
47
|
["lib/strict-json.mjs", "d941f327aabce5ffc212770852cfbc7e08dd03471e4e9bc9560eff54f06d489a"],
|
|
48
48
|
["lib/wikify-knowledge-cli.mjs", "d98e4b3ea0efe3dcd483750c2dc3a5d0dfd14bc6eb349437902b1e01b8fa2ff4"],
|
|
49
49
|
["lib/wikify-knowledge.mjs", "4d2f4e0ac3bc0b40ac513470b324e853e2aeeb3f009216c13d8e12ec08e6c28b"],
|
|
50
|
-
["scripts/scaffold-plan.mjs", "
|
|
50
|
+
["scripts/scaffold-plan.mjs", "c014b9acb49a647c97044dfb5a83eb5cc2bd4e13774ad1a9f213b9e074559d3e"],
|
|
51
51
|
["skills/autoconference/SKILL.md", "3731208dc3838d4d2916fb01da0c8cb63cca36342c2ffb5770770b3332d06cd3"],
|
|
52
52
|
["skills/autoresearch/SKILL.md", "2b69c53bade3851cfb9c770bce80afe5f9e75b9629719e9ba95a4b0045eaf5b3"],
|
|
53
53
|
["skills/browser-drive/scripts/capability-probe.mjs", "e767912bc034eaf9081256d8aa2f2bf63c7d9d29e39cb5e56f390e872df794f7"],
|
|
@@ -230,23 +230,38 @@ const inspectWorkspaceDirectory = (cwd) => {
|
|
|
230
230
|
return { workspaceRoot, workspaceStat };
|
|
231
231
|
};
|
|
232
232
|
|
|
233
|
+
// A directory that was actually REPLACED (rename-over, or unlink+recreate that
|
|
234
|
+
// reuses the freed inode number — dev/ino/birthtime can all coincide with the
|
|
235
|
+
// original on Linux; see test/inode-reuse.test.mjs) leaves an already-opened
|
|
236
|
+
// descriptor pinned to the old, now-unlinked inode. That inode's ctime is frozen
|
|
237
|
+
// at replacement time, so a descriptor-based read never converges with a fresh
|
|
238
|
+
// pathname-based read of the replacement. A brief sibling create/unlink INSIDE an
|
|
239
|
+
// otherwise-untouched directory (a different scaffold slug sharing
|
|
240
|
+
// `.litclaude/drafts/`, for example) also advances that directory's ctime and can
|
|
241
|
+
// land in the gap between the two reads, but it settles within microseconds since
|
|
242
|
+
// the directory itself was never replaced. Re-sampling a bounded number of times
|
|
243
|
+
// lets that transient churn resolve without weakening the replacement check: a
|
|
244
|
+
// genuine replacement's mismatch never resolves and still fails closed once the
|
|
245
|
+
// attempts are exhausted.
|
|
246
|
+
const DIRECTORY_PIN_SETTLE_ATTEMPTS = 5;
|
|
247
|
+
|
|
233
248
|
const assertDirectoryPin = async (pin, label) => {
|
|
234
249
|
if (pin?.descriptor === undefined || pin.parentState?.closed) throw new Error(`refused: ${label} pin is closed`);
|
|
235
250
|
const openedBefore = fstatSync(pin.descriptor);
|
|
236
251
|
const named = await lstat(pin.path);
|
|
237
252
|
const openedAfter = fstatSync(pin.descriptor);
|
|
238
253
|
const namedAfter = await lstat(pin.path);
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
// when the descriptor still names the same
|
|
248
|
-
// agrees with the pathname; a replacement
|
|
249
|
-
// disagreeing and remains fail-closed.
|
|
254
|
+
let openedFinal;
|
|
255
|
+
let namedFinal;
|
|
256
|
+
let settled = false;
|
|
257
|
+
for (let attempt = 0; attempt < DIRECTORY_PIN_SETTLE_ATTEMPTS && !settled; attempt += 1) {
|
|
258
|
+
openedFinal = fstatSync(pin.descriptor);
|
|
259
|
+
namedFinal = await lstat(pin.path);
|
|
260
|
+
settled = samePathIdentity(openedFinal, namedFinal);
|
|
261
|
+
}
|
|
262
|
+
// Accept the "before" pair only when the descriptor still names the same
|
|
263
|
+
// directory and the settled sample agrees with the pathname; a replacement
|
|
264
|
+
// after open leaves the two samples disagreeing and remains fail-closed.
|
|
250
265
|
const stable = openedBefore.isDirectory()
|
|
251
266
|
&& openedAfter.isDirectory()
|
|
252
267
|
&& openedFinal.isDirectory()
|
|
@@ -254,7 +269,7 @@ const assertDirectoryPin = async (pin, label) => {
|
|
|
254
269
|
&& namedAfter.isDirectory()
|
|
255
270
|
&& !named.isSymbolicLink()
|
|
256
271
|
&& !namedAfter.isSymbolicLink()
|
|
257
|
-
&&
|
|
272
|
+
&& settled
|
|
258
273
|
&& (samePathIdentity(openedBefore, named)
|
|
259
274
|
|| (openedBefore.dev === openedFinal.dev && openedBefore.ino === openedFinal.ino));
|
|
260
275
|
if (!stable) {
|