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 +38 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/commands/diff.js +12 -3
- package/src/commands/doctor.js +3 -19
- package/src/commands/init.js +1 -145
- package/src/commands/upgrade.js +356 -104
- package/src/core/config.js +8 -0
- package/src/core/drift-checks.js +63 -0
- package/src/core/file-categorizer.js +105 -37
- package/src/core/remover.js +1 -0
- package/src/core/scaffolder.js +1 -0
- package/src/core/variables.js +196 -0
- package/src/index.js +4 -1
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
|
|
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
|
|
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
package/src/commands/diff.js
CHANGED
|
@@ -32,10 +32,19 @@ export async function diffCommand() {
|
|
|
32
32
|
display.newline();
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
if (categories.
|
|
35
|
+
if (categories.missingExpected.length > 0) {
|
|
36
36
|
hasChanges = true;
|
|
37
|
-
display.barLine(`${display.red('-')}
|
|
38
|
-
for (const { key } of categories.
|
|
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();
|
package/src/commands/doctor.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
}
|
package/src/commands/init.js
CHANGED
|
@@ -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) {
|