worclaude 2.4.5 → 2.4.7

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
@@ -4,6 +4,44 @@ All notable changes to worclaude are documented in this file. Format loosely fol
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [2.4.7] — 2026-04-20
8
+
9
+ Bug fix release — the learn-capture Stop hook writes `.claude/.stop-hook-active` as a runtime re-entry guard, but the scaffolded `.gitignore` never covered it. Every project scaffolded or upgraded to 2.4.6 saw a dirty `git status` right after the Stop hook fired. `worclaude delete` also left the now-stale line in `.gitignore`. Both are fixed symmetrically.
10
+
11
+ ### Fixed
12
+
13
+ - `worclaude init` and `worclaude upgrade` now append `.claude/.stop-hook-active` to `.gitignore`. Pre-v2.4.7 installs pick up the missing entry on the next `upgrade`.
14
+ - `worclaude delete` now removes the `.claude/.stop-hook-active` line from `.gitignore` alongside the other worclaude entries. `.claude-backup-*/` and `.claude/learnings/` remain intentionally preserved so personal/backup content stays ignored after uninstall.
15
+
16
+ ### Changed
17
+
18
+ - `docs/reference/configuration.md` — gitignore entries reference now lists all 7 entries (previously out of date — missing `.claude/learnings/` too) with a one-line note on the stop-hook flag.
19
+
20
+ ## [2.4.6] — 2026-04-19
21
+
22
+ Bug fix release — `worclaude upgrade` was silently no-oping when the installed and CLI versions matched, even when on-disk files were missing. `worclaude doctor` flagged drift, but the upgrade command refused to reconcile it. This release adds a drift-repair pass to `upgrade` and exposes new flags.
23
+
24
+ ### Fixed
25
+
26
+ - `upgrade` now repairs on-disk drift (files listed in `workflow-meta.json` `fileHashes` but missing from disk) instead of pruning their hash entries. When versions match and drift exists, `upgrade` enters a "Repair-only" flow (preview → confirm → apply), version unchanged. When the installation is clean, behavior is unchanged — `Already up to date (vX.Y.Z)` and exit.
27
+ - Hook scripts (`.claude/hooks/*.{cjs,js}`) and `AGENTS.md` (tracked as `root/AGENTS.md`) are now part of `buildTemplateHashMap`, so missing copies are detected and restored. Pre-v2.4.6 installs pick them up via the `newFiles` path on first upgrade. User-edited copies on disk with no corresponding `fileHashes` entry are preserved — a `.workflow-ref` sidecar is written instead of overwriting.
28
+ - `.claude/learnings/` directory is re-created (with `.gitkeep`) when missing.
29
+ - When `CLAUDE.md` lacks memory-architecture guidance keywords, `CLAUDE.md.workflow-ref.md` is written alongside with suggested additions. `CLAUDE.md` itself is never auto-modified.
30
+
31
+ ### Added
32
+
33
+ - `worclaude upgrade --dry-run` — preview repair + template changes without writing.
34
+ - `worclaude upgrade --yes` — skip confirmation prompts (useful in CI / scripted flows).
35
+ - `worclaude upgrade --repair-only` — restore missing files without applying template updates, even when versions differ.
36
+ - New `src/core/drift-checks.js` module (`hasClaudeMdMemoryGuidance`, `ensureLearningsDir`, `writeMemoryGuidanceSidecar`) shared by `doctor` and `upgrade` so keyword checks stay aligned.
37
+ - New `src/core/variables.js` module — extracted `LANGUAGE_COMMANDS` / `buildCommandsBlock` from `init.js` and added `buildAgentsMdVariables(meta, projectRoot)` for repair flows. `init.js` now imports from it.
38
+
39
+ ### Changed
40
+
41
+ - `categorizeFiles` now returns `missingExpected` and `missingUntracked` instead of a single `deleted` array. `diff.js` renders them as "Missing (will be restored by upgrade)" and "Deleted (removed in current version)" respectively. `upgrade.js` only prunes hashes for `missingUntracked`.
42
+ - `doctor.js` `checkClaudeMdMemoryGuidance` now points users to the sidecar flow: `"Run worclaude upgrade to write a CLAUDE.md.workflow-ref.md sidecar with suggested additions."`
43
+ - `computeFileHashes` now also hashes `AGENTS.md` at the project root (as `root/AGENTS.md`) so freshly-initialized projects track it from the start.
44
+
7
45
  ## [2.4.5] — 2026-04-19
8
46
 
9
47
  Internal CI tooling patch. No change to the scaffolded output or the npm package surface — `worclaude init` / `upgrade` produce identical output to 2.4.4.
package/README.md CHANGED
@@ -122,7 +122,7 @@ claude --worktree --tmux
122
122
  | Command | Description |
123
123
  | ------------------- | ----------------------------------------------------------- |
124
124
  | `worclaude init` | Scaffold workflow into new or existing project |
125
- | `worclaude upgrade` | Update universal components to the latest version |
125
+ | `worclaude upgrade` | Update universal components and repair on-disk drift |
126
126
  | `worclaude status` | Show current workflow state, version, and npm update status |
127
127
  | `worclaude backup` | Create a timestamped backup of workflow files |
128
128
  | `worclaude restore` | Restore from a previous backup |
@@ -130,7 +130,7 @@ claude --worktree --tmux
130
130
  | `worclaude delete` | Remove worclaude workflow from project |
131
131
  | `worclaude doctor` | Validate workflow installation health |
132
132
 
133
- The `init` command detects existing setups and merges intelligently — no data is overwritten without your confirmation. Use `upgrade` to pull in new features while preserving your customizations.
133
+ The `init` command detects existing setups and merges intelligently — no data is overwritten without your confirmation. Use `upgrade` to pull in new features, restore missing files, and preserve your customizations. `upgrade` accepts `--dry-run`, `--yes`, and `--repair-only` for scripted flows.
134
134
 
135
135
  See the [full command reference](https://sefaertunc.github.io/Worclaude/reference/commands) for detailed usage and options.
136
136
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "worclaude",
3
- "version": "2.4.5",
3
+ "version": "2.4.7",
4
4
  "description": "The Workflow Layer for Claude Code — scaffold agents, commands, skills, hooks, and memory into any project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,10 +32,19 @@ export async function diffCommand() {
32
32
  display.newline();
33
33
  }
34
34
 
35
- if (categories.deleted.length > 0) {
35
+ if (categories.missingExpected.length > 0) {
36
36
  hasChanges = true;
37
- display.barLine(`${display.red('-')} Deleted (removed since install):`);
38
- for (const { key } of categories.deleted) {
37
+ display.barLine(`${display.red('-')} Missing (will be restored by upgrade):`);
38
+ for (const { key } of categories.missingExpected) {
39
+ display.barLine(` ${display.red(key)}`);
40
+ }
41
+ display.newline();
42
+ }
43
+
44
+ if (categories.missingUntracked.length > 0) {
45
+ hasChanges = true;
46
+ display.barLine(`${display.red('-')} Deleted (removed in current version):`);
47
+ for (const { key } of categories.missingUntracked) {
39
48
  display.barLine(` ${display.red(key)}`);
40
49
  }
41
50
  display.newline();
@@ -10,6 +10,7 @@ import {
10
10
  UNIVERSAL_SKILLS,
11
11
  TEMPLATE_SKILLS,
12
12
  } from '../data/agents.js';
13
+ import { hasClaudeMdMemoryGuidance, readClaudeMd } from '../core/drift-checks.js';
13
14
  import * as display from '../utils/display.js';
14
15
 
15
16
  // Check categories
@@ -138,14 +139,6 @@ async function checkClaudeMd(projectRoot) {
138
139
  // Returns CLAUDE.md content or null when missing/unreadable. Missing-file
139
140
  // reporting is owned by checkClaudeMd — callers that use this helper should
140
141
  // skip reporting (return []) to avoid duplicate complaints.
141
- async function readClaudeMd(projectRoot) {
142
- try {
143
- return await readFile(path.join(projectRoot, 'CLAUDE.md'));
144
- } catch {
145
- return null;
146
- }
147
- }
148
-
149
142
  async function checkClaudeMdSize(projectRoot) {
150
143
  const content = await readClaudeMd(projectRoot);
151
144
  if (content === null) return [];
@@ -201,23 +194,14 @@ async function checkClaudeMdLineCount(projectRoot) {
201
194
  async function checkClaudeMdMemoryGuidance(projectRoot) {
202
195
  const content = await readClaudeMd(projectRoot);
203
196
  if (content === null) return [];
204
- const indicators = [
205
- 'memory architecture',
206
- 'native memory',
207
- '.claude/learnings',
208
- '[LEARN]',
209
- '/learn',
210
- ];
211
- const lower = content.toLowerCase();
212
- const hasGuidance = indicators.some((i) => lower.includes(i.toLowerCase()));
213
- if (hasGuidance) {
197
+ if (hasClaudeMdMemoryGuidance(content)) {
214
198
  return [result(PASS, 'CLAUDE.md memory guidance', null)];
215
199
  }
216
200
  return [
217
201
  result(
218
202
  WARN,
219
203
  'CLAUDE.md memory guidance',
220
- 'CLAUDE.md has no memory architecture guidance. Auto-learnings may pollute this file. Run worclaude upgrade to add.'
204
+ 'CLAUDE.md lacks memory-architecture guidance. Run worclaude upgrade to write a CLAUDE.md.workflow-ref.md sidecar with suggested additions.'
221
205
  ),
222
206
  ];
223
207
  }
@@ -34,154 +34,10 @@ import {
34
34
  SPEC_MD_TEMPLATE_MAP,
35
35
  } from '../data/agents.js';
36
36
  import { buildAgentRoutingSkill } from '../generators/agent-routing.js';
37
+ import { buildCommandsBlock } from '../core/variables.js';
37
38
 
38
39
  // --- Helper functions ---
39
40
 
40
- const LANGUAGE_COMMANDS = {
41
- python: {
42
- heading: 'Python',
43
- commands: [
44
- 'python -m pytest # Run tests',
45
- 'ruff check . # Lint',
46
- 'ruff format . # Format',
47
- ],
48
- },
49
- node: {
50
- heading: 'Node.js / TypeScript',
51
- commands: [
52
- 'npm test # Run tests',
53
- 'npx eslint . # Lint',
54
- 'npx prettier --write . # Format',
55
- ],
56
- },
57
- java: {
58
- heading: 'Java',
59
- commands: [
60
- 'mvn test # Run tests',
61
- 'mvn checkstyle:check # Lint',
62
- 'mvn spotless:apply # Format',
63
- ],
64
- },
65
- csharp: {
66
- heading: 'C# / .NET',
67
- commands: [
68
- 'dotnet test # Run tests',
69
- 'dotnet format --verify-no-changes # Lint',
70
- 'dotnet format # Format',
71
- ],
72
- },
73
- cpp: {
74
- heading: 'C / C++',
75
- commands: [
76
- 'cmake --build build && ctest # Build & test',
77
- 'clang-tidy src/*.cpp # Lint',
78
- 'clang-format -i src/*.[ch]pp # Format',
79
- ],
80
- },
81
- go: {
82
- heading: 'Go',
83
- commands: [
84
- 'go test ./... # Run tests',
85
- 'golangci-lint run # Lint',
86
- 'gofmt -w . # Format',
87
- ],
88
- },
89
- php: {
90
- heading: 'PHP',
91
- commands: [
92
- 'vendor/bin/phpunit # Run tests',
93
- 'vendor/bin/phpstan analyse # Lint',
94
- 'vendor/bin/php-cs-fixer fix . # Format',
95
- ],
96
- },
97
- ruby: {
98
- heading: 'Ruby',
99
- commands: [
100
- 'bundle exec rspec # Run tests',
101
- 'rubocop # Lint',
102
- 'rubocop -A # Format',
103
- ],
104
- },
105
- kotlin: {
106
- heading: 'Kotlin',
107
- commands: [
108
- 'gradle test # Run tests',
109
- 'detekt # Lint',
110
- 'ktlint -F # Format',
111
- ],
112
- },
113
- swift: {
114
- heading: 'Swift',
115
- commands: [
116
- 'swift test # Run tests',
117
- 'swiftlint # Lint',
118
- 'swift-format format -r . -i # Format',
119
- ],
120
- },
121
- rust: {
122
- heading: 'Rust',
123
- commands: [
124
- 'cargo test # Run tests',
125
- 'cargo clippy # Lint',
126
- 'cargo fmt # Format',
127
- ],
128
- },
129
- dart: {
130
- heading: 'Dart / Flutter',
131
- commands: [
132
- 'dart test # Run tests',
133
- 'dart analyze # Lint',
134
- 'dart format . # Format',
135
- ],
136
- },
137
- scala: {
138
- heading: 'Scala',
139
- commands: [
140
- 'sbt test # Run tests',
141
- 'sbt scalafix # Lint',
142
- 'scalafmt # Format',
143
- ],
144
- },
145
- elixir: {
146
- heading: 'Elixir',
147
- commands: [
148
- 'mix test # Run tests',
149
- 'mix credo # Lint',
150
- 'mix format # Format',
151
- ],
152
- },
153
- zig: {
154
- heading: 'Zig',
155
- commands: [
156
- 'zig build test # Run tests',
157
- 'zig build # Build (lint via compiler)',
158
- 'zig fmt . # Format',
159
- ],
160
- },
161
- };
162
-
163
- function buildCommandsBlock(languages, useDocker) {
164
- const lines = ['```bash'];
165
- for (const lang of languages) {
166
- const entry = LANGUAGE_COMMANDS[lang];
167
- if (!entry) continue;
168
- if (lines.length > 1) lines.push('');
169
- lines.push(`# ${entry.heading}`);
170
- lines.push(...entry.commands);
171
- }
172
- if (useDocker) {
173
- if (lines.length > 1) lines.push('');
174
- lines.push('# Docker');
175
- lines.push('docker compose up -d # Start services');
176
- lines.push('docker compose down # Stop services');
177
- }
178
- if (lines.length === 1) {
179
- lines.push('# Add your project-specific commands here');
180
- }
181
- lines.push('```');
182
- return lines.join('\n');
183
- }
184
-
185
41
  // --- Step runner functions ---
186
42
 
187
43
  async function runProjectInfo(selections) {