devflow-kit 1.6.1 → 1.8.0
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 +45 -0
- package/README.md +31 -0
- package/dist/cli.js +3 -1
- package/dist/commands/hud.d.ts +22 -0
- package/dist/commands/hud.js +180 -0
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +114 -5
- package/dist/commands/list.js +1 -0
- package/dist/commands/uninstall.js +9 -16
- package/dist/hud/cache.d.ts +14 -0
- package/dist/hud/cache.js +54 -0
- package/dist/hud/colors.d.ts +23 -0
- package/dist/hud/colors.js +62 -0
- package/dist/hud/components/config-counts.d.ts +8 -0
- package/dist/hud/components/config-counts.js +91 -0
- package/dist/hud/components/context-usage.d.ts +8 -0
- package/dist/hud/components/context-usage.js +49 -0
- package/dist/hud/components/diff-stats.d.ts +3 -0
- package/dist/hud/components/diff-stats.js +36 -0
- package/dist/hud/components/directory.d.ts +3 -0
- package/dist/hud/components/directory.js +10 -0
- package/dist/hud/components/git-ahead-behind.d.ts +3 -0
- package/dist/hud/components/git-ahead-behind.js +16 -0
- package/dist/hud/components/git-branch.d.ts +3 -0
- package/dist/hud/components/git-branch.js +14 -0
- package/dist/hud/components/model.d.ts +3 -0
- package/dist/hud/components/model.js +21 -0
- package/dist/hud/components/release-info.d.ts +3 -0
- package/dist/hud/components/release-info.js +9 -0
- package/dist/hud/components/session-cost.d.ts +3 -0
- package/dist/hud/components/session-cost.js +9 -0
- package/dist/hud/components/session-duration.d.ts +3 -0
- package/dist/hud/components/session-duration.js +18 -0
- package/dist/hud/components/todo-progress.d.ts +3 -0
- package/dist/hud/components/todo-progress.js +11 -0
- package/dist/hud/components/usage-quota.d.ts +3 -0
- package/dist/hud/components/usage-quota.js +45 -0
- package/dist/hud/components/version-badge.d.ts +3 -0
- package/dist/hud/components/version-badge.js +80 -0
- package/dist/hud/components/worktree-count.d.ts +3 -0
- package/dist/hud/components/worktree-count.js +8 -0
- package/dist/hud/config.d.ts +10 -0
- package/dist/hud/config.js +55 -0
- package/dist/hud/credentials.d.ts +17 -0
- package/dist/hud/credentials.js +99 -0
- package/dist/hud/git.d.ts +7 -0
- package/dist/hud/git.js +153 -0
- package/dist/hud/index.d.ts +2 -0
- package/dist/hud/index.js +81 -0
- package/dist/hud/render.d.ts +7 -0
- package/dist/hud/render.js +111 -0
- package/dist/hud/stdin.d.ts +6 -0
- package/dist/hud/stdin.js +25 -0
- package/dist/hud/transcript.d.ts +7 -0
- package/dist/hud/transcript.js +130 -0
- package/dist/hud/types.d.ts +116 -0
- package/dist/hud/types.js +2 -0
- package/dist/hud/usage-api.d.ts +7 -0
- package/dist/hud/usage-api.js +84 -0
- package/dist/utils/manifest.d.ts +1 -0
- package/package.json +5 -2
- package/plugins/devflow-accessibility/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-ambient/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-ambient/agents/scrutinizer.md +6 -4
- package/plugins/devflow-ambient/agents/shepherd.md +26 -12
- package/plugins/devflow-ambient/agents/simplifier.md +24 -15
- package/plugins/devflow-ambient/agents/skimmer.md +71 -21
- package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-code-review/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-core-skills/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-debug/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-frontend-design/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-go/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-implement/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-implement/agents/scrutinizer.md +6 -4
- package/plugins/devflow-implement/agents/shepherd.md +26 -12
- package/plugins/devflow-implement/agents/simplifier.md +24 -15
- package/plugins/devflow-implement/agents/skimmer.md +71 -21
- package/plugins/devflow-implement/commands/implement-teams.md +1 -1
- package/plugins/devflow-implement/commands/implement.md +1 -1
- package/plugins/devflow-implement/skills/self-review/references/stub-detection.md +135 -0
- package/plugins/devflow-java/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-python/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-react/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-resolve/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-resolve/agents/simplifier.md +24 -15
- package/plugins/devflow-rust/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-self-review/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-self-review/agents/scrutinizer.md +6 -4
- package/plugins/devflow-self-review/agents/simplifier.md +24 -15
- package/plugins/devflow-self-review/skills/self-review/references/stub-detection.md +135 -0
- package/plugins/devflow-specify/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-specify/agents/skimmer.md +71 -21
- package/plugins/devflow-specify/commands/specify-teams.md +1 -1
- package/plugins/devflow-specify/commands/specify.md +1 -1
- package/plugins/devflow-typescript/.claude-plugin/plugin.json +1 -1
- package/scripts/hud/cache.d.ts +14 -0
- package/scripts/hud/cache.d.ts.map +1 -0
- package/scripts/hud/cache.js +54 -0
- package/scripts/hud/cache.js.map +1 -0
- package/scripts/hud/colors.d.ts +23 -0
- package/scripts/hud/colors.d.ts.map +1 -0
- package/scripts/hud/colors.js +62 -0
- package/scripts/hud/colors.js.map +1 -0
- package/scripts/hud/components/config-counts.d.ts +8 -0
- package/scripts/hud/components/config-counts.d.ts.map +1 -0
- package/scripts/hud/components/config-counts.js +91 -0
- package/scripts/hud/components/config-counts.js.map +1 -0
- package/scripts/hud/components/context-usage.d.ts +8 -0
- package/scripts/hud/components/context-usage.d.ts.map +1 -0
- package/scripts/hud/components/context-usage.js +49 -0
- package/scripts/hud/components/context-usage.js.map +1 -0
- package/scripts/hud/components/diff-stats.d.ts +3 -0
- package/scripts/hud/components/diff-stats.d.ts.map +1 -0
- package/scripts/hud/components/diff-stats.js +36 -0
- package/scripts/hud/components/diff-stats.js.map +1 -0
- package/scripts/hud/components/directory.d.ts +3 -0
- package/scripts/hud/components/directory.d.ts.map +1 -0
- package/scripts/hud/components/directory.js +10 -0
- package/scripts/hud/components/directory.js.map +1 -0
- package/scripts/hud/components/git-ahead-behind.d.ts +3 -0
- package/scripts/hud/components/git-ahead-behind.d.ts.map +1 -0
- package/scripts/hud/components/git-ahead-behind.js +16 -0
- package/scripts/hud/components/git-ahead-behind.js.map +1 -0
- package/scripts/hud/components/git-branch.d.ts +3 -0
- package/scripts/hud/components/git-branch.d.ts.map +1 -0
- package/scripts/hud/components/git-branch.js +14 -0
- package/scripts/hud/components/git-branch.js.map +1 -0
- package/scripts/hud/components/model.d.ts +3 -0
- package/scripts/hud/components/model.d.ts.map +1 -0
- package/scripts/hud/components/model.js +21 -0
- package/scripts/hud/components/model.js.map +1 -0
- package/scripts/hud/components/release-info.d.ts +3 -0
- package/scripts/hud/components/release-info.d.ts.map +1 -0
- package/scripts/hud/components/release-info.js +9 -0
- package/scripts/hud/components/release-info.js.map +1 -0
- package/scripts/hud/components/session-cost.d.ts +3 -0
- package/scripts/hud/components/session-cost.d.ts.map +1 -0
- package/scripts/hud/components/session-cost.js +9 -0
- package/scripts/hud/components/session-cost.js.map +1 -0
- package/scripts/hud/components/session-duration.d.ts +3 -0
- package/scripts/hud/components/session-duration.d.ts.map +1 -0
- package/scripts/hud/components/session-duration.js +18 -0
- package/scripts/hud/components/session-duration.js.map +1 -0
- package/scripts/hud/components/todo-progress.d.ts +3 -0
- package/scripts/hud/components/todo-progress.d.ts.map +1 -0
- package/scripts/hud/components/todo-progress.js +11 -0
- package/scripts/hud/components/todo-progress.js.map +1 -0
- package/scripts/hud/components/usage-quota.d.ts +3 -0
- package/scripts/hud/components/usage-quota.d.ts.map +1 -0
- package/scripts/hud/components/usage-quota.js +45 -0
- package/scripts/hud/components/usage-quota.js.map +1 -0
- package/scripts/hud/components/version-badge.d.ts +3 -0
- package/scripts/hud/components/version-badge.d.ts.map +1 -0
- package/scripts/hud/components/version-badge.js +80 -0
- package/scripts/hud/components/version-badge.js.map +1 -0
- package/scripts/hud/components/worktree-count.d.ts +3 -0
- package/scripts/hud/components/worktree-count.d.ts.map +1 -0
- package/scripts/hud/components/worktree-count.js +8 -0
- package/scripts/hud/components/worktree-count.js.map +1 -0
- package/scripts/hud/config.d.ts +10 -0
- package/scripts/hud/config.d.ts.map +1 -0
- package/scripts/hud/config.js +55 -0
- package/scripts/hud/config.js.map +1 -0
- package/scripts/hud/credentials.d.ts +17 -0
- package/scripts/hud/credentials.d.ts.map +1 -0
- package/scripts/hud/credentials.js +99 -0
- package/scripts/hud/credentials.js.map +1 -0
- package/scripts/hud/git.d.ts +7 -0
- package/scripts/hud/git.d.ts.map +1 -0
- package/scripts/hud/git.js +153 -0
- package/scripts/hud/git.js.map +1 -0
- package/scripts/hud/index.d.ts +2 -0
- package/scripts/hud/index.d.ts.map +1 -0
- package/scripts/hud/index.js +81 -0
- package/scripts/hud/index.js.map +1 -0
- package/scripts/hud/render.d.ts +7 -0
- package/scripts/hud/render.d.ts.map +1 -0
- package/scripts/hud/render.js +111 -0
- package/scripts/hud/render.js.map +1 -0
- package/scripts/hud/stdin.d.ts +6 -0
- package/scripts/hud/stdin.d.ts.map +1 -0
- package/scripts/hud/stdin.js +25 -0
- package/scripts/hud/stdin.js.map +1 -0
- package/scripts/hud/transcript.d.ts +7 -0
- package/scripts/hud/transcript.d.ts.map +1 -0
- package/scripts/hud/transcript.js +130 -0
- package/scripts/hud/transcript.js.map +1 -0
- package/scripts/hud/types.d.ts +116 -0
- package/scripts/hud/types.d.ts.map +1 -0
- package/scripts/hud/types.js +2 -0
- package/scripts/hud/types.js.map +1 -0
- package/scripts/hud/usage-api.d.ts +7 -0
- package/scripts/hud/usage-api.d.ts.map +1 -0
- package/scripts/hud/usage-api.js +84 -0
- package/scripts/hud/usage-api.js.map +1 -0
- package/scripts/hud.sh +5 -0
- package/shared/agents/scrutinizer.md +6 -4
- package/shared/agents/shepherd.md +26 -12
- package/shared/agents/simplifier.md +24 -15
- package/shared/agents/skimmer.md +71 -21
- package/shared/skills/self-review/references/stub-detection.md +135 -0
- package/src/templates/settings.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,49 @@ All notable changes to DevFlow will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.8.0] - 2026-03-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Configurable HUD** replacing bash statusline — 14 components, on/off model (#155)
|
|
12
|
+
- **HUD components**: directory, git branch, ahead/behind, diff stats, release info, worktree count, model, context usage, version badge, session duration, session cost, usage quota, todo progress, config counts
|
|
13
|
+
- **`--hud-only` flag** for standalone HUD install
|
|
14
|
+
- **`--no-hud` flag** to skip HUD during init
|
|
15
|
+
- **`devflow hud` command** (--status, --enable, --disable, --detail, --no-detail)
|
|
16
|
+
- **Version upgrade notification**: `✦ Devflow vX.Y.Z · update: npx devflow-kit init` (yellow, always visible even when HUD disabled)
|
|
17
|
+
- **Skill shadowing docs** and HUD options added to README (#156)
|
|
18
|
+
- **Simplifier agent** — 8 structured slop detection categories (#120)
|
|
19
|
+
- **Scrutinizer agent** — stub detection patterns with reference file (#121)
|
|
20
|
+
- **Shepherd agent** — goal-backward verification, artifact depth checking, stub type, re-verification (#124)
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- Init flow: HUD preset picker (5 options) → simple yes/no confirm
|
|
24
|
+
- `--disable` keeps statusLine registered (version badge still renders)
|
|
25
|
+
- Manifest `features.hud` field: `string|false` → `boolean`
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- HUD base branch detection matching raw commit hashes from reflog (#156)
|
|
29
|
+
- HUD comparing main vs main (0/0 always) — now compares against origin/main
|
|
30
|
+
|
|
31
|
+
### Removed
|
|
32
|
+
- HUD preset system (minimal/classic/standard/full)
|
|
33
|
+
- `--configure`, `--preset`, `--hud <preset>` flags
|
|
34
|
+
- `speed`, `tool-activity`, `agent-activity` components
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## [1.7.0] - 2026-03-20
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
- **Version update notification** — statusline shows magenta `⬆ X.Y.Z` badge when newer devflow-kit is available (24h cached npm check, fully async)
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
- **Skimmer agent** — enforce rskim usage via `tools: ["Bash", "Read"]` platform restriction and strict sequential workflow; prevents fallback to Grep/Glob
|
|
45
|
+
- **Init multiselect** — remove redundant "(optional)" suffix from plugin hints
|
|
46
|
+
- **Init multiselect** — hide `audit-claude` plugin (not production-ready; still installable via `--plugin=audit-claude`)
|
|
47
|
+
- **Statusline portability** — replace macOS-only `stat -f %m` with portable `get_mtime()` helper (macOS + Linux)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
8
51
|
## [1.6.1] - 2026-03-20
|
|
9
52
|
|
|
10
53
|
### Added
|
|
@@ -915,6 +958,8 @@ devflow init
|
|
|
915
958
|
---
|
|
916
959
|
|
|
917
960
|
[Unreleased]: https://github.com/dean0x/devflow/compare/v1.4.0...HEAD
|
|
961
|
+
[1.8.0]: https://github.com/dean0x/devflow/compare/v1.7.0...v1.8.0
|
|
962
|
+
[1.7.0]: https://github.com/dean0x/devflow/compare/v1.6.1...v1.7.0
|
|
918
963
|
[1.6.1]: https://github.com/dean0x/devflow/compare/v1.6.0...v1.6.1
|
|
919
964
|
[1.6.0]: https://github.com/dean0x/devflow/compare/v1.5.0...v1.6.0
|
|
920
965
|
[1.5.0]: https://github.com/dean0x/devflow/compare/v1.4.0...v1.5.0
|
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ DevFlow adds structured commands that handle the full lifecycle: specify feature
|
|
|
24
24
|
- **Full-lifecycle implementation** — spec, explore, plan, code, validate, refine in one command
|
|
25
25
|
- **Automatic session memory** — survives restarts, `/clear`, and context compaction
|
|
26
26
|
- **Parallel debugging** — competing hypotheses investigated simultaneously
|
|
27
|
+
- **Version notifications** — HUD shows `✦ Devflow vX.Y.Z · update: npx devflow-kit init` when a newer version is available
|
|
27
28
|
- **35 quality skills** — 9 auto-activating core, 8 optional language/ecosystem, plus specialized review, agent, and orchestration skills
|
|
28
29
|
|
|
29
30
|
## Quick Start
|
|
@@ -247,8 +248,38 @@ Session context is saved and restored automatically via Working Memory hooks —
|
|
|
247
248
|
| `--teams` / `--no-teams` | Enable/disable Agent Teams (experimental, default: off) |
|
|
248
249
|
| `--ambient` / `--no-ambient` | Enable/disable ambient mode (default: on) |
|
|
249
250
|
| `--memory` / `--no-memory` | Enable/disable working memory (default: on) |
|
|
251
|
+
| `--hud-only` | Install only the HUD (no plugins, hooks, or extras) |
|
|
252
|
+
| `--no-hud` | Disable HUD status line |
|
|
250
253
|
| `--verbose` | Show detailed output |
|
|
251
254
|
|
|
255
|
+
### HUD Options
|
|
256
|
+
|
|
257
|
+
| Command | Description |
|
|
258
|
+
|---------|-------------|
|
|
259
|
+
| `npx devflow-kit hud --status` | Show current HUD config |
|
|
260
|
+
| `npx devflow-kit hud --enable` | Enable HUD |
|
|
261
|
+
| `npx devflow-kit hud --disable` | Disable HUD (version notifications still appear) |
|
|
262
|
+
| `npx devflow-kit hud --detail` | Show tool/agent descriptions |
|
|
263
|
+
| `npx devflow-kit hud --no-detail` | Hide tool/agent descriptions |
|
|
264
|
+
|
|
265
|
+
### Skill Shadowing
|
|
266
|
+
|
|
267
|
+
Override any DevFlow skill with your own version. Shadowed skills survive `devflow init` — they won't be overwritten on reinstall or upgrade.
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# Create a personal override (copies current version as reference)
|
|
271
|
+
npx devflow-kit skills shadow core-patterns
|
|
272
|
+
|
|
273
|
+
# Edit your override
|
|
274
|
+
vim ~/.claude/skills/core-patterns/SKILL.md
|
|
275
|
+
|
|
276
|
+
# List all overrides
|
|
277
|
+
npx devflow-kit skills list-shadowed
|
|
278
|
+
|
|
279
|
+
# Remove override (next init restores DevFlow's version)
|
|
280
|
+
npx devflow-kit skills unshadow core-patterns
|
|
281
|
+
```
|
|
282
|
+
|
|
252
283
|
### Uninstall Options
|
|
253
284
|
|
|
254
285
|
| Option | Description |
|
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { listCommand } from './commands/list.js';
|
|
|
9
9
|
import { ambientCommand } from './commands/ambient.js';
|
|
10
10
|
import { memoryCommand } from './commands/memory.js';
|
|
11
11
|
import { skillsCommand } from './commands/skills.js';
|
|
12
|
+
import { hudCommand } from './commands/hud.js';
|
|
12
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
14
|
const __dirname = dirname(__filename);
|
|
14
15
|
// Read version from package.json
|
|
@@ -19,7 +20,7 @@ program
|
|
|
19
20
|
.description('Agentic Development Toolkit for Claude Code\n\nEnhance your AI-assisted development with intelligent commands and workflows.')
|
|
20
21
|
.version(packageJson.version, '-v, --version', 'Display version number')
|
|
21
22
|
.helpOption('-h, --help', 'Display help information')
|
|
22
|
-
.addHelpText('after', '\nExamples:\n $ devflow init Install all DevFlow plugins\n $ devflow init --plugin=implement Install specific plugin\n $ devflow init --plugin=implement,review Install multiple plugins\n $ devflow list List available plugins\n $ devflow ambient --enable Enable always-on ambient mode\n $ devflow memory --status Check working memory state\n $ devflow uninstall Remove DevFlow from Claude Code\n $ devflow --version Show version\n $ devflow --help Show help\n\nDocumentation:\n https://github.com/dean0x/devflow#readme');
|
|
23
|
+
.addHelpText('after', '\nExamples:\n $ devflow init Install all DevFlow plugins\n $ devflow init --plugin=implement Install specific plugin\n $ devflow init --plugin=implement,review Install multiple plugins\n $ devflow list List available plugins\n $ devflow ambient --enable Enable always-on ambient mode\n $ devflow memory --status Check working memory state\n $ devflow hud --configure Configure HUD preset\n $ devflow uninstall Remove DevFlow from Claude Code\n $ devflow --version Show version\n $ devflow --help Show help\n\nDocumentation:\n https://github.com/dean0x/devflow#readme');
|
|
23
24
|
// Register commands
|
|
24
25
|
program.addCommand(initCommand);
|
|
25
26
|
program.addCommand(uninstallCommand);
|
|
@@ -27,6 +28,7 @@ program.addCommand(listCommand);
|
|
|
27
28
|
program.addCommand(ambientCommand);
|
|
28
29
|
program.addCommand(memoryCommand);
|
|
29
30
|
program.addCommand(skillsCommand);
|
|
31
|
+
program.addCommand(hudCommand);
|
|
30
32
|
// Handle no command
|
|
31
33
|
program.action(() => {
|
|
32
34
|
program.help();
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
/**
|
|
3
|
+
* Add the HUD statusLine to settings JSON.
|
|
4
|
+
* Idempotent — returns unchanged JSON if HUD already set.
|
|
5
|
+
* Upgrades legacy statusline.sh to hud.sh automatically.
|
|
6
|
+
*/
|
|
7
|
+
export declare function addHudStatusLine(settingsJson: string, devflowDir: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Remove the HUD statusLine from settings JSON.
|
|
10
|
+
* Idempotent — returns unchanged JSON if statusLine not present or not DevFlow.
|
|
11
|
+
*/
|
|
12
|
+
export declare function removeHudStatusLine(settingsJson: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Check if the statusLine in settings JSON points to the DevFlow HUD.
|
|
15
|
+
*/
|
|
16
|
+
export declare function hasHudStatusLine(settingsJson: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Check if an existing statusLine belongs to a non-DevFlow tool.
|
|
19
|
+
*/
|
|
20
|
+
export declare function hasNonDevFlowStatusLine(settingsJson: string): boolean;
|
|
21
|
+
export declare const hudCommand: Command;
|
|
22
|
+
//# sourceMappingURL=hud.d.ts.map
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import * as p from '@clack/prompts';
|
|
5
|
+
import color from 'picocolors';
|
|
6
|
+
import { getClaudeDirectory, getDevFlowDirectory } from '../utils/paths.js';
|
|
7
|
+
import { HUD_COMPONENTS, loadConfig, saveConfig, } from '../hud/config.js';
|
|
8
|
+
/**
|
|
9
|
+
* Add the HUD statusLine to settings JSON.
|
|
10
|
+
* Idempotent — returns unchanged JSON if HUD already set.
|
|
11
|
+
* Upgrades legacy statusline.sh to hud.sh automatically.
|
|
12
|
+
*/
|
|
13
|
+
export function addHudStatusLine(settingsJson, devflowDir) {
|
|
14
|
+
const settings = JSON.parse(settingsJson);
|
|
15
|
+
const hudCommand = path.join(devflowDir, 'scripts', 'hud.sh');
|
|
16
|
+
// Already pointing to this exact HUD — nothing to do
|
|
17
|
+
if (settings.statusLine?.command === hudCommand) {
|
|
18
|
+
return settingsJson;
|
|
19
|
+
}
|
|
20
|
+
// If there's a non-DevFlow statusLine, don't overwrite (caller should check first)
|
|
21
|
+
if (settings.statusLine && !isDevFlowStatusLine(settings.statusLine)) {
|
|
22
|
+
return settingsJson;
|
|
23
|
+
}
|
|
24
|
+
settings.statusLine = {
|
|
25
|
+
type: 'command',
|
|
26
|
+
command: hudCommand,
|
|
27
|
+
};
|
|
28
|
+
return JSON.stringify(settings, null, 2) + '\n';
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Remove the HUD statusLine from settings JSON.
|
|
32
|
+
* Idempotent — returns unchanged JSON if statusLine not present or not DevFlow.
|
|
33
|
+
*/
|
|
34
|
+
export function removeHudStatusLine(settingsJson) {
|
|
35
|
+
const settings = JSON.parse(settingsJson);
|
|
36
|
+
if (!settings.statusLine) {
|
|
37
|
+
return settingsJson;
|
|
38
|
+
}
|
|
39
|
+
// Only remove if it's a DevFlow HUD/statusline
|
|
40
|
+
if (!isDevFlowStatusLine(settings.statusLine)) {
|
|
41
|
+
return settingsJson;
|
|
42
|
+
}
|
|
43
|
+
delete settings.statusLine;
|
|
44
|
+
return JSON.stringify(settings, null, 2) + '\n';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if the statusLine in settings JSON points to the DevFlow HUD.
|
|
48
|
+
*/
|
|
49
|
+
export function hasHudStatusLine(settingsJson) {
|
|
50
|
+
const settings = JSON.parse(settingsJson);
|
|
51
|
+
if (!settings.statusLine)
|
|
52
|
+
return false;
|
|
53
|
+
return isDevFlowStatusLine(settings.statusLine);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if an existing statusLine belongs to DevFlow (HUD or legacy statusline).
|
|
57
|
+
* Matches paths containing 'hud.sh', 'statusline.sh', or a '/devflow/' directory segment.
|
|
58
|
+
*/
|
|
59
|
+
function isDevFlowStatusLine(statusLine) {
|
|
60
|
+
const cmd = statusLine.command ?? '';
|
|
61
|
+
return (cmd.includes('hud.sh') ||
|
|
62
|
+
cmd.includes('statusline.sh') ||
|
|
63
|
+
cmd.includes('/devflow/') ||
|
|
64
|
+
cmd.includes('\\devflow\\'));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if an existing statusLine belongs to a non-DevFlow tool.
|
|
68
|
+
*/
|
|
69
|
+
export function hasNonDevFlowStatusLine(settingsJson) {
|
|
70
|
+
const settings = JSON.parse(settingsJson);
|
|
71
|
+
if (!settings.statusLine?.command)
|
|
72
|
+
return false;
|
|
73
|
+
return !isDevFlowStatusLine(settings.statusLine);
|
|
74
|
+
}
|
|
75
|
+
export const hudCommand = new Command('hud')
|
|
76
|
+
.description('Configure the HUD (status line)')
|
|
77
|
+
.option('--status', 'Show current HUD config')
|
|
78
|
+
.option('--detail', 'Show tool/agent descriptions in HUD')
|
|
79
|
+
.option('--no-detail', 'Hide tool/agent descriptions')
|
|
80
|
+
.option('--enable', 'Enable HUD in settings')
|
|
81
|
+
.option('--disable', 'Disable HUD (remove statusLine)')
|
|
82
|
+
.action(async (options) => {
|
|
83
|
+
const hasFlag = options.status ||
|
|
84
|
+
options.enable ||
|
|
85
|
+
options.disable ||
|
|
86
|
+
options.detail !== undefined;
|
|
87
|
+
if (!hasFlag) {
|
|
88
|
+
p.intro(color.bgCyan(color.white(' HUD ')));
|
|
89
|
+
p.note(`${color.cyan('devflow hud --detail')} Show tool/agent descriptions\n` +
|
|
90
|
+
`${color.cyan('devflow hud --no-detail')} Hide tool/agent descriptions\n` +
|
|
91
|
+
`${color.cyan('devflow hud --status')} Show current config\n` +
|
|
92
|
+
`${color.cyan('devflow hud --enable')} Enable HUD in settings\n` +
|
|
93
|
+
`${color.cyan('devflow hud --disable')} Remove HUD from settings`, 'Usage');
|
|
94
|
+
p.note(`${HUD_COMPONENTS.length} components: ${HUD_COMPONENTS.join(', ')}`, 'Components');
|
|
95
|
+
p.outro(color.dim('Toggle with --enable / --disable'));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (options.status) {
|
|
99
|
+
const config = loadConfig();
|
|
100
|
+
p.intro(color.bgCyan(color.white(' HUD Status ')));
|
|
101
|
+
p.note(`${color.dim('Enabled:')} ${config.enabled ? color.green('yes') : color.dim('no')}\n` +
|
|
102
|
+
`${color.dim('Detail:')} ${config.detail ? color.green('on') : color.dim('off')}\n` +
|
|
103
|
+
`${color.dim('Components:')} ${HUD_COMPONENTS.length}`, 'Current config');
|
|
104
|
+
// Check settings.json
|
|
105
|
+
const claudeDir = getClaudeDirectory();
|
|
106
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
107
|
+
try {
|
|
108
|
+
const content = await fs.readFile(settingsPath, 'utf-8');
|
|
109
|
+
const enabled = hasHudStatusLine(content);
|
|
110
|
+
p.log.info(`Status line: ${enabled ? color.green('enabled') : color.dim('disabled')}`);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
p.log.info(`Status line: ${color.dim('no settings.json found')}`);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (options.detail !== undefined) {
|
|
118
|
+
const config = loadConfig();
|
|
119
|
+
config.detail = options.detail;
|
|
120
|
+
saveConfig(config);
|
|
121
|
+
p.log.success(`HUD detail ${config.detail ? 'enabled' : 'disabled'}`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (options.enable) {
|
|
125
|
+
const claudeDir = getClaudeDirectory();
|
|
126
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
127
|
+
let settingsContent;
|
|
128
|
+
try {
|
|
129
|
+
settingsContent = await fs.readFile(settingsPath, 'utf-8');
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
settingsContent = '{}';
|
|
133
|
+
}
|
|
134
|
+
// Ensure statusLine is registered
|
|
135
|
+
if (!hasHudStatusLine(settingsContent)) {
|
|
136
|
+
// Check for non-DevFlow statusLine
|
|
137
|
+
if (hasNonDevFlowStatusLine(settingsContent)) {
|
|
138
|
+
const settings = JSON.parse(settingsContent);
|
|
139
|
+
p.log.warn(`Existing statusLine found: ${color.dim(settings.statusLine?.command ?? 'unknown')}`);
|
|
140
|
+
if (process.stdin.isTTY) {
|
|
141
|
+
const overwrite = await p.confirm({
|
|
142
|
+
message: 'Replace existing statusLine with DevFlow HUD?',
|
|
143
|
+
initialValue: false,
|
|
144
|
+
});
|
|
145
|
+
if (p.isCancel(overwrite) || !overwrite) {
|
|
146
|
+
p.log.info('HUD not enabled — existing statusLine preserved');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
p.log.info('Non-interactive mode — skipping (existing statusLine would be overwritten)');
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const devflowDir = getDevFlowDirectory();
|
|
156
|
+
const updated = addHudStatusLine(settingsContent, devflowDir);
|
|
157
|
+
await fs.writeFile(settingsPath, updated, 'utf-8');
|
|
158
|
+
}
|
|
159
|
+
// Update config
|
|
160
|
+
const config = loadConfig();
|
|
161
|
+
if (config.enabled) {
|
|
162
|
+
p.log.info('HUD already enabled');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
saveConfig({ ...config, enabled: true });
|
|
166
|
+
p.log.success('HUD enabled');
|
|
167
|
+
p.log.info(color.dim('Restart Claude Code to see the HUD'));
|
|
168
|
+
}
|
|
169
|
+
if (options.disable) {
|
|
170
|
+
const config = loadConfig();
|
|
171
|
+
if (!config.enabled) {
|
|
172
|
+
p.log.info('HUD already disabled');
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
saveConfig({ ...config, enabled: false });
|
|
176
|
+
p.log.success('HUD disabled');
|
|
177
|
+
p.log.info(color.dim('Version upgrade notifications will still appear'));
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
//# sourceMappingURL=hud.js.map
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type PluginDefinition } from '../plugins.js';
|
|
|
3
3
|
export { substituteSettingsTemplate, computeGitignoreAppend, applyTeamsConfig, stripTeamsConfig, mergeDenyList } from '../utils/post-install.js';
|
|
4
4
|
export { addAmbientHook, removeAmbientHook, hasAmbientHook } from './ambient.js';
|
|
5
5
|
export { addMemoryHooks, removeMemoryHooks, hasMemoryHooks } from './memory.js';
|
|
6
|
+
export { addHudStatusLine, removeHudStatusLine, hasHudStatusLine } from './hud.js';
|
|
6
7
|
/**
|
|
7
8
|
* Parse a comma-separated plugin selection string into normalized plugin names.
|
|
8
9
|
* Validates against known plugins; returns invalid names as errors.
|
package/dist/commands/init.js
CHANGED
|
@@ -8,18 +8,21 @@ import color from 'picocolors';
|
|
|
8
8
|
import { getInstallationPaths } from '../utils/paths.js';
|
|
9
9
|
import { getGitRoot } from '../utils/git.js';
|
|
10
10
|
import { isClaudeCliAvailable } from '../utils/cli.js';
|
|
11
|
-
import { installViaCli, installViaFileCopy } from '../utils/installer.js';
|
|
11
|
+
import { installViaCli, installViaFileCopy, copyDirectory } from '../utils/installer.js';
|
|
12
12
|
import { installSettings, installManagedSettings, installClaudeignore, updateGitignore, createDocsStructure, createMemoryDir, migrateMemoryFiles, } from '../utils/post-install.js';
|
|
13
13
|
import { DEVFLOW_PLUGINS, LEGACY_SKILL_NAMES, LEGACY_COMMAND_NAMES, buildAssetMaps } from '../plugins.js';
|
|
14
14
|
import { detectPlatform, detectShell, getProfilePath, getSafeDeleteInfo, hasSafeDelete } from '../utils/safe-delete.js';
|
|
15
15
|
import { generateSafeDeleteBlock, installToProfile, removeFromProfile, getInstalledVersion, SAFE_DELETE_BLOCK_VERSION } from '../utils/safe-delete-install.js';
|
|
16
16
|
import { addAmbientHook } from './ambient.js';
|
|
17
17
|
import { addMemoryHooks, removeMemoryHooks } from './memory.js';
|
|
18
|
+
import { addHudStatusLine, removeHudStatusLine } from './hud.js';
|
|
19
|
+
import { loadConfig as loadHudConfig, saveConfig as saveHudConfig } from '../hud/config.js';
|
|
18
20
|
import { readManifest, writeManifest, resolvePluginList, detectUpgrade } from '../utils/manifest.js';
|
|
19
21
|
// Re-export pure functions for tests (canonical source is post-install.ts)
|
|
20
22
|
export { substituteSettingsTemplate, computeGitignoreAppend, applyTeamsConfig, stripTeamsConfig, mergeDenyList } from '../utils/post-install.js';
|
|
21
23
|
export { addAmbientHook, removeAmbientHook, hasAmbientHook } from './ambient.js';
|
|
22
24
|
export { addMemoryHooks, removeMemoryHooks, hasMemoryHooks } from './memory.js';
|
|
25
|
+
export { addHudStatusLine, removeHudStatusLine, hasHudStatusLine } from './hud.js';
|
|
23
26
|
const __filename = fileURLToPath(import.meta.url);
|
|
24
27
|
const __dirname = dirname(__filename);
|
|
25
28
|
/**
|
|
@@ -66,6 +69,8 @@ export const initCommand = new Command('init')
|
|
|
66
69
|
.option('--no-ambient', 'Disable ambient mode')
|
|
67
70
|
.option('--memory', 'Enable working memory (session context preservation)')
|
|
68
71
|
.option('--no-memory', 'Disable working memory hooks')
|
|
72
|
+
.option('--no-hud', 'Disable HUD status line')
|
|
73
|
+
.option('--hud-only', 'Install only the HUD (no plugins, hooks, or extras)')
|
|
69
74
|
.action(async (options) => {
|
|
70
75
|
// Get package version
|
|
71
76
|
const packageJsonPath = path.resolve(__dirname, '../../package.json');
|
|
@@ -82,7 +87,11 @@ export const initCommand = new Command('init')
|
|
|
82
87
|
p.intro(color.bgCyan(color.black(` DevFlow v${version} `)));
|
|
83
88
|
// Determine installation scope
|
|
84
89
|
let scope = 'user';
|
|
85
|
-
if (options.
|
|
90
|
+
if (options.hudOnly) {
|
|
91
|
+
// --hud-only: skip scope prompt, always user scope
|
|
92
|
+
scope = 'user';
|
|
93
|
+
}
|
|
94
|
+
else if (options.scope) {
|
|
86
95
|
const normalizedScope = options.scope.toLowerCase();
|
|
87
96
|
if (normalizedScope !== 'user' && normalizedScope !== 'local') {
|
|
88
97
|
p.log.error('Invalid scope. Use "user" or "local"');
|
|
@@ -108,6 +117,70 @@ export const initCommand = new Command('init')
|
|
|
108
117
|
}
|
|
109
118
|
scope = selected;
|
|
110
119
|
}
|
|
120
|
+
// --hud-only: install only HUD (skip plugins, hooks, extras)
|
|
121
|
+
if (options.hudOnly) {
|
|
122
|
+
// Resolve paths
|
|
123
|
+
const paths = await getInstallationPaths(scope);
|
|
124
|
+
const claudeDir = paths.claudeDir;
|
|
125
|
+
const devflowDir = paths.devflowDir;
|
|
126
|
+
// Save HUD config
|
|
127
|
+
const existingHud = loadHudConfig();
|
|
128
|
+
saveHudConfig({ enabled: true, detail: existingHud.detail });
|
|
129
|
+
// Update statusLine in settings.json
|
|
130
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
131
|
+
try {
|
|
132
|
+
let content;
|
|
133
|
+
try {
|
|
134
|
+
content = await fs.readFile(settingsPath, 'utf-8');
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
content = '{}';
|
|
138
|
+
}
|
|
139
|
+
const updated = addHudStatusLine(content, devflowDir);
|
|
140
|
+
await fs.writeFile(settingsPath, updated, 'utf-8');
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
p.log.error(`Failed to update settings: ${error instanceof Error ? error.message : error}`);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
// Copy HUD scripts to devflow dir
|
|
147
|
+
const rootDir = path.resolve(__dirname, '..', '..');
|
|
148
|
+
const scriptsSource = path.join(rootDir, 'scripts');
|
|
149
|
+
const scriptsTarget = path.join(devflowDir, 'scripts');
|
|
150
|
+
try {
|
|
151
|
+
await fs.mkdir(scriptsTarget, { recursive: true });
|
|
152
|
+
// Copy hud.sh
|
|
153
|
+
await fs.copyFile(path.join(scriptsSource, 'hud.sh'), path.join(scriptsTarget, 'hud.sh'));
|
|
154
|
+
// Copy hud/ directory
|
|
155
|
+
const hudSource = path.join(scriptsSource, 'hud');
|
|
156
|
+
const hudTarget = path.join(scriptsTarget, 'hud');
|
|
157
|
+
await copyDirectory(hudSource, hudTarget);
|
|
158
|
+
if (process.platform !== 'win32') {
|
|
159
|
+
await fs.chmod(path.join(scriptsTarget, 'hud.sh'), 0o755);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
p.log.error(`Failed to copy HUD scripts: ${error instanceof Error ? error.message : error}`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
// Write minimal manifest
|
|
167
|
+
const now = new Date().toISOString();
|
|
168
|
+
try {
|
|
169
|
+
await writeManifest(devflowDir, {
|
|
170
|
+
version,
|
|
171
|
+
plugins: [],
|
|
172
|
+
scope,
|
|
173
|
+
features: { teams: false, ambient: false, memory: false, hud: true },
|
|
174
|
+
installedAt: now,
|
|
175
|
+
updatedAt: now,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch { /* non-fatal */ }
|
|
179
|
+
p.log.success('HUD installed');
|
|
180
|
+
p.log.info(`Configure later: ${color.cyan('devflow hud --status')}`);
|
|
181
|
+
p.outro(color.green('HUD-only install complete.'));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
111
184
|
// Select plugins to install
|
|
112
185
|
let selectedPlugins = [];
|
|
113
186
|
if (options.plugin) {
|
|
@@ -121,11 +194,11 @@ export const initCommand = new Command('init')
|
|
|
121
194
|
}
|
|
122
195
|
else if (process.stdin.isTTY) {
|
|
123
196
|
const choices = DEVFLOW_PLUGINS
|
|
124
|
-
.filter(pl => pl.name !== 'devflow-core-skills' && pl.name !== 'devflow-ambient')
|
|
197
|
+
.filter(pl => pl.name !== 'devflow-core-skills' && pl.name !== 'devflow-ambient' && pl.name !== 'devflow-audit-claude')
|
|
125
198
|
.map(pl => ({
|
|
126
199
|
value: pl.name,
|
|
127
200
|
label: pl.name.replace('devflow-', ''),
|
|
128
|
-
hint: pl.description
|
|
201
|
+
hint: pl.description,
|
|
129
202
|
}));
|
|
130
203
|
const preSelected = DEVFLOW_PLUGINS
|
|
131
204
|
.filter(pl => !pl.optional && pl.name !== 'devflow-core-skills' && pl.name !== 'devflow-ambient')
|
|
@@ -205,6 +278,25 @@ export const initCommand = new Command('init')
|
|
|
205
278
|
}
|
|
206
279
|
memoryEnabled = memoryChoice;
|
|
207
280
|
}
|
|
281
|
+
// HUD selection (yes/no)
|
|
282
|
+
let hudEnabled;
|
|
283
|
+
if (options.hud !== undefined) {
|
|
284
|
+
hudEnabled = options.hud;
|
|
285
|
+
}
|
|
286
|
+
else if (!process.stdin.isTTY) {
|
|
287
|
+
hudEnabled = true;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
const hudChoice = await p.confirm({
|
|
291
|
+
message: 'Enable HUD status line?',
|
|
292
|
+
initialValue: true,
|
|
293
|
+
});
|
|
294
|
+
if (p.isCancel(hudChoice)) {
|
|
295
|
+
p.cancel('Installation cancelled.');
|
|
296
|
+
process.exit(0);
|
|
297
|
+
}
|
|
298
|
+
hudEnabled = hudChoice;
|
|
299
|
+
}
|
|
208
300
|
// Security deny list placement (user scope + TTY only)
|
|
209
301
|
let securityMode = 'user';
|
|
210
302
|
if (scope === 'user' && process.stdin.isTTY) {
|
|
@@ -442,6 +534,23 @@ export const initCommand = new Command('init')
|
|
|
442
534
|
await createMemoryDir(verbose);
|
|
443
535
|
await migrateMemoryFiles(verbose);
|
|
444
536
|
}
|
|
537
|
+
// Configure HUD
|
|
538
|
+
const existingHud = loadHudConfig();
|
|
539
|
+
saveHudConfig({ enabled: hudEnabled, detail: existingHud.detail });
|
|
540
|
+
// Update statusLine in settings.json (add or remove based on choice)
|
|
541
|
+
try {
|
|
542
|
+
const hudContent = await fs.readFile(settingsPath, 'utf-8');
|
|
543
|
+
const hudUpdated = hudEnabled
|
|
544
|
+
? addHudStatusLine(hudContent, devflowDir)
|
|
545
|
+
: removeHudStatusLine(hudContent);
|
|
546
|
+
if (hudUpdated !== hudContent) {
|
|
547
|
+
await fs.writeFile(settingsPath, hudUpdated, 'utf-8');
|
|
548
|
+
if (verbose) {
|
|
549
|
+
p.log.info(`HUD ${hudEnabled ? 'enabled' : 'disabled'}`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
catch { /* settings.json may not exist yet */ }
|
|
445
554
|
}
|
|
446
555
|
const fileExtras = selectedExtras.filter(e => e !== 'settings' && e !== 'safe-delete');
|
|
447
556
|
if (fileExtras.length > 0) {
|
|
@@ -542,7 +651,7 @@ export const initCommand = new Command('init')
|
|
|
542
651
|
version,
|
|
543
652
|
plugins: resolvePluginList(installedPluginNames, existingManifest, !!options.plugin),
|
|
544
653
|
scope,
|
|
545
|
-
features: { teams: teamsEnabled, ambient: ambientEnabled, memory: memoryEnabled },
|
|
654
|
+
features: { teams: teamsEnabled, ambient: ambientEnabled, memory: memoryEnabled, hud: hudEnabled },
|
|
546
655
|
installedAt: existingManifest?.installedAt ?? now,
|
|
547
656
|
updatedAt: now,
|
|
548
657
|
};
|
package/dist/commands/list.js
CHANGED
|
@@ -11,6 +11,7 @@ import { isClaudeCliAvailable } from '../utils/cli.js';
|
|
|
11
11
|
import { DEVFLOW_PLUGINS, getAllSkillNames, LEGACY_SKILL_NAMES } from '../plugins.js';
|
|
12
12
|
import { removeAmbientHook } from './ambient.js';
|
|
13
13
|
import { removeMemoryHooks } from './memory.js';
|
|
14
|
+
import { removeHudStatusLine } from './hud.js';
|
|
14
15
|
import { listShadowed } from './skills.js';
|
|
15
16
|
import { detectShell, getProfilePath } from '../utils/safe-delete.js';
|
|
16
17
|
import { isAlreadyInstalled, removeFromProfile } from '../utils/safe-delete-install.js';
|
|
@@ -360,23 +361,15 @@ export const uninstallCommand = new Command('uninstall')
|
|
|
360
361
|
try {
|
|
361
362
|
const paths = await getInstallationPaths(scope);
|
|
362
363
|
const settingsPath = path.join(paths.claudeDir, 'settings.json');
|
|
363
|
-
|
|
364
|
-
//
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
364
|
+
const originalContent = await fs.readFile(settingsPath, 'utf-8');
|
|
365
|
+
// Remove all DevFlow hooks in one pass (idempotent)
|
|
366
|
+
let settingsContent = removeAmbientHook(originalContent);
|
|
367
|
+
settingsContent = removeMemoryHooks(settingsContent);
|
|
368
|
+
settingsContent = removeHudStatusLine(settingsContent);
|
|
369
|
+
if (settingsContent !== originalContent) {
|
|
370
|
+
await fs.writeFile(settingsPath, settingsContent, 'utf-8');
|
|
369
371
|
if (verbose) {
|
|
370
|
-
p.log.success(`
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
// Always remove memory hooks on full uninstall (idempotent)
|
|
374
|
-
const withoutMemory = removeMemoryHooks(settingsContent);
|
|
375
|
-
if (withoutMemory !== settingsContent) {
|
|
376
|
-
await fs.writeFile(settingsPath, withoutMemory, 'utf-8');
|
|
377
|
-
settingsContent = withoutMemory;
|
|
378
|
-
if (verbose) {
|
|
379
|
-
p.log.success(`Memory hooks removed from settings.json (${scope})`);
|
|
372
|
+
p.log.success(`DevFlow hooks removed from settings.json (${scope})`);
|
|
380
373
|
}
|
|
381
374
|
}
|
|
382
375
|
const settings = JSON.parse(settingsContent);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function getCacheDir(): string;
|
|
2
|
+
/**
|
|
3
|
+
* Read a cached value. Returns null if missing or expired.
|
|
4
|
+
*/
|
|
5
|
+
export declare function readCache<T>(key: string): T | null;
|
|
6
|
+
/**
|
|
7
|
+
* Read a cached value regardless of TTL (stale data). Returns null if missing.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readCacheStale<T>(key: string): T | null;
|
|
10
|
+
/**
|
|
11
|
+
* Write a value to cache with a TTL in milliseconds.
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeCache<T>(key: string, data: T, ttlMs: number): void;
|
|
14
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as path from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
export function getCacheDir() {
|
|
5
|
+
const devflowDir = process.env.DEVFLOW_DIR || path.join(process.env.HOME || homedir(), '.devflow');
|
|
6
|
+
return path.join(devflowDir, 'cache');
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Read a cached value. Returns null if missing or expired.
|
|
10
|
+
* When `ignoreExpiry` is true, returns data regardless of TTL (stale read).
|
|
11
|
+
*/
|
|
12
|
+
function readCacheEntry(key, ignoreExpiry) {
|
|
13
|
+
try {
|
|
14
|
+
const filePath = path.join(getCacheDir(), `${key}.json`);
|
|
15
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
16
|
+
const entry = JSON.parse(raw);
|
|
17
|
+
if (ignoreExpiry || Date.now() - entry.timestamp < entry.ttl) {
|
|
18
|
+
return entry.data;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Read a cached value. Returns null if missing or expired.
|
|
28
|
+
*/
|
|
29
|
+
export function readCache(key) {
|
|
30
|
+
return readCacheEntry(key, false);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Read a cached value regardless of TTL (stale data). Returns null if missing.
|
|
34
|
+
*/
|
|
35
|
+
export function readCacheStale(key) {
|
|
36
|
+
return readCacheEntry(key, true);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Write a value to cache with a TTL in milliseconds.
|
|
40
|
+
*/
|
|
41
|
+
export function writeCache(key, data, ttlMs) {
|
|
42
|
+
try {
|
|
43
|
+
const dir = getCacheDir();
|
|
44
|
+
if (!fs.existsSync(dir)) {
|
|
45
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
46
|
+
}
|
|
47
|
+
const entry = { data, timestamp: Date.now(), ttl: ttlMs };
|
|
48
|
+
fs.writeFileSync(path.join(dir, `${key}.json`), JSON.stringify(entry));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Cache write failure is non-fatal
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=cache.js.map
|