@litfamily/litclaude 1.0.7 β†’ 1.0.8

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.8
4
+
5
+ - Paint the activation logo and its `πŸ”₯ LIT IGNITED Β· <discipline> πŸ”₯` label with a bold truecolor gradient that runs from ignition orange through the HUD hot pink to electric cyan. The hook sets the colour depth itself because its output is always piped, so terminal detection cannot drop it to monochrome; `NO_COLOR` still prints plain text, and the reply line the model is asked to print stays free of escape codes.
6
+ - Show a bold, ignition-orange `πŸ”₯ LIT IGNITED Β· <discipline> πŸ”₯` mark in the HUD status line whenever the prompt hook activates a LitClaude discipline. The prompt hook records the selected discipline per session under `litclaude-hud/` in the per-user temp directory (`LITCLAUDE_HUD_STATE_ROOT` overrides it; the repository state root and home directory stay untouched), and the HUD reads that record back, so the mark reflects the hook's decision rather than model output. Turns without an activation clear the record and the mark disappears.
7
+ - Ask model replies to start with `πŸ”₯ **LIT IGNITED Β· <discipline>** πŸ”₯`, while hook messages and the HUD render the same activation mark without Markdown.
8
+
3
9
  ## 1.0.7
4
10
 
5
11
  - Add the animated cover to both README pages, with a static cover for reduced-motion settings.
@@ -85,9 +91,9 @@
85
91
  fallback, and plain text for non-UTF-8 or dumb terminals. Keep the install-plan
86
92
  frame and add `--help`. Respect NO_COLOR, piped output, JSON, and CI.
87
93
  - Render a standard mark once per session through the SessionStart system message
88
- and a micro mark with the discipline on prompt activation. Preserve the session
94
+ and an ignition mark with the discipline on prompt activation. Preserve the session
89
95
  receipt across resume and compaction. Model replies begin with exactly one
90
- `β–² LIT Β· <discipline>` probe line; the model does not redraw the harness mark.
96
+ `πŸ”₯ **LIT IGNITED Β· <discipline>** πŸ”₯` probe line; the model does not redraw the harness logo.
91
97
  Refresh skill-resource pins and verify runtime closures before the major version transition.
92
98
 
93
99
  - Rename skills: `hyperplan` β†’ `lit-crucible`, `init-deep` β†’ `lit-init`,
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
- <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/cover.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/cover-motion.webp" width="100%" alt="LitClaude cover art. An orange signal moves through orbital paths above the CLAUDE CODE wordmark. The static family cover appears for reduced-motion preference." /></picture></p>
2
- <p align="center"><a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/cover.webp">View the static cover</a></p>
1
+ <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/cover.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/cover-motion.webp" width="100%" alt="LitClaude cover art. An orange signal moves through orbital paths above the CLAUDE CODE wordmark. The static family cover appears for reduced-motion preference." /></picture></p>
2
+ <p align="center"><a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/cover.webp">View the static cover</a></p>
3
3
 
4
4
  <h1 align="center">LitClaude</h1>
5
5
  <p align="center"><strong>Keep the work lit.</strong></p>
@@ -39,12 +39,12 @@
39
39
 
40
40
  </details>
41
41
 
42
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/litclaude-wordmark.svg" width="480" alt="LITCLAUDE display type" /></p>
43
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/litclaude-clay-icon.png" width="160" alt="LitClaude clay mark" /></p>
42
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/litclaude-wordmark.svg" width="480" alt="LITCLAUDE display type" /></p>
43
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/litclaude-clay-icon.png" width="160" alt="LitClaude clay mark" /></p>
44
44
 
45
45
  <p align="center">
46
- <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/readme/badge-version.svg" alt="1.0.7" />
47
- <a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
46
+ <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/readme/badge-version.svg" alt="1.0.8" />
47
+ <a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
48
48
  </p>
49
49
 
50
50
  <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.7 version
358
+ npm view @litfamily/litclaude@1.0.8 version
359
359
  ```
360
360
 
361
- If that lookup returns `1.0.7`, the exact install is available:
361
+ If that lookup returns `1.0.8`, the exact install is available:
362
362
 
363
363
  ```bash
364
- npm exec --yes --package @litfamily/litclaude@1.0.7 -- litclaude install
364
+ npm exec --yes --package @litfamily/litclaude@1.0.8 -- litclaude install
365
365
  ```
366
366
 
367
367
  Otherwise, wait for explicit human publication before using that pin. Check the
@@ -413,6 +413,13 @@ Interactive installation previews the available HUD accents. The LitClaude HUD
413
413
  uses `[πŸ”₯LITCLAUDE vX.Y.Z]`, a compact `ctx [β–Žβ–‘β–‘]` bar, and a `5h [▏░] 4% ↻`
414
414
  rate-limit reset countdown. Set `LITCLAUDE_HUD_ACCENT` before installation to
415
415
  choose an accent.
416
+ When the prompt hook activates a LitClaude discipline, the HUD adds a bold,
417
+ ignition-orange `πŸ”₯ LIT IGNITED Β· lit-loop πŸ”₯` mark right after the brand until
418
+ the next turn without an activation; the hook records the selected discipline
419
+ per session under `litclaude-hud/` in the per-user temp directory, never in the
420
+ repository or your home directory (`LITCLAUDE_HUD_STATE_ROOT` overrides the location).
421
+ The reply starts with `πŸ”₯ **LIT IGNITED Β· <discipline>** πŸ”₯`; the hook system
422
+ message and HUD display the same mark without Markdown.
416
423
 
417
424
  HUD appearance and color capability are independent. By default (`dark`) the
418
425
  model, context, usage, reset, and Git text carry the selected accent, usage
package/README_ko-KR.md CHANGED
@@ -1,5 +1,5 @@
1
- <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/cover.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/cover-motion.webp" width="100%" alt="LitClaude cover art. An orange signal moves through orbital paths above the CLAUDE CODE wordmark. The static family cover appears for reduced-motion preference." /></picture></p>
2
- <p align="center"><a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/cover.webp">μ •μ§€ ν‘œμ§€ 보기</a></p>
1
+ <p align="center"><picture><source media="(prefers-reduced-motion: reduce)" srcset="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/cover.webp" /><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/cover-motion.webp" width="100%" alt="LitClaude cover art. An orange signal moves through orbital paths above the CLAUDE CODE wordmark. The static family cover appears for reduced-motion preference." /></picture></p>
2
+ <p align="center"><a href="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/cover.webp">μ •μ§€ ν‘œμ§€ 보기</a></p>
3
3
 
4
4
  <h1 align="center">LitClaude</h1>
5
5
  <p align="center"><strong>Keep the work lit.</strong></p>
@@ -39,12 +39,12 @@
39
39
 
40
40
  </details>
41
41
 
42
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/litclaude-wordmark.svg" width="480" alt="LITCLAUDE λ””μŠ€ν”Œλ ˆμ΄ νƒ€μž…" /></p>
43
- <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/litclaude-clay-icon.png" width="160" alt="LitClaude 클레이 마크" /></p>
42
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/litclaude-wordmark.svg" width="480" alt="LITCLAUDE λ””μŠ€ν”Œλ ˆμ΄ νƒ€μž…" /></p>
43
+ <p align="center"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/litclaude-clay-icon.png" width="160" alt="LitClaude 클레이 마크" /></p>
44
44
 
45
45
  <p align="center">
46
- <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/readme/badge-version.svg" alt="1.0.7" />
47
- <a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.7/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
46
+ <img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/readme/badge-version.svg" alt="1.0.8" />
47
+ <a href="./LICENSE"><img src="https://cdn.jsdelivr.net/npm/@litfamily/litclaude@1.0.8/docs/assets/readme/badge-license.svg" alt="MIT license" /></a>
48
48
  </p>
49
49
 
50
50
  <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.7 version
353
+ npm view @litfamily/litclaude@1.0.8 version
354
354
  ```
355
355
 
356
- 쑰회 κ²°κ³Όκ°€ `1.0.7`이면 exact install을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
356
+ 쑰회 κ²°κ³Όκ°€ `1.0.8`이면 exact install을 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
357
357
 
358
358
  ```bash
359
- npm exec --yes --package @litfamily/litclaude@1.0.7 -- litclaude install
359
+ npm exec --yes --package @litfamily/litclaude@1.0.8 -- litclaude install
360
360
  ```
361
361
 
362
362
  κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ λͺ…μ‹œμ μΈ human publication을 κΈ°λ‹€λ¦½λ‹ˆλ‹€. Pin은 κ·Έ 뒀에 μ‚¬μš©ν•©λ‹ˆλ‹€.
@@ -389,6 +389,13 @@ Interactive μ„€μΉ˜μ—μ„œλŠ” HUD accent 후보λ₯Ό ν„°λ―Έλ„μ—μ„œ 미리 λ³Ό 수
389
389
  LitClaude HUDλŠ” `[πŸ”₯LITCLAUDE vX.Y.Z]`, `ctx [β–Žβ–‘β–‘]` context bar,
390
390
  `5h [▏░] 4% ↻` rate-limit reset countdown을 μ‚¬μš©ν•©λ‹ˆλ‹€. μ„€μΉ˜ 전에
391
391
  `LITCLAUDE_HUD_ACCENT`λ₯Ό μ§€μ •ν•΄ accentλ₯Ό 선택할 수 μžˆμŠ΅λ‹ˆλ‹€.
392
+ prompt hook이 LitClaude discipline을 ν™œμ„±ν™”ν•˜λ©΄ HUDλŠ” brand λ°”λ‘œ 뒀에 ꡡ은
393
+ ignition-orange `πŸ”₯ LIT IGNITED Β· lit-loop πŸ”₯` ν‘œμ‹œλ₯Ό 뢙이고, ν™œμ„±ν™”κ°€ μ—†λŠ” λ‹€μŒ
394
+ ν„΄μ—μ„œ μ§€μ›λ‹ˆλ‹€. hook은 μ„ νƒλœ discipline을 μ„Έμ…˜λ³„λ‘œ μ‚¬μš©μž μž„μ‹œ λ””λ ‰ν„°λ¦¬μ˜
395
+ `litclaude-hud/`에 κΈ°λ‘ν•˜κ³ (μ €μž₯μ†Œμ™€ ν™ˆ λ””λ ‰ν„°λ¦¬λŠ” κ±΄λ“œλ¦¬μ§€ μ•ŠμŒ)
396
+ `LITCLAUDE_HUD_STATE_ROOT`둜 μœ„μΉ˜λ₯Ό λ°”κΏ€ 수 μžˆμŠ΅λ‹ˆλ‹€.
397
+ λͺ¨λΈ 응닡은 `πŸ”₯ **LIT IGNITED Β· <discipline>** πŸ”₯`둜 μ‹œμž‘ν•˜λ©°, hook system
398
+ message와 HUDλŠ” Markdown 없이 같은 ν‘œμ‹œλ₯Ό 보여 μ€λ‹ˆλ‹€.
392
399
 
393
400
  HUD의 λ°°κ²½ μ„€μ •κ³Ό 터미널 색상 지원 μˆ˜μ€€μ€ λ³„κ°œμž…λ‹ˆλ‹€. κΈ°λ³Έκ°’(`dark`)μ—μ„œλŠ” model,
394
401
  context, usage, reset, Git κΈ€μžμ— μ„ νƒν•œ accentκ°€ λ“€μ–΄κ°€κ³ , μ‚¬μš©λŸ‰ νΌμ„ΌνŠΈλŠ” μˆ˜μ€€μ—
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.7"><title>release: 1.0.7</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.7</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="146" height="20" role="img" aria-label="release: 1.0.8"><title>release: 1.0.8</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.8</text></g></svg>
package/docs/hooks.md CHANGED
@@ -51,7 +51,7 @@ verdicts: [PASS, FAIL, BLOCKED]
51
51
  ## #contract.outputs
52
52
 
53
53
  - Claude Code hook JSON containing `continue: true`, `hookSpecificOutput.hookEventName`, and route-specific `additionalContext`.
54
- - Optional `systemMessage` for the once-per-session mark and active route micro marks.
54
+ - Optional `systemMessage` for the once-per-session mark and active route ignition marks.
55
55
  - `DELIVERABLE_HEDGE_VIOLATION` as `PostToolUse` `additionalContext` after a client-deliverable write contains a matched limitation phrase; the file has already been written, so the response asks Claude to revise it rather than claiming the write was prevented.
56
56
  - `BLOCKED:` text for natural-language start-work, unavailable native goal binding, disabled Dynamic workflow, or gated agent-team setup.
57
57
  - Unavailable native goal binding also includes `READY_TO_PASTE` and one bounded `/goal` command for the user to copy, paste, and send; the hook never enters or submits it.
@@ -273,7 +273,7 @@ lit-scientific-visualization
273
273
  ```
274
274
 
275
275
  When a LIT trigger is present, the hook returns additional context containing
276
- `LITWORK MODE ENABLED` and a visible `litclaude Β· <discipline>` micro system
276
+ `LITWORK MODE ENABLED` and a visible `πŸ”₯ LIT IGNITED Β· <discipline> πŸ”₯` system
277
277
  message. That context is guidance for Claude Code; it is not executed as a
278
278
  command. Slash commands and slash-command mentions are native Claude Code
279
279
  surfaces and do not activate this prompt hook; code spans, substrings, and
@@ -316,8 +316,8 @@ against another process with the same uid.
316
316
 
317
317
  `handoff` is a separate exact-bare route: only the complete prompt `handoff`
318
318
  after outer whitespace activates `Skill(lit-handoff)` and injects the complete
319
- canonical bundled source. Its system message shows the micro mark with
320
- `litclaude Β· lit-handoff`; the model begins with exactly one `β–² LIT Β· lit-handoff` probe line. Explanatory mentions, quoted or fenced
319
+ canonical bundled source. Its system message shows `πŸ”₯ LIT IGNITED Β· lit-handoff πŸ”₯`;
320
+ the model begins with exactly one `πŸ”₯ **LIT IGNITED Β· lit-handoff** πŸ”₯` probe line. Explanatory mentions, quoted or fenced
321
321
  text, compound prompts, `/litclaude:lit-handoff`, and secret-bearing multiline
322
322
  content do not activate the hook. The slash command remains a native Claude
323
323
  Code command surface.
@@ -325,8 +325,8 @@ Code command surface.
325
325
  Scientific visualization has one exact-bare UserPromptSubmit route: only the
326
326
  complete prompt `lit-scientific-visualization` after outer whitespace activates
327
327
  `Skill(lit-scientific-visualization)`, injects the full adapter and canonical
328
- source, and shows the micro mark with `litclaude Β· lit-scientific-visualization`.
329
- The model begins with exactly one `β–² LIT Β· lit-scientific-visualization` probe line.
328
+ source, and shows `πŸ”₯ LIT IGNITED Β· lit-scientific-visualization πŸ”₯` in its system
329
+ message. The model begins with exactly one `πŸ”₯ **LIT IGNITED Β· lit-scientific-visualization** πŸ”₯` probe line.
330
330
  Generic visualization, plot, chart, figure, and scientific visualization prose,
331
331
  mentions, quoted or fenced text, mixed prompts, near misses, and
332
332
  `/litclaude:lit-scientific-visualization` text do not activate the prompt hook.
@@ -495,11 +495,11 @@ or symlinked cwd and missing project roots also suppress decoration; unsafe root
495
495
  state never falls back to a nested state directory.
496
496
  A compact event never repeats the session mark.
497
497
 
498
- Activated UserPromptSubmit routes render the flat micro mark with
499
- `litclaude Β· <discipline>` in `systemMessage`. Inactive prompts stay silent.
498
+ Activated UserPromptSubmit routes render the plain mark
499
+ `πŸ”₯ LIT IGNITED Β· <discipline> πŸ”₯` in `systemMessage`. Inactive prompts stay silent.
500
500
  `additionalContext` requires the model's reply to begin with exactly one
501
- `β–² LIT Β· <discipline>` line. The model must not draw the harness logo again;
502
- the probe and visible mark are separate outputs.
501
+ `πŸ”₯ **LIT IGNITED Β· <discipline>** πŸ”₯` line. The system mark and reply probe are
502
+ separate outputs; the model must not draw ASCII art or emit a second probe.
503
503
 
504
504
  Hook JSON uses uncolored rows. CLI output uses the 44Γ—20 Ignition B banner and
505
505
  native product column inside the existing installer frame; `--help` and doctor
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@litfamily/litclaude",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Claude Code-native workflow distribution.",
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.7",
4
+ "version": "1.0.8",
5
5
  "author": {
6
6
  "name": "LitClaude contributors"
7
7
  },
@@ -3,7 +3,9 @@
3
3
  import { existsSync, lstatSync, readFileSync } from "node:fs";
4
4
  import { dirname, extname, join, resolve } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { standard, micro, supportsBlocks } from "../lib/lit-mark.mjs";
6
+ import { standard, micro, colorMode, supportsBlocks } from "../lib/lit-mark.mjs";
7
+ import { NEON_END, NEON_START } from "../lib/hud-accent-palette.mjs";
8
+ import { ignitionMark, writeIgnitionState } from "../lib/hud-ignition.mjs";
7
9
  import { renameAliases, renameNote } from "../lib/rename-aliases.mjs";
8
10
  import { transcriptHasContextPressure } from "../lib/context-pressure.mjs";
9
11
  import { extractMutatedFilePaths, serializeUntrustedData } from "../lib/mutated-file-paths.mjs";
@@ -114,11 +116,36 @@ const writeContext = (additionalContext, systemMessage, shouldContinue = true) =
114
116
  );
115
117
  };
116
118
 
117
- // Hooks write JSON to a pipe: the host renders uncolored rows, never model ASCII art.
118
- const activationMessage = (discipline) => supportsBlocks()
119
- ? `\n${micro.map((row, index) => index === 2 ? `${row} litclaude Β· ${discipline}` : row).join("\n")}`
120
- : `\nLIT\nlitclaude Β· ${discipline}`;
121
- const probeInstruction = (discipline) => `Begin your reply with the exact probe line \`β–² LIT Β· ${discipline}\` on its own line, exactly once before anything else. The harness already renders the mark; do not draw or repeat it.`;
119
+ const activationStops = Object.freeze([Object.freeze([255, 99, 55]), NEON_START, NEON_END]);
120
+
121
+ const lerp = (stops, t) => {
122
+ const segment = Math.min(stops.length - 2, Math.floor(t * (stops.length - 1)));
123
+ const progress = t * (stops.length - 1) - segment;
124
+ return stops[segment].map((value, channel) => Math.round(value + (stops[segment + 1][channel] - value) * progress));
125
+ };
126
+
127
+ const paint = (text) => {
128
+ const chars = [...text];
129
+ const length = chars.length;
130
+ return `\x1b[1m${chars.map((char, index) => {
131
+ if (char === " ") return char;
132
+ const [red, green, blue] = lerp(activationStops, length === 1 ? 0 : index / (length - 1));
133
+ return `\x1b[38;2;${red};${green};${blue}m${char}`;
134
+ }).join("")}\x1b[0m`;
135
+ };
136
+
137
+ // Claude Code renders ANSI in activation systemMessage; the model probe remains markdown text.
138
+ const activationMessage = (discipline) => {
139
+ if (!supportsBlocks()) return `\nLIT\n${ignitionMark(discipline)}`;
140
+ if (colorMode({ isTTY: true }) === "none") {
141
+ return `\n${micro.map((row, index) => index === 2 ? `${row} ${ignitionMark(discipline)}` : row).join("\n")}`;
142
+ }
143
+ const width = Math.max(...micro.map((row) => [...row.trimEnd()].length));
144
+ const rows = micro.map((row) => row.trimEnd().padEnd(width));
145
+ const label = `LIT IGNITED Β· ${discipline}`;
146
+ return `\n${rows.map((row, index) => index === 2 ? `${paint(row)} πŸ”₯ ${paint(label)} πŸ”₯` : paint(row)).join("\n")}`;
147
+ };
148
+ const probeInstruction = (discipline) => `Begin your reply with the exact probe line \`${ignitionMark(discipline, { markdown: true })}\` on its own line, exactly once before anything else. The harness status mark is a separate plain-text surface; do not draw ASCII art or repeat the probe.`;
122
149
 
123
150
  const plainWordBoundary = /^[A-Za-z0-9]$/u;
124
151
  const compoundWordBoundary = /^[A-Za-z0-9_-]$/u;
@@ -403,7 +430,7 @@ const handoffContext = () => {
403
430
  }
404
431
 
405
432
  return [
406
- "HANDOFF MODE ENABLED: begin your reply with the exact banner line `β–² LIT Β· lit-handoff` on its own line, exactly once before anything else. The harness renders the mark separately; do not repeat it.",
433
+ `HANDOFF MODE ENABLED: ${probeInstruction("lit-handoff")}`,
407
434
  "Treat this exact bare prompt as an explicit request for /litclaude:lit-handoff and Skill(lit-handoff).",
408
435
  llmContractReference,
409
436
  `Canonical source root: ${inertFilesystemData(canonicalRoot)}. Read and follow the complete canonical source body below; resolve its template, example, and eval resources relative to this absolute installed source root rather than the process cwd or ~/skills.`,
@@ -424,7 +451,7 @@ const scientificVisualizationContext = () => {
424
451
  }
425
452
 
426
453
  return [
427
- "SCIENTIFIC VISUALIZATION MODE ENABLED: begin your reply with the exact banner line `β–² LIT Β· lit-scientific-visualization` on its own line, exactly once before anything else. The harness renders the mark separately; do not repeat it.",
454
+ `SCIENTIFIC VISUALIZATION MODE ENABLED: ${probeInstruction("lit-scientific-visualization")}`,
428
455
  "Treat this exact bare prompt as an explicit request for /litclaude:lit-scientific-visualization and Skill(lit-scientific-visualization).",
429
456
  llmContractReference,
430
457
  `Canonical source root: ${inertFilesystemData(canonicalRoot)}. Read and follow the complete canonical source body below; resolve its references, scripts, assets, evals, and tests relative to this absolute installed source root rather than the process cwd or ~/skills.`,
@@ -1023,6 +1050,22 @@ switch (eventName) {
1023
1050
  const exactBareHandoff = isExactBareHandoff(prompt);
1024
1051
  const exactBareScientificVisualization = isExactBareScientificVisualization(prompt);
1025
1052
  const trigger = exactBareHandoff || exactBareScientificVisualization || isDiagnosticLiteralPrompt(prompt) ? undefined : findWorkflowTrigger(prompt);
1053
+ // The HUD status line reads this record back, so the visible ignition mark tracks the
1054
+ // discipline actually selected for this turn instead of anything the model chooses to draw.
1055
+ try {
1056
+ writeIgnitionState({
1057
+ sessionId: input.session_id,
1058
+ discipline: trustedResume
1059
+ ? "start-work"
1060
+ : exactBareHandoff
1061
+ ? "lit-handoff"
1062
+ : exactBareScientificVisualization
1063
+ ? "lit-scientific-visualization"
1064
+ : trigger?.discipline ?? null,
1065
+ });
1066
+ } catch {
1067
+ // A HUD record is cosmetic; an unwritable home never alters the prompt hook.
1068
+ }
1026
1069
  // The Stop-hook persistence gate only knows about a lit-plan turn through this record,
1027
1070
  // so every other prompt clears it: the gate must never outlive the turn that armed it.
1028
1071
  try {
@@ -12,6 +12,7 @@ import {
12
12
  normalizeHudAppearance,
13
13
  } from "../lib/hud-accent-palette.mjs";
14
14
  import { latestUsageTokens } from "../lib/cache-measurement.mjs";
15
+ import { readIgnitionState, renderIgnitionSegment } from "../lib/hud-ignition.mjs";
15
16
 
16
17
  const pluginRoot = dirname(dirname(fileURLToPath(import.meta.url)));
17
18
  const pluginManifestPath = join(pluginRoot, ".claude-plugin", "plugin.json");
@@ -263,7 +264,10 @@ const main = async () => {
263
264
  appearance,
264
265
  });
265
266
  const contextText = `${text("ctx")} ${accent("[")}${makeContextBar(contextPct)}${accent("]")} ${text(`${contextPct}%/${maxK}k`)}`;
266
- const line = `${prefix} ${accent("|")} ${text(model)} ${accent(sep)} ${contextText}${usageText}${git ? ` ${accent(sep)} ${text("git")} ${text(git)}` : ""}`;
267
+ const ignition = renderIgnitionSegment(readIgnitionState(status.session_id), {
268
+ depth: plainOutput ? "plain" : colorDepth,
269
+ });
270
+ const line = `${prefix}${ignition ? ` ${ignition}` : ""} ${accent("|")} ${text(model)} ${accent(sep)} ${contextText}${usageText}${git ? ` ${accent(sep)} ${text("git")} ${text(git)}` : ""}`;
267
271
  process.stdout.write(`${line}\n`);
268
272
 
269
273
  const lastMessage = latestUserMessage(status.transcript_path);
@@ -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.7";
12
+ const serverVersion = "1.0.8";
13
13
 
14
14
  const publicSourceReadTool = {
15
15
  name: "public_source_read",
@@ -17,7 +17,7 @@ verdicts: [PASS, DEGRADED, FAIL, BLOCKED]
17
17
 
18
18
  | Field | Obligation | Evidence |
19
19
  | --- | --- | --- |
20
- | banner | Begin with exactly `β–² LIT Β· lit-handoff`. | First visible response line. |
20
+ | banner | Begin with exactly `πŸ”₯ **LIT IGNITED Β· lit-handoff** πŸ”₯`. | First visible response line. |
21
21
  | skill | Load and follow `Skill(lit-handoff)`. | Route receipt. |
22
22
  | source | Read the immutable bundled handoff `SKILL.md` completely. | Canonical source path. |
23
23
 
@@ -37,7 +37,7 @@ verdicts: [PASS, DEGRADED, FAIL, BLOCKED]
37
37
 
38
38
  ## #contract.procedure
39
39
 
40
- 1. Begin with `β–² LIT Β· lit-handoff`.
40
+ 1. Begin with `πŸ”₯ **LIT IGNITED Β· lit-handoff** πŸ”₯`.
41
41
  2. Load `Skill(lit-handoff)` and read its canonical vendored source completely.
42
42
  3. Reconcile stale handoff prose with current live state.
43
43
  4. Create or update only the correct continuation artifact.
@@ -73,4 +73,4 @@ body verbatim merely because it was generated.
73
73
 
74
74
  Use `Skill(lit-handoff)` now. The first visible response line must be exactly:
75
75
 
76
- `β–² LIT Β· lit-handoff`
76
+ `πŸ”₯ **LIT IGNITED Β· lit-handoff** πŸ”₯`
@@ -17,7 +17,7 @@ verdicts: [PASS, DEGRADED, FAIL, BLOCKED]
17
17
 
18
18
  | Field | Obligation | Evidence |
19
19
  | --- | --- | --- |
20
- | banner | Begin with exactly `β–² LIT Β· lit-scientific-visualization`. | First visible response line. |
20
+ | banner | Begin with exactly `πŸ”₯ **LIT IGNITED Β· lit-scientific-visualization** πŸ”₯`. | First visible response line. |
21
21
  | skill | Load `Skill(lit-scientific-visualization)`. | Route receipt. |
22
22
  | runtime | Preflight without silent dependency installation. | PASS or DEGRADED report. |
23
23
 
@@ -71,4 +71,4 @@ their full scientific content.
71
71
 
72
72
  Use `Skill(lit-scientific-visualization)` now. The first visible response line must be exactly:
73
73
 
74
- `β–² LIT Β· lit-scientific-visualization`
74
+ `πŸ”₯ **LIT IGNITED Β· lit-scientific-visualization** πŸ”₯`
@@ -170,7 +170,7 @@ export const canonicalSkillResourceManifest = Object.freeze(
170
170
  ["skills/lit-team/SKILL.md", "6d4ca726d1240db7692ccc95802ab6abfd45588147ec663dafa1b3b233a08a13"],
171
171
  ["skills/lit-team/scripts/team.mjs", "a0be61f09cc1c10989b12709135ac4b99260496f840dcf58514478082e239fe7"],
172
172
  ["skills/litresearch/ATTRIBUTION.md", "1ed8b43d48a13d7fc106cbfd86bc1bac0316529bdac4e2e38043fafeae2a8e15"],
173
- ["skills/litwork/SKILL.md", "18d91a20d882d72f9795cfeb8d46a3e07c773d66853d51aa965cdcec5513bea3"],
173
+ ["skills/litwork/SKILL.md", "5c5964d4df69c0e7cc7505f2dec38beed9413e79d64eb61f325012215e86d0ba"],
174
174
  ["skills/visual-qa/SKILL.md", "089d26a14800b461cfd628b4789f676308d5e09fe13e9e24632b8fd6305c8517"],
175
175
  ["skills/visual-qa/references/capture-playbook.md", "92cad16893118c9e878cabbb49dc2187049ec6e759fcc4e6006d79bdae998689"],
176
176
  ["skills/visual-qa/references/complete-contract.md", "8dd878975eb386b8b5d0b5439ed7bc50de9c4e3ee2aeff6d553c4299c5b30cb4"],
@@ -61,8 +61,8 @@ export const ansi16CodeForAccent = (value) => ({
61
61
  // to bright-magenta bold; NO_COLOR is plain text. The πŸ”₯ is mandatory and the
62
62
  // brand is accent-independent (LITCLAUDE_HUD_ACCENT still themes the HUD body).
63
63
  const NEON_BRAND = "LITCLAUDE";
64
- const NEON_START = [255, 45, 149]; // #ff2d95 hot pink
65
- const NEON_END = [0, 229, 255]; // #00e5ff electric cyan
64
+ export const NEON_START = Object.freeze([255, 45, 149]); // #ff2d95 hot pink
65
+ export const NEON_END = Object.freeze([0, 229, 255]); // #00e5ff electric cyan
66
66
 
67
67
  export const supportsTruecolor = (env = process.env) => {
68
68
  // The portable signal: terminals that export COLORTERM=truecolor|24bit.
@@ -0,0 +1,74 @@
1
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+
5
+ // Per-session ignition record: the prompt hook writes it on every UserPromptSubmit and the HUD
6
+ // status line reads it back, so the status bar reflects the discipline actually selected for
7
+ // the current turn instead of anything the model chooses to draw. Mode is per turn and never
8
+ // durable, so the record lives in the per-user temp directory: not in the repository state
9
+ // root (activation must stay side-effect-free there) and not in the home directory.
10
+
11
+ const IGNITION_PALETTE = Object.freeze({
12
+ truecolor: "\x1b[38;2;255;99;55m",
13
+ "256": "\x1b[38;5;203m",
14
+ "16": "\x1b[91m",
15
+ });
16
+
17
+ export const ignitionStateRoot = (env = process.env) => {
18
+ const override = env.LITCLAUDE_HUD_STATE_ROOT?.trim();
19
+ if (override) return override;
20
+ const tmp = env.TMPDIR?.trim() || tmpdir();
21
+ return join(tmp, "litclaude-hud");
22
+ };
23
+
24
+ const safeSessionFile = (sessionId) => {
25
+ const raw = typeof sessionId === "string" && sessionId.trim() ? sessionId.trim() : "unknown-session";
26
+ return `${raw.replace(/[^A-Za-z0-9._-]/gu, "_").replace(/^\.+/u, "_")}.json`;
27
+ };
28
+
29
+ export const ignitionStatePath = (sessionId, env = process.env) => join(ignitionStateRoot(env), safeSessionFile(sessionId));
30
+
31
+ export function ignitionMark(discipline, { markdown = false } = {}) {
32
+ const label = `LIT IGNITED Β· ${discipline}`;
33
+ return markdown ? `πŸ”₯ **${label}** πŸ”₯` : `πŸ”₯ ${label} πŸ”₯`;
34
+ }
35
+
36
+ export function writeIgnitionState({ sessionId, discipline }, env = process.env, now = () => new Date()) {
37
+ const root = ignitionStateRoot(env);
38
+ mkdirSync(root, { recursive: true });
39
+ const target = ignitionStatePath(sessionId, env);
40
+ const record = {
41
+ sessionId: typeof sessionId === "string" ? sessionId : null,
42
+ discipline: typeof discipline === "string" && discipline ? discipline : null,
43
+ at: now().toISOString(),
44
+ };
45
+ const staging = `${target}.${process.pid}.tmp`;
46
+ writeFileSync(staging, `${JSON.stringify(record)}\n`);
47
+ renameSync(staging, target);
48
+ return record;
49
+ }
50
+
51
+ export function readIgnitionState(sessionId, env = process.env) {
52
+ const target = ignitionStatePath(sessionId, env);
53
+ if (!existsSync(target)) return null;
54
+ try {
55
+ const parsed = JSON.parse(readFileSync(target, "utf8"));
56
+ if (!parsed || typeof parsed !== "object") return null;
57
+ return {
58
+ sessionId: typeof parsed.sessionId === "string" ? parsed.sessionId : null,
59
+ discipline: typeof parsed.discipline === "string" && parsed.discipline ? parsed.discipline : null,
60
+ at: typeof parsed.at === "string" ? parsed.at : null,
61
+ };
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+
67
+ export function renderIgnitionSegment(state, { depth = "plain" } = {}) {
68
+ const discipline = state?.discipline ?? null;
69
+ if (!discipline) return "";
70
+ const label = ignitionMark(discipline);
71
+ if (depth === "plain") return label;
72
+ const paint = IGNITION_PALETTE[depth] ?? IGNITION_PALETTE["256"];
73
+ return `\x1b[1m${paint}${label}\x1b[0m`;
74
+ }
@@ -17,7 +17,7 @@ verdicts: [PASS, DEGRADED, FAIL, BLOCKED]
17
17
 
18
18
  | Field | Contract | Evidence |
19
19
  | --- | --- | --- |
20
- | activation | Begin the user-visible response with exactly `β–² LIT Β· lit-handoff`. | First response line and route receipt. |
20
+ | activation | Begin the user-visible response with exactly `πŸ”₯ **LIT IGNITED Β· lit-handoff** πŸ”₯`. | First response line and route receipt. |
21
21
  | canonical source | Read the vendored handoff reference completely before acting: `SKILL.md` in the canonical `../../vendor/handoff/` directory. | Source path and destination decision. |
22
22
  | completion | Create or update the correct continuation packet without exposing secrets. | Artifact path, checks, and `PASS`, `FAIL`, or `BLOCKED`. |
23
23
 
@@ -39,7 +39,7 @@ verdicts: [PASS, DEGRADED, FAIL, BLOCKED]
39
39
 
40
40
  ## #contract.procedure
41
41
 
42
- 1. Print `β–² LIT Β· lit-handoff` as the first visible line.
42
+ 1. Print `πŸ”₯ **LIT IGNITED Β· lit-handoff** πŸ”₯` as the first visible line.
43
43
  2. Resolve every linked resource relative to this loaded `SKILL.md` through Claude Code's Skill resource root, never relative to the process cwd. For the exact-bare hook route, use the absolute installed source root injected by the hook. Never assume `~/skills` exists after package installation.
44
44
  3. Read the vendored handoff reference `SKILL.md` in full. Follow every destination, stale-state, secret-redaction, and verification rule in that source without abbreviating it.
45
45
  4. Inspect existing handoff files and live ledgers or JSONL surfaces before choosing the destination. Prefer live operational truth over stale prose.
@@ -17,7 +17,7 @@ verdicts: [PASS, DEGRADED, FAIL, BLOCKED]
17
17
 
18
18
  | Field | Contract | Evidence |
19
19
  | --- | --- | --- |
20
- | activation | Begin the response with the exact banner `β–² LIT Β· lit-scientific-visualization`. | First visible response line. |
20
+ | activation | Begin the response with the exact probe `πŸ”₯ **LIT IGNITED Β· lit-scientific-visualization** πŸ”₯`. | First visible response line. |
21
21
  | canonical source | Read `../../vendor/scientific-visualization/SKILL.md` completely before plotting. | Source-root receipt. |
22
22
  | runtime | Preflight Python and plotting dependencies without installing them. | PASS or DEGRADED doctor output. |
23
23
  | completion | Produce and inspect the requested figure artifacts. | Files, dimensions, formats, DPI, and visual QA. |
@@ -35,14 +35,14 @@ verdicts: [PASS, DEGRADED, FAIL, BLOCKED]
35
35
  | --- | --- | --- |
36
36
  | direct-skill | Claude Code loads `Skill(lit-scientific-visualization)`. | Explicit user intent is required; there is no generic visualization auto-trigger. |
37
37
  | command-routed | `/litclaude:lit-scientific-visualization` is invoked. | Follow the command and this full adapter. |
38
- | hook-routed | The complete UserPromptSubmit prompt is exactly `lit-scientific-visualization` after outer whitespace. | Show the micro mark and discipline as a hook `systemMessage`, inject this adapter and the complete canonical source, and keep all mixed or near-miss prompts inert. |
38
+ | hook-routed | The complete UserPromptSubmit prompt is exactly `lit-scientific-visualization` after outer whitespace. | Show `πŸ”₯ LIT IGNITED Β· lit-scientific-visualization πŸ”₯` in the hook `systemMessage`, inject this adapter and the complete canonical source, and keep all mixed or near-miss prompts inert. |
39
39
  | core-ready | Python and matplotlib are available. | Use packaged scripts and verify real exports. |
40
40
  | degraded | Python or matplotlib is unavailable. | Report `DEGRADED:` with the missing capability; do not claim artifact creation. |
41
41
  | optional-degraded | seaborn, pandas, scipy, plotly, kaleido, numpy, or MDAnalysis is missing. | Use a valid core fallback or report the specific blocked workflow. |
42
42
 
43
43
  ## #contract.procedure
44
44
 
45
- 1. Begin the reply with the exact banner `β–² LIT Β· lit-scientific-visualization` on its own line. The exact-bare UserPromptSubmit route renders the micro mark and `litclaude Β· lit-scientific-visualization` as its visible hook `systemMessage`; the probe is model-emitted exactly once; do not treat generic visualization prose as equivalent invocation.
45
+ 1. Begin the reply with the exact probe `πŸ”₯ **LIT IGNITED Β· lit-scientific-visualization** πŸ”₯` on its own line. The exact-bare UserPromptSubmit route renders `πŸ”₯ LIT IGNITED Β· lit-scientific-visualization πŸ”₯` as its plain-text hook `systemMessage`; the model probe appears exactly once. Do not treat generic visualization prose as equivalent invocation.
46
46
  2. Resolve every linked resource relative to this loaded `SKILL.md` through Claude Code's Skill resource root, never relative to the process cwd. Never hard-code `~/skills` or the source checkout.
47
47
  3. Read the [canonical `SKILL.md`](../../vendor/scientific-visualization/SKILL.md) completely, then read only the referenced source files needed for the requested figure. Preserve every restraint, including `rcparams()`, scatter-only semantics, journal sizing, legend treatment, grids, fonts, layout, and export requirements.
48
48
  4. Resolve the [bundled doctor](../../bin/litclaude-scientific-visualization-doctor.js) as an installed Skill resource and invoke its absolute path with Node, or use `litclaude doctor`; never run a cwd-relative shell path. Never install Python, matplotlib, or optional packages silently. Ask before any dependency or environment mutation.
@@ -583,8 +583,8 @@ history-safety detail when the operation grows past a single commit.
583
583
 
584
584
  ## Output discipline
585
585
 
586
- - First line, literally: `β–² LIT Β· litwork`, on its own line, before
587
- anything else, exactly once. The harness renders its mark separately; do not repeat it.
586
+ - First line, literally: `πŸ”₯ **LIT IGNITED Β· litwork** πŸ”₯`, on its own line, before
587
+ anything else, exactly once. The harness shows its plain-text status mark separately; do not draw ASCII art or add a second probe line.
588
588
  - After bootstrap in reader mode: the current result, decision, or next required
589
589
  action. Keep the notepad path internal unless the request asks for it.
590
590
  - During execution in reader mode, surface only a current result, material
@@ -25,6 +25,7 @@ import { tmpdir } from "node:os";
25
25
  import { join, resolve } from "node:path";
26
26
  import { fileURLToPath, pathToFileURL } from "node:url";
27
27
  import { deflateSync } from "node:zlib";
28
+ import { stripAnsi } from "./strip-ansi.mjs";
28
29
 
29
30
  export const repoRoot = resolve(fileURLToPath(new URL("..", import.meta.url)));
30
31
 
@@ -606,8 +607,8 @@ function phaseCorrect(phase, run) {
606
607
  if (phase.id === "session_start") return context.startsWith("LitClaude rules loaded for ");
607
608
  if (phase.id === "s1_activation") {
608
609
  return /LITWORK MODE ENABLED/u.test(context)
609
- && /litclaude Β· lit-loop/u.test(run.parsed.systemMessage ?? "")
610
- && /β–² LIT Β· lit-loop/u.test(context);
610
+ && /πŸ”₯ LIT IGNITED Β· lit-loop πŸ”₯/u.test(stripAnsi(run.parsed.systemMessage ?? ""))
611
+ && /πŸ”₯ \*\*LIT IGNITED Β· lit-loop\*\* πŸ”₯/u.test(context);
611
612
  }
612
613
  return run.parsed.systemMessage === undefined
613
614
  && context === "LitClaude prompt hook checked: no workflow activation.";
@@ -0,0 +1 @@
1
+ export { stripVTControlCharacters as stripAnsi } from "node:util";