warp-os 1.1.0 → 1.1.2

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
@@ -6,6 +6,27 @@ Format: [Semantic Versioning](https://semver.org/). Sections: Added, Changed, Re
6
6
 
7
7
  ---
8
8
 
9
+ ## [1.1.2] - 2026-04-05
10
+
11
+ Session migration for existing users.
12
+
13
+ ### Added
14
+ - **Session migration.** `bin/migrate-sessions.js` imports old `.warp/sessions/*.md` files into claude-mem. Runs automatically during install/upgrade when old session files are detected. Originals archived to `.warp/sessions/migrated-to-claude-mem/`.
15
+
16
+ ---
17
+
18
+ ## [1.1.1] - 2026-04-05
19
+
20
+ npm installer and upgrade improvements.
21
+
22
+ ### Changed
23
+ - **npm-based install.** `npx warp-os install` replaces symlink-based install.sh. Zero symlinks, works on Windows without Developer Mode.
24
+ - **Upgrade rewrite.** `/warp-upgrade` now runs `npx warp-os@latest install`, patches per-project hooks, checks for stale artifacts from previous versions.
25
+ - **Release skill.** `/warp-release-update` detects package.json/pyproject.toml/Cargo.toml and offers to publish to npm/PyPI/crates.io during deploy phase.
26
+ - **Bootstrap scripts.** get-warp.sh and get-warp.ps1 simplified to check Node.js and run `npx warp-os install`.
27
+
28
+ ---
29
+
9
30
  ## [1.1.0] - 2026-04-05
10
31
 
11
32
  Persistent cross-session memory via [claude-mem](https://github.com/thedotmack/claude-mem). Automatic observation capture replaces manual session handoffs.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.1.2
@@ -690,7 +690,38 @@ PRE-DEPLOY:
690
690
  ☐ Rollback plan documented (see deploy strategy above)
691
691
  ```
692
692
 
693
- ### 6C. Deploy Execution
693
+ ### 6C. Package Registry Publish
694
+
695
+ Detect if this project publishes to a package registry:
696
+
697
+ ```bash
698
+ # npm / Node.js
699
+ [ -f "package.json" ] && grep -q '"name"' package.json && echo "npm: $(node -e "console.log(require('./package.json').name)")" || true
700
+ # PyPI / Python
701
+ [ -f "pyproject.toml" ] && grep -q 'name' pyproject.toml && echo "pypi: detected" || true
702
+ # Cargo / Rust
703
+ [ -f "Cargo.toml" ] && grep -q 'name' Cargo.toml && echo "crates.io: detected" || true
704
+ ```
705
+
706
+ If a publishable package is detected:
707
+ 1. Verify the version in the package file matches the version being released
708
+ 2. Confirm with the user: "Publish [name]@[version] to [registry]? [Y/n]"
709
+ 3. Publish:
710
+
711
+ ```bash
712
+ # npm
713
+ npm publish --access public
714
+
715
+ # PyPI
716
+ python -m build && twine upload dist/*
717
+
718
+ # Cargo
719
+ cargo publish
720
+ ```
721
+
722
+ If publish fails with auth error, guide the user through login/token setup for that registry.
723
+
724
+ ### 6D. Deploy Execution
694
725
 
695
726
  ```bash
696
727
  # Merge the PR (adapt to project workflow)
@@ -712,7 +743,7 @@ DEPLOY STATUS:
712
743
  Environment: [staging | production]
713
744
  ```
714
745
 
715
- ### 6D. Canary Check
746
+ ### 6E. Canary Check
716
747
 
717
748
  Immediately after deploy, verify the deployment is healthy:
718
749
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: warp-upgrade
3
3
  description: >-
4
- One-command Warp upgrade from inside Claude Code. Pulls latest, rebuilds, reinstalls, shows changelog, detects migration requirements, and offers to re-run /warp-setup on the current project. No terminal switching needed.
4
+ One-command Warp upgrade from inside Claude Code. Fetches latest from npm, reinstalls, patches project hooks, shows changelog. No terminal switching needed.
5
5
  ---
6
6
 
7
7
  <!-- ═══════════════════════════════════════════════════════════ -->
@@ -188,112 +188,113 @@ Status values: **DONE**, **DONE_WITH_CONCERNS** (list concerns), **BLOCKED** (st
188
188
 
189
189
  # Upgrade
190
190
 
191
- Meta skill. Upgrades WarpOS from inside Claude Code — no terminal switching.
192
-
193
- **The upgrade is ONE COMMAND.** Do not decompose into manual steps. The upgrade
194
- script handles pull, build, install, auto-patch, changelog, and migration detection.
191
+ Meta skill. Upgrades Warp from inside Claude Code — no terminal switching.
195
192
 
196
193
  ---
197
194
 
198
- ## STEP 1: Locate the WarpOS Repo
195
+ ## STEP 1: Run the Upgrade
196
+
197
+ **One command. Do not decompose into manual steps.**
199
198
 
200
199
  ```bash
201
- WARP_REPO=""
202
- for candidate in \
203
- "$(cat "$HOME/.warp/repo-path" 2>/dev/null)" \
204
- "$(readlink -f ~/.claude/skills/warp-setup 2>/dev/null)/../../../.." \
205
- "$(dirname "$(readlink -f ~/.warp/hooks/identity-briefing.sh 2>/dev/null)")/../.." \
206
- "$HOME/Projects/warp" \
207
- "$HOME/warp" \
208
- ; do
209
- [ -z "$candidate" ] && continue
210
- if [ -d "$candidate/.git" ] && [ -f "$candidate/VERSION" ] && [ -f "$candidate/build.sh" ]; then
211
- WARP_REPO="$(cd "$candidate" && pwd)"
212
- break
213
- fi
214
- done
215
- echo "Warp repo: ${WARP_REPO:-NOT FOUND}"
200
+ npx warp-os@latest install
216
201
  ```
217
202
 
218
- If not found, ask the user for the path.
203
+ **Timeout:** On Windows, npm fetch + install can take 2-4 minutes. Use a Bash timeout of at least 300000ms (5 minutes).
204
+
205
+ **If it succeeds:** Read the output, note the version, proceed to Step 2.
206
+
207
+ **If it fails:**
208
+ - Network error → "Check your connection and try again"
209
+ - Permission error → "Try running from a regular terminal: npx warp-os@latest install"
210
+ - Node.js missing → "Install Node.js 18+ from https://nodejs.org/"
219
211
 
220
212
  ---
221
213
 
222
- ## STEP 2: Run the Upgrade Script
214
+ ## STEP 2: Patch Project Hooks
223
215
 
224
- **Run `bin/warp-upgrade.sh` as a single command. Do NOT decompose into manual steps.**
216
+ The npm installer updates global files (~/.claude/skills/, ~/.claude/agents/, ~/.warp/hooks/). But per-project config needs patching too.
225
217
 
226
- The script handles everything: fetch, version check, pull, build, install, auto-patch
227
- project hooks, changelog display, migration detection, and restart recommendation.
218
+ Check if the current project's hook config is current:
228
219
 
229
220
  ```bash
230
- cd "$WARP_REPO" && bash bin/warp-upgrade.sh
221
+ # Check for stale hooks (old hook names that no longer exist)
222
+ grep -c 'lifecycle-session-start\|warp-save\|session-end' .claude/settings.local.json 2>/dev/null && echo "STALE — needs patching" || echo "OK"
231
223
  ```
232
224
 
233
- **IMPORTANT — Timeout:** On Windows (Git Bash), build + install can take 2-4 minutes.
234
- Use a Bash timeout of at least 300000ms (5 minutes). If the default timeout is shorter,
235
- set it explicitly. A timed-out upgrade leaves a half-installed state.
225
+ If stale, patch it using the canonical template:
236
226
 
237
- **If the script succeeds:** Read its output, summarize what changed, and remind the user
238
- to restart Claude Code.
227
+ ```bash
228
+ node -e "
229
+ const fs = require('fs');
230
+ const home = require('os').homedir();
231
+ const settings = JSON.parse(fs.readFileSync('.claude/settings.local.json', 'utf8'));
232
+ const template = JSON.parse(fs.readFileSync(home + '/.warp/project-hooks.json', 'utf8'));
233
+ settings.agent = template.agent;
234
+ settings.hooks = template.hooks;
235
+ fs.writeFileSync('.claude/settings.local.json', JSON.stringify(settings, null, 2) + '\n');
236
+ console.log('Patched.');
237
+ "
238
+ ```
239
239
 
240
- **If the script fails:** Read the error output. Common failures:
241
- - Network error on git pull → "Check your connection and try again"
242
- - Build error → "build.sh failed — check the error above"
243
- - Install error (Windows file locks) → "Close other Claude Code instances and retry"
244
- - Git conflicts → "Your local Warp repo has changes. Run `git stash` first."
240
+ This preserves the project's `permissions` and `enabledMcpjsonServers` while updating `agent` and `hooks` from the template.
245
241
 
246
- Only if the script itself is missing or broken should you fall back to manual steps.
242
+ If `.claude/settings.local.json` doesn't exist tell user to run `/warp-setup`.
247
243
 
248
244
  ---
249
245
 
250
- ## STEP 3: Verify Auto-Patch (if script completed)
251
-
252
- The upgrade script auto-patches `.claude/settings.local.json` in the current project
253
- directory with the latest hook config from `~/.warp/project-hooks.json`.
246
+ ## STEP 3: Verify claude-mem
254
247
 
255
- Verify the patch applied:
248
+ Check if claude-mem is installed (required since v1.1.0):
256
249
 
257
250
  ```bash
258
- # Check that settings.local.json references new hook names
259
- grep -c 'identity-foundation\|identity-briefing\|consistency-check' .claude/settings.local.json 2>/dev/null && echo "hooks patched" || echo "hooks NOT patched"
251
+ npx claude-mem --version 2>/dev/null && echo "claude-mem OK" || echo "claude-mem MISSING"
260
252
  ```
261
253
 
262
- If NOT patched (script ran from a different directory, or no settings.local.json):
263
- - If `settings.local.json` exists but has old hook names → patch it manually using
264
- `~/.warp/project-hooks.json` as the source. Preserve `permissions` and `enabledMcpjsonServers`.
265
- - If no `settings.local.json` → tell user to run `/warp-setup` (first-time setup, not upgrade).
254
+ If missing, install it:
255
+ ```bash
256
+ npx claude-mem install
257
+ ```
266
258
 
267
259
  ---
268
260
 
269
- ## FALLBACK: Manual Steps (only if warp-upgrade.sh is missing/broken)
261
+ ## STEP 4: Show Changelog
270
262
 
271
- If `bin/warp-upgrade.sh` does not exist or crashes on invocation, fall back to manual:
263
+ ```bash
264
+ # Show what changed in the new version
265
+ cat CHANGELOG.md 2>/dev/null | head -40 || echo "(CHANGELOG not found locally)"
266
+ ```
272
267
 
268
+ If CHANGELOG is not in the current directory, check the npm package:
273
269
  ```bash
274
- cd "$WARP_REPO"
275
- git fetch origin --quiet
276
- git pull --rebase origin master
277
- bash build.sh
278
- bash install.sh
279
- cat CHANGELOG.md | head -60
270
+ cat "$(npm root -g)/warp-os/CHANGELOG.md" 2>/dev/null | head -40 || echo "(not found)"
280
271
  ```
281
272
 
282
- Then manually patch project hooks:
273
+ ---
274
+
275
+ ## STEP 5: Migration Checks
276
+
277
+ After upgrading, check for stale artifacts from previous versions:
278
+
283
279
  ```bash
284
- # Read template and patch settings.local.json
285
- python3 -c "
286
- import json
287
- t = json.load(open('$HOME/.warp/project-hooks.json'))
288
- s = json.load(open('.claude/settings.local.json'))
289
- s['agent'] = t['agent']
290
- s['hooks'] = t['hooks']
291
- json.dump(s, open('.claude/settings.local.json','w'), indent=2)
292
- print('Patched.')
293
- "
280
+ # Stale session directories (replaced by claude-mem in v1.1.0)
281
+ [ -d ".warp/sessions" ] && echo "STALE: .warp/sessions/ exists (claude-mem handles sessions now)" || echo "OK"
282
+
283
+ # Stale hook scripts in ~/.warp/hooks/
284
+ for old in lifecycle-session-start.sh lifecycle-session-end.sh lifecycle-pre-compact.sh; do
285
+ [ -f "$HOME/.warp/hooks/$old" ] && echo "STALE: ~/.warp/hooks/$old"
286
+ done
287
+
288
+ # Stale skill symlinks (replaced by file copies in v1.1.0)
289
+ for skill in ~/.claude/skills/warp-*/; do
290
+ [ -L "$skill" ] && echo "STALE SYMLINK: $skill (should be a directory, not a symlink)"
291
+ done
294
292
  ```
295
293
 
296
- **This fallback exists for emergencies only.** The script is the primary path.
294
+ If stale items found, offer to clean them:
295
+ - Stale .warp/sessions/ → "These are old session handoffs. claude-mem now handles session memory. Safe to delete? [Y/n]"
296
+ - Stale hook scripts → delete automatically (installer should have cleaned these)
297
+ - Stale symlinks → re-run `npx warp-os install` to replace with file copies
297
298
 
298
299
  ---
299
300
 
@@ -303,13 +304,14 @@ print('Patched.')
303
304
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
304
305
  WARP │ UPGRADE
305
306
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
306
- Repo: {path}
307
- Upgrade: v{old} → v{new}
307
+ Upgraded: v{old} → v{new}
308
308
 
309
- {changelog excerpt — Added/Changed/Removed}
309
+ {changelog excerpt}
310
310
 
311
- Hooks: auto-patched ✓
312
- Restart: required (new hooks + skills)
311
+ Hooks: patched ✓
312
+ claude-mem: installed
313
+ Stale: {N items cleaned / none}
314
+ Restart: required
313
315
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
314
316
  ```
315
317
 
@@ -320,15 +322,15 @@ WARP │ UPGRADE
320
322
  ## MUST / MUST NOT
321
323
 
322
324
  **MUST:**
323
- - Run `bin/warp-upgrade.sh` as a single command (not decomposed steps)
324
- - Use a 5-minute timeout for the upgrade script on Windows
325
- - Verify hooks auto-patched after script completes
325
+ - Run `npx warp-os@latest install` as the primary upgrade command
326
+ - Patch per-project settings.local.json with latest hooks
327
+ - Check for and offer to clean stale artifacts
328
+ - Verify claude-mem is installed
326
329
  - Show changelog summary
327
330
  - Remind user to restart Claude Code
328
331
 
329
332
  **MUST NOT:**
330
- - Decompose the upgrade into individual git/build/install commands when the script works
331
- - Use default Bash timeout (2 minutes is too short on Windows)
332
- - Proceed to install if build fails
333
- - Require the user to re-run `/warp-setup` after a normal upgrade
334
- - Force-push, reset, or destructively modify the Warp repo without consent
333
+ - Use git clone/pull to upgrade (npm handles distribution now)
334
+ - Skip the per-project hook patch
335
+ - Delete .warp/sessions/ without asking (user may want the archives)
336
+ - Require the user to re-run `/warp-setup` after a normal upgrade (hook patching should suffice)
package/bin/install.js CHANGED
@@ -280,7 +280,35 @@ try {
280
280
  info('Install manually: npx claude-mem install');
281
281
  }
282
282
 
283
- // ── Step 6: Version Tracking ─────────────────────────────────────────────────
283
+ // ── Step 6: Migrate old session files to claude-mem ──────────────────────────
284
+
285
+ // Check if this is running inside a project with old .warp/sessions/ files
286
+ const projectSessionsDir = path.join(process.cwd(), '.warp', 'sessions');
287
+ if (fs.existsSync(projectSessionsDir)) {
288
+ const sessionFiles = fs.readdirSync(projectSessionsDir)
289
+ .filter(f => f.endsWith('.md') && f.startsWith('SESSION_'));
290
+
291
+ if (sessionFiles.length > 0) {
292
+ console.log('');
293
+ console.log(`Migrating ${sessionFiles.length} session file(s) to claude-mem...`);
294
+ const migrationScript = path.join(REPO_ROOT, 'bin', 'migrate-sessions.js');
295
+ if (fs.existsSync(migrationScript)) {
296
+ try {
297
+ execSync(`node "${migrationScript}" "${process.cwd()}"`, {
298
+ stdio: 'inherit',
299
+ timeout: 60000
300
+ });
301
+ } catch {
302
+ warn('Session migration failed — files left in place. Run manually: node bin/migrate-sessions.js');
303
+ }
304
+ } else {
305
+ info(`Found ${sessionFiles.length} old session files in .warp/sessions/`);
306
+ info('claude-mem will capture new sessions automatically. Old files preserved.');
307
+ }
308
+ }
309
+ }
310
+
311
+ // ── Step 7: Version Tracking ────────────────────────────────────────────────
284
312
 
285
313
  console.log('');
286
314
  console.log('Writing version...');
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env node
2
+ // migrate-sessions.js — Import old .warp/sessions/*.md into claude-mem
3
+ // Run once during upgrade. Reads markdown session handoffs, posts them
4
+ // to claude-mem's worker API as observations, then archives originals.
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const http = require('http');
9
+
10
+ const GREEN = '\x1b[32m';
11
+ const YELLOW = '\x1b[33m';
12
+ const CYAN = '\x1b[36m';
13
+ const NC = '\x1b[0m';
14
+
15
+ function ok(msg) { console.log(` ${GREEN}OK${NC} ${msg}`); }
16
+ function warn(msg) { console.log(` ${YELLOW}WARN${NC} ${msg}`); }
17
+ function info(msg) { console.log(` ${CYAN}INFO${NC} ${msg}`); }
18
+
19
+ // ── Find session files ───────────────────────────────────────────────────────
20
+
21
+ const cwd = process.argv[2] || process.cwd();
22
+ const sessionsDir = path.join(cwd, '.warp', 'sessions');
23
+ const archiveDir = path.join(sessionsDir, 'archive');
24
+
25
+ if (!fs.existsSync(sessionsDir)) {
26
+ console.log('No .warp/sessions/ directory found. Nothing to migrate.');
27
+ process.exit(0);
28
+ }
29
+
30
+ // Gather all session files (active + archived)
31
+ const sessionFiles = [];
32
+
33
+ for (const file of fs.readdirSync(sessionsDir)) {
34
+ if (file.endsWith('.md') && file.startsWith('SESSION_')) {
35
+ sessionFiles.push(path.join(sessionsDir, file));
36
+ }
37
+ }
38
+
39
+ if (fs.existsSync(archiveDir)) {
40
+ for (const file of fs.readdirSync(archiveDir)) {
41
+ if (file.endsWith('.md') && file.startsWith('SESSION_')) {
42
+ sessionFiles.push(path.join(archiveDir, file));
43
+ }
44
+ }
45
+ }
46
+
47
+ if (sessionFiles.length === 0) {
48
+ console.log('No session files found to migrate.');
49
+ process.exit(0);
50
+ }
51
+
52
+ console.log(`Found ${sessionFiles.length} session file(s) to migrate.`);
53
+
54
+ // ── Check if claude-mem worker is running ────────────────────────────────────
55
+
56
+ function httpPost(urlPath, data) {
57
+ return new Promise((resolve, reject) => {
58
+ const body = JSON.stringify(data);
59
+ const req = http.request({
60
+ hostname: '127.0.0.1',
61
+ port: 37777,
62
+ path: urlPath,
63
+ method: 'POST',
64
+ headers: {
65
+ 'Content-Type': 'application/json',
66
+ 'Content-Length': Buffer.byteLength(body)
67
+ },
68
+ timeout: 10000
69
+ }, (res) => {
70
+ let data = '';
71
+ res.on('data', chunk => data += chunk);
72
+ res.on('end', () => resolve({ status: res.statusCode, body: data }));
73
+ });
74
+ req.on('error', reject);
75
+ req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
76
+ req.write(body);
77
+ req.end();
78
+ });
79
+ }
80
+
81
+ function httpGet(urlPath) {
82
+ return new Promise((resolve, reject) => {
83
+ const req = http.request({
84
+ hostname: '127.0.0.1',
85
+ port: 37777,
86
+ path: urlPath,
87
+ method: 'GET',
88
+ timeout: 5000
89
+ }, (res) => {
90
+ let data = '';
91
+ res.on('data', chunk => data += chunk);
92
+ res.on('end', () => resolve({ status: res.statusCode, body: data }));
93
+ });
94
+ req.on('error', reject);
95
+ req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
96
+ req.end();
97
+ });
98
+ }
99
+
100
+ // ── Parse session file ───────────────────────────────────────────────────────
101
+
102
+ function parseSessionFile(filePath) {
103
+ const content = fs.readFileSync(filePath, 'utf8');
104
+ const filename = path.basename(filePath, '.md');
105
+
106
+ // Extract session metadata from filename: SESSION_CC7_20260404
107
+ const match = filename.match(/SESSION_CC(\d+)_(\d{8})/);
108
+ const sessionNum = match ? `CC${match[1]}` : filename;
109
+ const dateStr = match ? `${match[2].slice(0,4)}-${match[2].slice(4,6)}-${match[2].slice(6,8)}` : 'unknown';
110
+
111
+ // Extract sections
112
+ const sections = {};
113
+ let currentSection = 'header';
114
+ sections[currentSection] = [];
115
+
116
+ for (const line of content.split('\n')) {
117
+ if (line.startsWith('## ')) {
118
+ currentSection = line.replace('## ', '').trim();
119
+ sections[currentSection] = [];
120
+ } else {
121
+ if (!sections[currentSection]) sections[currentSection] = [];
122
+ sections[currentSection].push(line);
123
+ }
124
+ }
125
+
126
+ // Extract goal from header
127
+ const goalLine = content.match(/Goal:\s+(.+)/);
128
+ const goal = goalLine ? goalLine[1].trim() : `Session ${sessionNum}`;
129
+
130
+ return {
131
+ filename,
132
+ sessionNum,
133
+ dateStr,
134
+ goal,
135
+ content,
136
+ sections,
137
+ keyDecisions: (sections['Key Decisions'] || []).filter(l => l.trim().startsWith('-')).map(l => l.trim().replace(/^- /, '')),
138
+ itemsAchieved: (sections['Items Achieved'] || []).filter(l => l.trim().startsWith('-')).map(l => l.trim().replace(/^- /, '')),
139
+ itemsNotDone: (sections['Items Not Done'] || []).filter(l => l.trim().startsWith('-')).map(l => l.trim().replace(/^- /, '')),
140
+ nextPickup: (sections['Next Pickup Point'] || []).join('\n').trim(),
141
+ filesProduced: (sections['Files Produced'] || []).filter(l => l.trim().startsWith('-')).map(l => l.trim().replace(/^- /, '')),
142
+ filesAmended: (sections['Files Amended'] || []).filter(l => l.trim().startsWith('-')).map(l => l.trim().replace(/^- /, '')),
143
+ };
144
+ }
145
+
146
+ // ── Main ─────────────────────────────────────────────────────────────────────
147
+
148
+ async function main() {
149
+ // Check worker health
150
+ try {
151
+ const health = await httpGet('/health');
152
+ if (health.status !== 200) {
153
+ warn('claude-mem worker not healthy. Start it with: npx claude-mem start');
154
+ process.exit(1);
155
+ }
156
+ } catch {
157
+ warn('claude-mem worker not running. Start it with: npx claude-mem start');
158
+ info('Migration will run on next upgrade after worker is available.');
159
+ process.exit(0);
160
+ }
161
+
162
+ const projectName = path.basename(cwd);
163
+ let migrated = 0;
164
+ let failed = 0;
165
+
166
+ for (const file of sessionFiles) {
167
+ const session = parseSessionFile(file);
168
+
169
+ // Build a narrative for claude-mem from the session handoff
170
+ const narrative = [
171
+ `Session ${session.sessionNum} (${session.dateStr}): ${session.goal}`,
172
+ '',
173
+ session.keyDecisions.length > 0 ? `Key Decisions:\n${session.keyDecisions.map(d => ` - ${d}`).join('\n')}` : '',
174
+ session.itemsAchieved.length > 0 ? `Completed:\n${session.itemsAchieved.map(d => ` - ${d}`).join('\n')}` : '',
175
+ session.itemsNotDone.length > 0 ? `Not Done:\n${session.itemsNotDone.map(d => ` - ${d}`).join('\n')}` : '',
176
+ session.nextPickup ? `Next Pickup: ${session.nextPickup}` : '',
177
+ session.filesProduced.length > 0 ? `Files Produced:\n${session.filesProduced.map(d => ` - ${d}`).join('\n')}` : '',
178
+ session.filesAmended.length > 0 ? `Files Amended:\n${session.filesAmended.map(d => ` - ${d}`).join('\n')}` : '',
179
+ ].filter(Boolean).join('\n\n');
180
+
181
+ try {
182
+ // Post as an observation to claude-mem
183
+ const result = await httpPost('/api/sessions/observations', {
184
+ contentSessionId: `warp-migration-${session.sessionNum}`,
185
+ project: projectName,
186
+ tool_name: 'warp-session-migration',
187
+ tool_input: {
188
+ session: session.sessionNum,
189
+ date: session.dateStr,
190
+ goal: session.goal
191
+ },
192
+ tool_output: {
193
+ narrative: narrative,
194
+ keyDecisions: session.keyDecisions,
195
+ itemsAchieved: session.itemsAchieved,
196
+ filesAmended: session.filesAmended,
197
+ nextPickup: session.nextPickup
198
+ }
199
+ });
200
+
201
+ if (result.status >= 200 && result.status < 300) {
202
+ ok(`${session.filename} → claude-mem (${session.keyDecisions.length} decisions, ${session.itemsAchieved.length} items)`);
203
+ migrated++;
204
+ } else {
205
+ // If the observation API doesn't accept this format, try the raw session init
206
+ const initResult = await httpPost('/api/sessions/init', {
207
+ contentSessionId: `warp-migration-${session.sessionNum}`,
208
+ project: projectName,
209
+ userPrompt: `[Migrated from ${session.filename}] ${session.goal}\n\n${narrative}`
210
+ });
211
+
212
+ if (initResult.status >= 200 && initResult.status < 300) {
213
+ ok(`${session.filename} → claude-mem (via session init)`);
214
+ migrated++;
215
+ } else {
216
+ warn(`${session.filename} — API returned ${result.status}`);
217
+ failed++;
218
+ }
219
+ }
220
+ } catch (err) {
221
+ warn(`${session.filename} — ${err.message}`);
222
+ failed++;
223
+ }
224
+ }
225
+
226
+ // Archive migrated files
227
+ if (migrated > 0) {
228
+ const migratedDir = path.join(sessionsDir, 'migrated-to-claude-mem');
229
+ fs.mkdirSync(migratedDir, { recursive: true });
230
+
231
+ for (const file of sessionFiles) {
232
+ const basename = path.basename(file);
233
+ const dest = path.join(migratedDir, basename);
234
+ try {
235
+ fs.copyFileSync(file, dest);
236
+ fs.unlinkSync(file);
237
+ } catch {
238
+ // File might already be in archive subdir, just leave it
239
+ }
240
+ }
241
+ ok(`Archived ${migrated} session file(s) → .warp/sessions/migrated-to-claude-mem/`);
242
+ }
243
+
244
+ console.log('');
245
+ console.log(`Migration: ${GREEN}${migrated}${NC} imported, ${YELLOW}${failed}${NC} failed`);
246
+ if (failed > 0) {
247
+ info('Failed files left in place. Re-run migration after fixing claude-mem worker.');
248
+ }
249
+ }
250
+
251
+ main().catch(err => {
252
+ warn(`Migration error: ${err.message}`);
253
+ process.exit(1);
254
+ });
@@ -712,7 +712,38 @@ PRE-DEPLOY:
712
712
  ☐ Rollback plan documented (see deploy strategy above)
713
713
  ```
714
714
 
715
- ### 6C. Deploy Execution
715
+ ### 6C. Package Registry Publish
716
+
717
+ Detect if this project publishes to a package registry:
718
+
719
+ ```bash
720
+ # npm / Node.js
721
+ [ -f "package.json" ] && grep -q '"name"' package.json && echo "npm: $(node -e "console.log(require('./package.json').name)")" || true
722
+ # PyPI / Python
723
+ [ -f "pyproject.toml" ] && grep -q 'name' pyproject.toml && echo "pypi: detected" || true
724
+ # Cargo / Rust
725
+ [ -f "Cargo.toml" ] && grep -q 'name' Cargo.toml && echo "crates.io: detected" || true
726
+ ```
727
+
728
+ If a publishable package is detected:
729
+ 1. Verify the version in the package file matches the version being released
730
+ 2. Confirm with the user: "Publish [name]@[version] to [registry]? [Y/n]"
731
+ 3. Publish:
732
+
733
+ ```bash
734
+ # npm
735
+ npm publish --access public
736
+
737
+ # PyPI
738
+ python -m build && twine upload dist/*
739
+
740
+ # Cargo
741
+ cargo publish
742
+ ```
743
+
744
+ If publish fails with auth error, guide the user through login/token setup for that registry.
745
+
746
+ ### 6D. Deploy Execution
716
747
 
717
748
  ```bash
718
749
  # Merge the PR (adapt to project workflow)
@@ -734,7 +765,7 @@ DEPLOY STATUS:
734
765
  Environment: [staging | production]
735
766
  ```
736
767
 
737
- ### 6D. Canary Check
768
+ ### 6E. Canary Check
738
769
 
739
770
  Immediately after deploy, verify the deployment is healthy:
740
771
 
@@ -1,10 +1,8 @@
1
1
  ---
2
2
  name: warp-upgrade
3
3
  description: >
4
- One-command Warp upgrade from inside Claude Code. Pulls latest,
5
- rebuilds, reinstalls, shows changelog, detects migration requirements,
6
- and offers to re-run /warp-setup on the current project. No terminal
7
- switching needed.
4
+ One-command Warp upgrade from inside Claude Code. Fetches latest from npm,
5
+ reinstalls, patches project hooks, shows changelog. No terminal switching needed.
8
6
  triggers:
9
7
  - /warp-upgrade
10
8
  - /upgrade
@@ -199,112 +197,113 @@ Status values: **DONE**, **DONE_WITH_CONCERNS** (list concerns), **BLOCKED** (st
199
197
 
200
198
  # Upgrade
201
199
 
202
- Meta skill. Upgrades WarpOS from inside Claude Code — no terminal switching.
203
-
204
- **The upgrade is ONE COMMAND.** Do not decompose into manual steps. The upgrade
205
- script handles pull, build, install, auto-patch, changelog, and migration detection.
200
+ Meta skill. Upgrades Warp from inside Claude Code — no terminal switching.
206
201
 
207
202
  ---
208
203
 
209
- ## STEP 1: Locate the WarpOS Repo
204
+ ## STEP 1: Run the Upgrade
205
+
206
+ **One command. Do not decompose into manual steps.**
210
207
 
211
208
  ```bash
212
- WARP_REPO=""
213
- for candidate in \
214
- "$(cat "$HOME/.warp/repo-path" 2>/dev/null)" \
215
- "$(readlink -f ~/.claude/skills/warp-setup 2>/dev/null)/../../../.." \
216
- "$(dirname "$(readlink -f ~/.warp/hooks/identity-briefing.sh 2>/dev/null)")/../.." \
217
- "$HOME/Projects/warp" \
218
- "$HOME/warp" \
219
- ; do
220
- [ -z "$candidate" ] && continue
221
- if [ -d "$candidate/.git" ] && [ -f "$candidate/VERSION" ] && [ -f "$candidate/build.sh" ]; then
222
- WARP_REPO="$(cd "$candidate" && pwd)"
223
- break
224
- fi
225
- done
226
- echo "Warp repo: ${WARP_REPO:-NOT FOUND}"
209
+ npx warp-os@latest install
227
210
  ```
228
211
 
229
- If not found, ask the user for the path.
212
+ **Timeout:** On Windows, npm fetch + install can take 2-4 minutes. Use a Bash timeout of at least 300000ms (5 minutes).
213
+
214
+ **If it succeeds:** Read the output, note the version, proceed to Step 2.
215
+
216
+ **If it fails:**
217
+ - Network error → "Check your connection and try again"
218
+ - Permission error → "Try running from a regular terminal: npx warp-os@latest install"
219
+ - Node.js missing → "Install Node.js 18+ from https://nodejs.org/"
230
220
 
231
221
  ---
232
222
 
233
- ## STEP 2: Run the Upgrade Script
223
+ ## STEP 2: Patch Project Hooks
234
224
 
235
- **Run `bin/warp-upgrade.sh` as a single command. Do NOT decompose into manual steps.**
225
+ The npm installer updates global files (~/.claude/skills/, ~/.claude/agents/, ~/.warp/hooks/). But per-project config needs patching too.
236
226
 
237
- The script handles everything: fetch, version check, pull, build, install, auto-patch
238
- project hooks, changelog display, migration detection, and restart recommendation.
227
+ Check if the current project's hook config is current:
239
228
 
240
229
  ```bash
241
- cd "$WARP_REPO" && bash bin/warp-upgrade.sh
230
+ # Check for stale hooks (old hook names that no longer exist)
231
+ grep -c 'lifecycle-session-start\|warp-save\|session-end' .claude/settings.local.json 2>/dev/null && echo "STALE — needs patching" || echo "OK"
242
232
  ```
243
233
 
244
- **IMPORTANT — Timeout:** On Windows (Git Bash), build + install can take 2-4 minutes.
245
- Use a Bash timeout of at least 300000ms (5 minutes). If the default timeout is shorter,
246
- set it explicitly. A timed-out upgrade leaves a half-installed state.
234
+ If stale, patch it using the canonical template:
247
235
 
248
- **If the script succeeds:** Read its output, summarize what changed, and remind the user
249
- to restart Claude Code.
236
+ ```bash
237
+ node -e "
238
+ const fs = require('fs');
239
+ const home = require('os').homedir();
240
+ const settings = JSON.parse(fs.readFileSync('.claude/settings.local.json', 'utf8'));
241
+ const template = JSON.parse(fs.readFileSync(home + '/.warp/project-hooks.json', 'utf8'));
242
+ settings.agent = template.agent;
243
+ settings.hooks = template.hooks;
244
+ fs.writeFileSync('.claude/settings.local.json', JSON.stringify(settings, null, 2) + '\n');
245
+ console.log('Patched.');
246
+ "
247
+ ```
250
248
 
251
- **If the script fails:** Read the error output. Common failures:
252
- - Network error on git pull → "Check your connection and try again"
253
- - Build error → "build.sh failed — check the error above"
254
- - Install error (Windows file locks) → "Close other Claude Code instances and retry"
255
- - Git conflicts → "Your local Warp repo has changes. Run `git stash` first."
249
+ This preserves the project's `permissions` and `enabledMcpjsonServers` while updating `agent` and `hooks` from the template.
256
250
 
257
- Only if the script itself is missing or broken should you fall back to manual steps.
251
+ If `.claude/settings.local.json` doesn't exist tell user to run `/warp-setup`.
258
252
 
259
253
  ---
260
254
 
261
- ## STEP 3: Verify Auto-Patch (if script completed)
262
-
263
- The upgrade script auto-patches `.claude/settings.local.json` in the current project
264
- directory with the latest hook config from `~/.warp/project-hooks.json`.
255
+ ## STEP 3: Verify claude-mem
265
256
 
266
- Verify the patch applied:
257
+ Check if claude-mem is installed (required since v1.1.0):
267
258
 
268
259
  ```bash
269
- # Check that settings.local.json references new hook names
270
- grep -c 'identity-foundation\|identity-briefing\|consistency-check' .claude/settings.local.json 2>/dev/null && echo "hooks patched" || echo "hooks NOT patched"
260
+ npx claude-mem --version 2>/dev/null && echo "claude-mem OK" || echo "claude-mem MISSING"
271
261
  ```
272
262
 
273
- If NOT patched (script ran from a different directory, or no settings.local.json):
274
- - If `settings.local.json` exists but has old hook names → patch it manually using
275
- `~/.warp/project-hooks.json` as the source. Preserve `permissions` and `enabledMcpjsonServers`.
276
- - If no `settings.local.json` → tell user to run `/warp-setup` (first-time setup, not upgrade).
263
+ If missing, install it:
264
+ ```bash
265
+ npx claude-mem install
266
+ ```
277
267
 
278
268
  ---
279
269
 
280
- ## FALLBACK: Manual Steps (only if warp-upgrade.sh is missing/broken)
270
+ ## STEP 4: Show Changelog
281
271
 
282
- If `bin/warp-upgrade.sh` does not exist or crashes on invocation, fall back to manual:
272
+ ```bash
273
+ # Show what changed in the new version
274
+ cat CHANGELOG.md 2>/dev/null | head -40 || echo "(CHANGELOG not found locally)"
275
+ ```
283
276
 
277
+ If CHANGELOG is not in the current directory, check the npm package:
284
278
  ```bash
285
- cd "$WARP_REPO"
286
- git fetch origin --quiet
287
- git pull --rebase origin master
288
- bash build.sh
289
- bash install.sh
290
- cat CHANGELOG.md | head -60
279
+ cat "$(npm root -g)/warp-os/CHANGELOG.md" 2>/dev/null | head -40 || echo "(not found)"
291
280
  ```
292
281
 
293
- Then manually patch project hooks:
282
+ ---
283
+
284
+ ## STEP 5: Migration Checks
285
+
286
+ After upgrading, check for stale artifacts from previous versions:
287
+
294
288
  ```bash
295
- # Read template and patch settings.local.json
296
- python3 -c "
297
- import json
298
- t = json.load(open('$HOME/.warp/project-hooks.json'))
299
- s = json.load(open('.claude/settings.local.json'))
300
- s['agent'] = t['agent']
301
- s['hooks'] = t['hooks']
302
- json.dump(s, open('.claude/settings.local.json','w'), indent=2)
303
- print('Patched.')
304
- "
289
+ # Stale session directories (replaced by claude-mem in v1.1.0)
290
+ [ -d ".warp/sessions" ] && echo "STALE: .warp/sessions/ exists (claude-mem handles sessions now)" || echo "OK"
291
+
292
+ # Stale hook scripts in ~/.warp/hooks/
293
+ for old in lifecycle-session-start.sh lifecycle-session-end.sh lifecycle-pre-compact.sh; do
294
+ [ -f "$HOME/.warp/hooks/$old" ] && echo "STALE: ~/.warp/hooks/$old"
295
+ done
296
+
297
+ # Stale skill symlinks (replaced by file copies in v1.1.0)
298
+ for skill in ~/.claude/skills/warp-*/; do
299
+ [ -L "$skill" ] && echo "STALE SYMLINK: $skill (should be a directory, not a symlink)"
300
+ done
305
301
  ```
306
302
 
307
- **This fallback exists for emergencies only.** The script is the primary path.
303
+ If stale items found, offer to clean them:
304
+ - Stale .warp/sessions/ → "These are old session handoffs. claude-mem now handles session memory. Safe to delete? [Y/n]"
305
+ - Stale hook scripts → delete automatically (installer should have cleaned these)
306
+ - Stale symlinks → re-run `npx warp-os install` to replace with file copies
308
307
 
309
308
  ---
310
309
 
@@ -314,13 +313,14 @@ print('Patched.')
314
313
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
315
314
  WARP │ UPGRADE
316
315
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
317
- Repo: {path}
318
- Upgrade: v{old} → v{new}
316
+ Upgraded: v{old} → v{new}
319
317
 
320
- {changelog excerpt — Added/Changed/Removed}
318
+ {changelog excerpt}
321
319
 
322
- Hooks: auto-patched ✓
323
- Restart: required (new hooks + skills)
320
+ Hooks: patched ✓
321
+ claude-mem: installed
322
+ Stale: {N items cleaned / none}
323
+ Restart: required
324
324
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
325
325
  ```
326
326
 
@@ -331,15 +331,15 @@ WARP │ UPGRADE
331
331
  ## MUST / MUST NOT
332
332
 
333
333
  **MUST:**
334
- - Run `bin/warp-upgrade.sh` as a single command (not decomposed steps)
335
- - Use a 5-minute timeout for the upgrade script on Windows
336
- - Verify hooks auto-patched after script completes
334
+ - Run `npx warp-os@latest install` as the primary upgrade command
335
+ - Patch per-project settings.local.json with latest hooks
336
+ - Check for and offer to clean stale artifacts
337
+ - Verify claude-mem is installed
337
338
  - Show changelog summary
338
339
  - Remind user to restart Claude Code
339
340
 
340
341
  **MUST NOT:**
341
- - Decompose the upgrade into individual git/build/install commands when the script works
342
- - Use default Bash timeout (2 minutes is too short on Windows)
343
- - Proceed to install if build fails
344
- - Require the user to re-run `/warp-setup` after a normal upgrade
345
- - Force-push, reset, or destructively modify the Warp repo without consent
342
+ - Use git clone/pull to upgrade (npm handles distribution now)
343
+ - Skip the per-project hook patch
344
+ - Delete .warp/sessions/ without asking (user may want the archives)
345
+ - Require the user to re-run `/warp-setup` after a normal upgrade (hook patching should suffice)
package/package.json CHANGED
@@ -1,21 +1,22 @@
1
1
  {
2
2
  "name": "warp-os",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "A development operating system for Claude Code. 16 skills compiled into a pipeline that thinks through every step of building a product.",
5
5
  "author": "WolfOnWings",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/WolfOnWings/warp"
9
+ "url": "git+https://github.com/WolfOnWings/warp.git"
10
10
  },
11
11
  "bin": {
12
- "warp-os": "./bin/cli.js"
12
+ "warp-os": "bin/cli.js"
13
13
  },
14
14
  "files": [
15
15
  "dist/",
16
16
  "agents/",
17
17
  "bin/cli.js",
18
18
  "bin/install.js",
19
+ "bin/migrate-sessions.js",
19
20
  "bin/hooks/",
20
21
  "shared/tier1-engineering-constitution.md",
21
22
  "shared/project-hooks.json",