claws-code 0.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/.claude/commands/claws-auto.md +90 -0
- package/.claude/commands/claws-bin.md +28 -0
- package/.claude/commands/claws-cleanup.md +28 -0
- package/.claude/commands/claws-do.md +82 -0
- package/.claude/commands/claws-fix.md +40 -0
- package/.claude/commands/claws-goal.md +111 -0
- package/.claude/commands/claws-help.md +54 -0
- package/.claude/commands/claws-plan.md +103 -0
- package/.claude/commands/claws-report.md +29 -0
- package/.claude/commands/claws-status.md +37 -0
- package/.claude/commands/claws-update.md +32 -0
- package/.claude/commands/claws.md +64 -0
- package/.claude/rules/claws-default-behavior.md +76 -0
- package/.claude/settings.json +112 -0
- package/.claude/settings.local.json +19 -0
- package/.claude/skills/claws-auto-engine/SKILL.md +97 -0
- package/.claude/skills/claws-goal-tracker/SKILL.md +106 -0
- package/.claude/skills/claws-prompt-templates/SKILL.md +203 -0
- package/.claude/skills/claws-wave-lead/SKILL.md +126 -0
- package/.claude/skills/claws-wave-subworker/SKILL.md +60 -0
- package/CHANGELOG.md +1949 -0
- package/LICENSE +21 -0
- package/README.md +420 -0
- package/bin/cli.js +84 -0
- package/cli.js +223 -0
- package/docs/ARCHITECTURE.md +511 -0
- package/docs/event-protocol.md +588 -0
- package/docs/features.md +562 -0
- package/docs/guide.md +891 -0
- package/docs/index.html +716 -0
- package/docs/protocol.md +323 -0
- package/extension/.vscodeignore +15 -0
- package/extension/CHANGELOG.md +1906 -0
- package/extension/LICENSE +21 -0
- package/extension/README.md +137 -0
- package/extension/docs/features.md +424 -0
- package/extension/docs/protocol.md +197 -0
- package/extension/esbuild.mjs +25 -0
- package/extension/icon.png +0 -0
- package/extension/native/.metadata.json +10 -0
- package/extension/native/node-pty/LICENSE +69 -0
- package/extension/native/node-pty/README.md +165 -0
- package/extension/native/node-pty/lib/conpty_console_list_agent.js +16 -0
- package/extension/native/node-pty/lib/conpty_console_list_agent.js.map +1 -0
- package/extension/native/node-pty/lib/eventEmitter2.js +47 -0
- package/extension/native/node-pty/lib/eventEmitter2.js.map +1 -0
- package/extension/native/node-pty/lib/index.js +52 -0
- package/extension/native/node-pty/lib/index.js.map +1 -0
- package/extension/native/node-pty/lib/interfaces.js +7 -0
- package/extension/native/node-pty/lib/interfaces.js.map +1 -0
- package/extension/native/node-pty/lib/shared/conout.js +11 -0
- package/extension/native/node-pty/lib/shared/conout.js.map +1 -0
- package/extension/native/node-pty/lib/terminal.js +190 -0
- package/extension/native/node-pty/lib/terminal.js.map +1 -0
- package/extension/native/node-pty/lib/types.js +7 -0
- package/extension/native/node-pty/lib/types.js.map +1 -0
- package/extension/native/node-pty/lib/unixTerminal.js +346 -0
- package/extension/native/node-pty/lib/unixTerminal.js.map +1 -0
- package/extension/native/node-pty/lib/utils.js +39 -0
- package/extension/native/node-pty/lib/utils.js.map +1 -0
- package/extension/native/node-pty/lib/windowsConoutConnection.js +125 -0
- package/extension/native/node-pty/lib/windowsConoutConnection.js.map +1 -0
- package/extension/native/node-pty/lib/windowsPtyAgent.js +320 -0
- package/extension/native/node-pty/lib/windowsPtyAgent.js.map +1 -0
- package/extension/native/node-pty/lib/windowsTerminal.js +199 -0
- package/extension/native/node-pty/lib/windowsTerminal.js.map +1 -0
- package/extension/native/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/extension/native/node-pty/lib/worker/conoutSocketWorker.js.map +1 -0
- package/extension/native/node-pty/package.json +64 -0
- package/extension/native/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/extension/native/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
- package/extension/package-lock.json +605 -0
- package/extension/package.json +343 -0
- package/extension/scripts/bundle-native.mjs +104 -0
- package/extension/scripts/deploy-dev.mjs +60 -0
- package/extension/src/ansi-strip.ts +52 -0
- package/extension/src/backends/vscode/claws-pty.ts +483 -0
- package/extension/src/backends/vscode/status-bar.ts +99 -0
- package/extension/src/backends/vscode/vscode-backend.ts +282 -0
- package/extension/src/capture-store.ts +125 -0
- package/extension/src/event-log.ts +629 -0
- package/extension/src/event-schemas.ts +478 -0
- package/extension/src/extension.js +492 -0
- package/extension/src/extension.ts +873 -0
- package/extension/src/lifecycle-engine.ts +60 -0
- package/extension/src/lifecycle-rules.ts +171 -0
- package/extension/src/lifecycle-store.ts +506 -0
- package/extension/src/peer-registry.ts +176 -0
- package/extension/src/pipeline-registry.ts +82 -0
- package/extension/src/platform.ts +64 -0
- package/extension/src/protocol.ts +532 -0
- package/extension/src/server-config.ts +98 -0
- package/extension/src/server.ts +2210 -0
- package/extension/src/task-registry.ts +51 -0
- package/extension/src/terminal-backend.ts +211 -0
- package/extension/src/terminal-manager.ts +395 -0
- package/extension/src/topic-registry.ts +70 -0
- package/extension/src/topic-utils.ts +46 -0
- package/extension/src/transport.ts +45 -0
- package/extension/src/uninstall-cleanup.ts +232 -0
- package/extension/src/wave-registry.ts +314 -0
- package/extension/src/websocket-transport.ts +153 -0
- package/extension/tsconfig.json +23 -0
- package/lib/capabilities.js +145 -0
- package/lib/dry-run.js +43 -0
- package/lib/install.js +1018 -0
- package/lib/mcp-setup.js +92 -0
- package/lib/platform.js +240 -0
- package/lib/preflight.js +152 -0
- package/lib/shell-hook.js +343 -0
- package/lib/uninstall.js +162 -0
- package/lib/verify.js +166 -0
- package/mcp_server.js +3529 -0
- package/package.json +48 -0
- package/rules/claws-default-behavior.md +72 -0
- package/scripts/_helpers/atomic-file.mjs +137 -0
- package/scripts/_helpers/fix-repair.js +64 -0
- package/scripts/_helpers/json-safe.mjs +218 -0
- package/scripts/bump-version.sh +84 -0
- package/scripts/codegen/gen-docs.mjs +61 -0
- package/scripts/codegen/gen-json-schema.mjs +62 -0
- package/scripts/codegen/gen-mcp-tools.mjs +358 -0
- package/scripts/codegen/gen-types.mjs +172 -0
- package/scripts/codegen/index.mjs +42 -0
- package/scripts/dev-hooks/check-extension-dirs.js +77 -0
- package/scripts/dev-hooks/check-open-claws-terminals.js +70 -0
- package/scripts/dev-hooks/check-stale-main.js +55 -0
- package/scripts/dev-hooks/check-tag-pushed.js +51 -0
- package/scripts/dev-hooks/check-tag-vs-main.js +56 -0
- package/scripts/dev-vsix-install.sh +60 -0
- package/scripts/fix.sh +702 -0
- package/scripts/gen-client-types.mjs +81 -0
- package/scripts/git-hooks/pre-commit +31 -0
- package/scripts/hooks/lifecycle-state.js +61 -0
- package/scripts/hooks/package.json +4 -0
- package/scripts/hooks/post-tool-use-claws.js +292 -0
- package/scripts/hooks/pre-bash-no-verify-block.js +72 -0
- package/scripts/hooks/pre-tool-use-claws.js +206 -0
- package/scripts/hooks/session-start-claws.js +97 -0
- package/scripts/hooks/stop-claws.js +88 -0
- package/scripts/inject-claude-md.js +205 -0
- package/scripts/inject-dev-hooks.js +96 -0
- package/scripts/inject-global-claude-md.js +140 -0
- package/scripts/inject-settings-hooks.js +370 -0
- package/scripts/install.ps1 +146 -0
- package/scripts/install.sh +1729 -0
- package/scripts/monitor-arm-watch.js +155 -0
- package/scripts/rebuild-node-pty.sh +245 -0
- package/scripts/report.sh +232 -0
- package/scripts/shell-hook.fish +164 -0
- package/scripts/shell-hook.ps1 +33 -0
- package/scripts/shell-hook.sh +232 -0
- package/scripts/stream-events.js +399 -0
- package/scripts/terminal-wrapper.sh +36 -0
- package/scripts/test-enforcement.sh +132 -0
- package/scripts/test-install.sh +174 -0
- package/scripts/test-installer-parity.sh +135 -0
- package/scripts/test-template-enforcement.sh +76 -0
- package/scripts/uninstall.sh +143 -0
- package/scripts/update.sh +337 -0
- package/scripts/verify-release.sh +323 -0
- package/scripts/verify-wrapped.sh +194 -0
- package/templates/CLAUDE.global.md +135 -0
- package/templates/CLAUDE.project.md +37 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Claws — post-install test + live demo of multi-terminal orchestration
|
|
3
|
+
# Run after install.sh. Proves every feature works end-to-end.
|
|
4
|
+
# Usage: bash scripts/test-install.sh
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
SOCK=".claws/claws.sock"
|
|
9
|
+
PASS=0
|
|
10
|
+
FAIL=0
|
|
11
|
+
|
|
12
|
+
passed() { echo " ✓ $1"; PASS=$((PASS+1)); }
|
|
13
|
+
failed() { echo " ✗ $1"; FAIL=$((FAIL+1)); }
|
|
14
|
+
|
|
15
|
+
echo ""
|
|
16
|
+
echo " ╔═══════════════════════════════════════════╗"
|
|
17
|
+
echo " ║ CLAWS — Installation Test + Live Demo ║"
|
|
18
|
+
echo " ╚═══════════════════════════════════════════╝"
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
# Test 1: Socket exists
|
|
22
|
+
echo "── Test 1: Socket connection ──"
|
|
23
|
+
if [ -S "$SOCK" ]; then
|
|
24
|
+
passed "socket found at $SOCK"
|
|
25
|
+
else
|
|
26
|
+
failed "no socket at $SOCK — did you reload VS Code?"
|
|
27
|
+
echo " Run: Cmd+Shift+P → 'Developer: Reload Window'"
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Test 2: List terminals
|
|
32
|
+
echo "── Test 2: List terminals ──"
|
|
33
|
+
COUNT=$(node -e "
|
|
34
|
+
const net=require('net');
|
|
35
|
+
const s=net.createConnection('$SOCK');
|
|
36
|
+
s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'list'})+'\n'));
|
|
37
|
+
let b='';
|
|
38
|
+
s.on('data',d=>{b+=d;if(b.includes('\n')){try{const d2=JSON.parse(b.split('\n')[0]);if(!d2.ok)throw new Error('not ok');console.log(d2.terminals.length)}catch(e){console.log('ERROR:'+e.message)};s.destroy()}});
|
|
39
|
+
s.on('error',e=>{console.log('ERROR:'+e.message);s.destroy()});
|
|
40
|
+
setTimeout(()=>{console.log('ERROR:timeout');s.destroy()},5000);
|
|
41
|
+
" 2>/dev/null)
|
|
42
|
+
if echo "$COUNT" | grep -q "^[0-9]"; then
|
|
43
|
+
passed "listed $COUNT terminal(s)"
|
|
44
|
+
else
|
|
45
|
+
failed "list command failed: $COUNT"
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Test 3: Node socket module
|
|
49
|
+
echo "── Test 3: Node net module ──"
|
|
50
|
+
if node -e "require('net'); console.log('OK')" 2>/dev/null; then
|
|
51
|
+
passed "node net module available (MCP server registered via settings.json)"
|
|
52
|
+
else
|
|
53
|
+
failed "node not available or net module missing"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# Test 4: Create + exec + read + close (full loop)
|
|
57
|
+
echo "── Test 4: Full terminal lifecycle ──"
|
|
58
|
+
node -e "
|
|
59
|
+
const net=require('net'),fs=require('fs'),crypto=require('crypto');
|
|
60
|
+
const SOCK='$SOCK';
|
|
61
|
+
|
|
62
|
+
function send(cmd){return new Promise((resolve,reject)=>{const s=net.createConnection(SOCK);s.on('connect',()=>s.write(JSON.stringify(cmd)+'\n'));let b='';s.on('data',d=>{b+=d;if(b.includes('\n')){try{resolve(JSON.parse(b.split('\n')[0]))}catch(e){reject(e)};s.destroy()}});s.on('error',e=>reject(e));setTimeout(()=>reject(new Error('timeout')),10000)})}
|
|
63
|
+
|
|
64
|
+
async function run(){
|
|
65
|
+
// Create terminal
|
|
66
|
+
const cr=await send({id:1,cmd:'create',name:'claws-test',wrapped:true});
|
|
67
|
+
if(!cr.ok)throw new Error('create failed: '+cr.error);
|
|
68
|
+
const tid=cr.id;
|
|
69
|
+
|
|
70
|
+
// Wait for terminal to start
|
|
71
|
+
await new Promise(r=>setTimeout(r,1500));
|
|
72
|
+
|
|
73
|
+
// Exec command via send + poll
|
|
74
|
+
const eid=crypto.randomBytes(4).toString('hex');
|
|
75
|
+
const base='/tmp/claws-exec';
|
|
76
|
+
try{fs.mkdirSync(base,{recursive:true})}catch(e){}
|
|
77
|
+
const outF=base+'/'+eid+'.out',doneF=base+'/'+eid+'.done';
|
|
78
|
+
const wrapper='{ echo CLAWS_TEST_PASS && date && uname -a; } > '+outF+' 2>&1; echo \$? > '+doneF;
|
|
79
|
+
await send({id:1,cmd:'send',id:tid,text:wrapper});
|
|
80
|
+
|
|
81
|
+
// Poll for completion
|
|
82
|
+
const deadline=Date.now()+30000;
|
|
83
|
+
while(Date.now()<deadline){if(fs.existsSync(doneF))break;await new Promise(r=>setTimeout(r,200))}
|
|
84
|
+
if(!fs.existsSync(doneF))throw new Error('exec timed out');
|
|
85
|
+
const exitCode=fs.readFileSync(doneF,'utf8').trim();
|
|
86
|
+
if(exitCode!=='0')throw new Error('exit code '+exitCode);
|
|
87
|
+
const output=fs.readFileSync(outF,'utf8');
|
|
88
|
+
if(!output.includes('CLAWS_TEST_PASS'))throw new Error('output missing marker');
|
|
89
|
+
try{fs.unlinkSync(outF)}catch(e){}
|
|
90
|
+
try{fs.unlinkSync(doneF)}catch(e){}
|
|
91
|
+
|
|
92
|
+
// Read log
|
|
93
|
+
const lr=await send({id:1,cmd:'readLog',id:tid,strip:true});
|
|
94
|
+
if(!lr.ok)throw new Error('readLog failed: '+lr.error);
|
|
95
|
+
if(!lr.bytes||lr.bytes.length===0)throw new Error('empty log');
|
|
96
|
+
|
|
97
|
+
// Close terminal
|
|
98
|
+
await send({id:1,cmd:'close',id:tid});
|
|
99
|
+
console.log(' ✓ create → exec → readLog → close — all passed');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
run().catch(e=>{console.log(' ✗ lifecycle test failed: '+e.message);process.exit(1)});
|
|
103
|
+
" 2>/dev/null
|
|
104
|
+
|
|
105
|
+
# Test 5: Multi-terminal orchestration demo
|
|
106
|
+
echo ""
|
|
107
|
+
echo "── Test 5: LIVE DEMO — Multi-terminal orchestration ──"
|
|
108
|
+
echo ""
|
|
109
|
+
node -e "
|
|
110
|
+
const net=require('net'),fs=require('fs'),crypto=require('crypto');
|
|
111
|
+
const SOCK='$SOCK';
|
|
112
|
+
|
|
113
|
+
function send(cmd){return new Promise((resolve,reject)=>{const s=net.createConnection(SOCK);s.on('connect',()=>s.write(JSON.stringify(cmd)+'\n'));let b='';s.on('data',d=>{b+=d;if(b.includes('\n')){try{resolve(JSON.parse(b.split('\n')[0]))}catch(e){reject(e)};s.destroy()}});s.on('error',e=>reject(e));setTimeout(()=>reject(new Error('timeout')),10000)})}
|
|
114
|
+
|
|
115
|
+
async function run(){
|
|
116
|
+
// Spawn 3 workers
|
|
117
|
+
console.log(' Spawning 3 parallel workers...');
|
|
118
|
+
const workers={};
|
|
119
|
+
const specs=[
|
|
120
|
+
{name:'worker-alpha',cmd:\"echo 'Alpha reporting' && sleep 1 && echo 'Alpha done'\"},
|
|
121
|
+
{name:'worker-beta',cmd:\"echo 'Beta reporting' && ls -1 | head -5 && echo 'Beta done'\"},
|
|
122
|
+
{name:'worker-gamma',cmd:\"echo 'Gamma reporting' && date && whoami && echo 'Gamma done'\"}
|
|
123
|
+
];
|
|
124
|
+
for(const spec of specs){
|
|
125
|
+
const cr=await send({id:1,cmd:'create',name:spec.name,wrapped:true});
|
|
126
|
+
workers[spec.name]={id:cr.id,cmd:spec.cmd};
|
|
127
|
+
await new Promise(r=>setTimeout(r,500));
|
|
128
|
+
}
|
|
129
|
+
console.log(' ✓ 3 terminals spawned: '+Object.keys(workers).join(', '));
|
|
130
|
+
|
|
131
|
+
// Fire all commands in parallel
|
|
132
|
+
console.log(' Firing commands into all 3...');
|
|
133
|
+
for(const [name,w] of Object.entries(workers)){
|
|
134
|
+
await send({id:1,cmd:'send',id:w.id,text:w.cmd});
|
|
135
|
+
}
|
|
136
|
+
console.log(' ✓ Commands sent to all 3 workers');
|
|
137
|
+
|
|
138
|
+
// Wait and collect results
|
|
139
|
+
console.log(' Waiting for results...');
|
|
140
|
+
await new Promise(r=>setTimeout(r,3000));
|
|
141
|
+
|
|
142
|
+
console.log('');
|
|
143
|
+
console.log(' ┌─────────────────────────────────────────────┐');
|
|
144
|
+
for(const [name,w] of Object.entries(workers)){
|
|
145
|
+
const lr=await send({id:1,cmd:'readLog',id:w.id,strip:true});
|
|
146
|
+
const log=lr.ok?(lr.bytes||''):'';
|
|
147
|
+
const lines=log.split('\n').filter(l=>l.trim()&&l.toLowerCase().includes('done'));
|
|
148
|
+
const status=lines.length>0?'DONE':'...';
|
|
149
|
+
console.log(' │ '+name.padEnd(20)+' ['+status+']');
|
|
150
|
+
}
|
|
151
|
+
console.log(' └─────────────────────────────────────────────┘');
|
|
152
|
+
console.log('');
|
|
153
|
+
|
|
154
|
+
// Cleanup
|
|
155
|
+
for(const [name,w] of Object.entries(workers)){
|
|
156
|
+
await send({id:1,cmd:'close',id:w.id});
|
|
157
|
+
}
|
|
158
|
+
console.log(' ✓ All 3 workers closed. Terminals cleaned up.');
|
|
159
|
+
console.log('');
|
|
160
|
+
console.log(' Multi-terminal orchestration works. You\\'re ready.');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
run().catch(e=>{console.log(' ✗ demo failed: '+e.message);process.exit(1)});
|
|
164
|
+
" 2>/dev/null
|
|
165
|
+
|
|
166
|
+
echo ""
|
|
167
|
+
echo " ════════════════════════════════════════════"
|
|
168
|
+
echo " Results: $PASS passed"
|
|
169
|
+
echo ""
|
|
170
|
+
echo " Your terminals are now programmable."
|
|
171
|
+
echo " Docs: https://github.com/neunaha/claws"
|
|
172
|
+
echo " Website: https://neunaha.github.io/claws/"
|
|
173
|
+
echo " ════════════════════════════════════════════"
|
|
174
|
+
echo ""
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# scripts/test-installer-parity.sh — parity harness: bash install.sh vs node bin/cli.js install
|
|
3
|
+
#
|
|
4
|
+
# Creates two temp project dirs, runs bash and node installers, diffs:
|
|
5
|
+
# .mcp.json claws entry (normalized), CLAUDE.md CLAWS:BEGIN block,
|
|
6
|
+
# .claude/settings.json hooks, .claws-bin/ file list, shell rc hook line.
|
|
7
|
+
# Exits 0 on zero diff, 1 otherwise with concrete diff output.
|
|
8
|
+
|
|
9
|
+
set -euo pipefail
|
|
10
|
+
|
|
11
|
+
REPO="$(cd "$(dirname "$0")/.." && pwd)"
|
|
12
|
+
TMP="$(mktemp -d /tmp/claws-parity-XXXXXX)"
|
|
13
|
+
# Use same basename so {PROJECT_NAME} matches in both CLAUDE.md blocks
|
|
14
|
+
A="$TMP/a/claws-parity-project"
|
|
15
|
+
B="$TMP/b/claws-parity-project"
|
|
16
|
+
SRC="$TMP/src"
|
|
17
|
+
HOME_A="$TMP/home-a"
|
|
18
|
+
HOME_B="$TMP/home-b"
|
|
19
|
+
trap 'rm -rf "$TMP"' EXIT
|
|
20
|
+
FAIL=0
|
|
21
|
+
|
|
22
|
+
_ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
|
|
23
|
+
_fail() { printf ' \033[31m✗\033[0m %s\n' "$1"; FAIL=$((FAIL+1)); }
|
|
24
|
+
_diff() { diff -u "$1" "$2" 2>/dev/null | head -30 || true; }
|
|
25
|
+
|
|
26
|
+
mkdir -p "$A" "$B" "$HOME_A/.claude" "$HOME_B/.claude"
|
|
27
|
+
|
|
28
|
+
# ── Build source clone for bash installer ─────────────────────────────────────
|
|
29
|
+
printf '\n[parity] cloning source for bash installer...\n'
|
|
30
|
+
git clone --local --no-hardlinks -q "$REPO" "$SRC"
|
|
31
|
+
# Pre-seed pre-built artifacts so bash skips extension build
|
|
32
|
+
[ -d "$REPO/extension/dist" ] && cp -R "$REPO/extension/dist" "$SRC/extension/"
|
|
33
|
+
[ -d "$REPO/extension/native" ] && cp -R "$REPO/extension/native" "$SRC/extension/"
|
|
34
|
+
# Align .build-sha with clone HEAD so needs_build() returns false
|
|
35
|
+
git -C "$SRC" rev-parse HEAD > "$SRC/extension/dist/.build-sha" 2>/dev/null || true
|
|
36
|
+
# Touch bundle so find -newer finds no src files newer than it
|
|
37
|
+
touch "$SRC/extension/dist/extension.js" 2>/dev/null || true
|
|
38
|
+
|
|
39
|
+
# ── Run bash installer ────────────────────────────────────────────────────────
|
|
40
|
+
printf '[parity] running bash install.sh in proj A...\n'
|
|
41
|
+
(
|
|
42
|
+
cd "$A"
|
|
43
|
+
CLAWS_DIR="$SRC" CLAWS_NO_LOG=1 CLAWS_NO_GLOBAL_HOOKS=1 \
|
|
44
|
+
CLAWS_EDITOR=skip CLAWS_SKIP_EXTENSION_COPY=1 CLAWS_SKIP_VSCODE_RECOMMEND=1 \
|
|
45
|
+
HOME="$HOME_A" \
|
|
46
|
+
bash "$REPO/scripts/install.sh" 2>&1
|
|
47
|
+
) | grep -E '^\s*(✓|!|✗|\[)' | head -20 || true
|
|
48
|
+
|
|
49
|
+
# ── Run node installer ────────────────────────────────────────────────────────
|
|
50
|
+
printf '[parity] running node bin/cli.js install in proj B...\n'
|
|
51
|
+
(
|
|
52
|
+
cd "$B"
|
|
53
|
+
HOME="$HOME_B" CLAWS_SKIP_EXTENSION_COPY=1 \
|
|
54
|
+
node "$REPO/bin/cli.js" install --no-hooks 2>&1
|
|
55
|
+
) | grep -E '^\s*(✓|!|\[)' | head -20 || true
|
|
56
|
+
|
|
57
|
+
# ── Compare artifacts ─────────────────────────────────────────────────────────
|
|
58
|
+
printf '\n[parity] comparing artifacts...\n'
|
|
59
|
+
|
|
60
|
+
# (a) .mcp.json: normalize absolute paths → relative before comparing
|
|
61
|
+
_norm_mcp() {
|
|
62
|
+
node -e "
|
|
63
|
+
const c = JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'));
|
|
64
|
+
const e = (c.mcpServers||{}).claws || {};
|
|
65
|
+
const args = (e.args||[]).map(a => a.replace(/^.*\\/\\.claws-bin\\//, '.claws-bin/'));
|
|
66
|
+
process.stdout.write(JSON.stringify({ command: e.command||'', args }) + '\n');
|
|
67
|
+
" "$1"
|
|
68
|
+
}
|
|
69
|
+
if [ -f "$A/.mcp.json" ] && [ -f "$B/.mcp.json" ]; then
|
|
70
|
+
A_MCP="$(_norm_mcp "$A/.mcp.json")"; B_MCP="$(_norm_mcp "$B/.mcp.json")"
|
|
71
|
+
if [ "$A_MCP" = "$B_MCP" ]; then _ok ".mcp.json"
|
|
72
|
+
else _fail ".mcp.json"; printf ' bash: %s\n node: %s\n' "$A_MCP" "$B_MCP"; fi
|
|
73
|
+
else
|
|
74
|
+
_fail ".mcp.json missing: bash=$( [ -f "$A/.mcp.json" ] && echo Y || echo N) node=$( [ -f "$B/.mcp.json" ] && echo Y || echo N)"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# (b) CLAUDE.md CLAWS:BEGIN block (normalize project-name and cmds-list lines)
|
|
78
|
+
_extract_block() {
|
|
79
|
+
awk '/<!-- CLAWS:BEGIN/,/<!-- CLAWS:END/{print}' "$1" 2>/dev/null \
|
|
80
|
+
| grep -vE '\{PROJECT_NAME\}|claws-parity-project|^.*\bclaws-[a-z-]+\b.*$|CMDS_COUNT|CMDS_LIST|Slash commands \([0-9]+\)' \
|
|
81
|
+
|| true
|
|
82
|
+
}
|
|
83
|
+
if [ -f "$A/CLAUDE.md" ] && [ -f "$B/CLAUDE.md" ]; then
|
|
84
|
+
BA="$(_extract_block "$A/CLAUDE.md")"; BB="$(_extract_block "$B/CLAUDE.md")"
|
|
85
|
+
if [ "$BA" = "$BB" ] && [ -n "$BA" ]; then _ok "CLAUDE.md CLAWS:BEGIN block"
|
|
86
|
+
else _fail "CLAUDE.md CLAWS:BEGIN block"; _diff <(echo "$BA") <(echo "$BB"); fi
|
|
87
|
+
else
|
|
88
|
+
_fail "CLAUDE.md missing: bash=$( [ -f "$A/CLAUDE.md" ] && echo Y || echo N) node=$( [ -f "$B/CLAUDE.md" ] && echo Y || echo N)"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
# (c) .claude/settings.json hooks (both --no-hooks → should be absent)
|
|
92
|
+
_get_hooks() {
|
|
93
|
+
[ -f "$1" ] && node -e "
|
|
94
|
+
try{ const c=JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'));
|
|
95
|
+
process.stdout.write(JSON.stringify(c.hooks||{})); }catch{process.stdout.write('{}')}
|
|
96
|
+
" "$1" 2>/dev/null || printf '{}'
|
|
97
|
+
}
|
|
98
|
+
HA="$(_get_hooks "$HOME_A/.claude/settings.json")"
|
|
99
|
+
HB="$(_get_hooks "$HOME_B/.claude/settings.json")"
|
|
100
|
+
if [ "$HA" = "$HB" ]; then _ok ".claude/settings.json hooks"
|
|
101
|
+
else _fail ".claude/settings.json hooks differ"; printf ' bash: %s\n node: %s\n' "$HA" "$HB"; fi
|
|
102
|
+
|
|
103
|
+
# (d) .claws-bin/ file list
|
|
104
|
+
FILES_A="$(cd "$A" && find .claws-bin -type f 2>/dev/null | sort || true)"
|
|
105
|
+
FILES_B="$(cd "$B" && find .claws-bin -type f 2>/dev/null | sort || true)"
|
|
106
|
+
if [ "$FILES_A" = "$FILES_B" ] && [ -n "$FILES_A" ]; then _ok ".claws-bin/ file list"
|
|
107
|
+
else _fail ".claws-bin/ file list"; _diff <(echo "$FILES_A") <(echo "$FILES_B"); fi
|
|
108
|
+
|
|
109
|
+
# (e) Shell rc-file: both must reference shell-hook.sh
|
|
110
|
+
RC_A="$(grep -rh 'shell-hook\.sh' "$HOME_A"/.zshrc "$HOME_A"/.bashrc 2>/dev/null | head -1 || true)"
|
|
111
|
+
RC_B="$(grep -rh 'shell-hook\.sh' "$HOME_B"/.zshrc "$HOME_B"/.bashrc 2>/dev/null | head -1 || true)"
|
|
112
|
+
if [ -n "$RC_A" ] && [ -n "$RC_B" ]; then _ok "shell rc-file (shell-hook.sh sourced in both)"
|
|
113
|
+
else _fail "shell rc-file: bash='${RC_A:-MISSING}' node='${RC_B:-MISSING}'"; fi
|
|
114
|
+
|
|
115
|
+
# (f) Project-local .claude/rules/ and .claude/skills/ — W7-6 regression guard
|
|
116
|
+
# Both installers must write claws-default-behavior.md into <project>/.claude/rules/
|
|
117
|
+
# and at least one skill dir into <project>/.claude/skills/.
|
|
118
|
+
RULES_A="$([ -d "$A/.claude/rules" ] && echo "Y" || echo "N")"
|
|
119
|
+
RULES_B="$([ -d "$B/.claude/rules" ] && echo "Y" || echo "N")"
|
|
120
|
+
SKILLS_A="$([ -d "$A/.claude/skills" ] && echo "Y" || echo "N")"
|
|
121
|
+
SKILLS_B="$([ -d "$B/.claude/skills" ] && echo "Y" || echo "N")"
|
|
122
|
+
if [ "$RULES_A" = "Y" ] && [ "$RULES_B" = "Y" ]; then _ok ".claude/rules/ project-local (both)"
|
|
123
|
+
else _fail ".claude/rules/ project-local: bash=$RULES_A node=$RULES_B"; fi
|
|
124
|
+
if [ "$SKILLS_A" = "Y" ] && [ "$SKILLS_B" = "Y" ]; then _ok ".claude/skills/ project-local (both)"
|
|
125
|
+
else _fail ".claude/skills/ project-local: bash=$SKILLS_A node=$SKILLS_B"; fi
|
|
126
|
+
# Guard: neither installer should put rules/skills into the fake HOME
|
|
127
|
+
RULES_HOME_A="$([ -d "$HOME_A/.claude/rules" ] && echo "Y" || echo "N")"
|
|
128
|
+
RULES_HOME_B="$([ -d "$HOME_B/.claude/rules" ] && echo "Y" || echo "N")"
|
|
129
|
+
if [ "$RULES_HOME_A" = "N" ] && [ "$RULES_HOME_B" = "N" ]; then _ok ".claude/rules/ not leaked to HOME (both)"
|
|
130
|
+
else _fail ".claude/rules/ leaked to HOME: bash=$RULES_HOME_A node=$RULES_HOME_B"; fi
|
|
131
|
+
|
|
132
|
+
printf '\n[parity] '
|
|
133
|
+
[ "$FAIL" -eq 0 ] && printf '\033[32mPASS\033[0m — all %d checks green\n' 8 || \
|
|
134
|
+
printf '\033[31mFAIL\033[0m — %d check(s) failed\n' "$FAIL"
|
|
135
|
+
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT='/Users/ANISH.NEUNAHA/Desktop/Claws'
|
|
5
|
+
TMPDIR=$(mktemp -d)
|
|
6
|
+
TMPHOME=$(mktemp -d)
|
|
7
|
+
trap 'rm -rf "$TMPDIR" "$TMPHOME"' EXIT
|
|
8
|
+
|
|
9
|
+
fail() { echo "FAIL: $*" >&2; exit 1; }
|
|
10
|
+
|
|
11
|
+
VERSION=$(node -e "console.log(require('$ROOT/package.json').version)")
|
|
12
|
+
|
|
13
|
+
# 1. Run project injector against TMPDIR
|
|
14
|
+
mkdir -p "$TMPDIR/.claude/commands"
|
|
15
|
+
cp "$ROOT/.claude/commands/"claws*.md "$TMPDIR/.claude/commands/" 2>/dev/null || true
|
|
16
|
+
node "$ROOT/scripts/inject-claude-md.js" "$TMPDIR" >/dev/null
|
|
17
|
+
PROJECT_MD="$TMPDIR/CLAUDE.md"
|
|
18
|
+
[ -f "$PROJECT_MD" ] || fail "project CLAUDE.md not created"
|
|
19
|
+
|
|
20
|
+
# 2. Run global injector with HOME redirected
|
|
21
|
+
HOME="$TMPHOME" node "$ROOT/scripts/inject-global-claude-md.js" >/dev/null
|
|
22
|
+
GLOBAL_MD="$TMPHOME/.claude/CLAUDE.md"
|
|
23
|
+
[ -f "$GLOBAL_MD" ] || fail "global CLAUDE.md not created"
|
|
24
|
+
|
|
25
|
+
# 3. PROJECT presence assertions
|
|
26
|
+
for s in 'claws_done' '__CLAWS_DONE__' 'claws_fleet' 'claws_dispatch_subworker' 'claws_drain_events' 'claws_workers_wait' 'SESSION-BOOT' 'SESSION-END'; do
|
|
27
|
+
grep -q -- "$s" "$PROJECT_MD" || fail "project: missing required string '$s'"
|
|
28
|
+
done
|
|
29
|
+
grep -q "<!-- CLAWS:BEGIN v$VERSION -->" "$PROJECT_MD" || fail "project: missing versioned sentinel v$VERSION"
|
|
30
|
+
|
|
31
|
+
# 4. PROJECT absence assertions
|
|
32
|
+
for s in 'MARK_M??_OK_COLOR' 'bypass permissions' 'No marker required'; do
|
|
33
|
+
grep -q -- "$s" "$PROJECT_MD" && fail "project: forbidden string '$s' present" || true
|
|
34
|
+
done
|
|
35
|
+
|
|
36
|
+
# 5. GLOBAL presence assertions
|
|
37
|
+
for s in 'claws_done' '__CLAWS_DONE__' 'SESSION-BOOT' 'SESSION-END' 'FAILED' 'mode-aware'; do
|
|
38
|
+
grep -q -- "$s" "$GLOBAL_MD" || fail "global: missing required string '$s'"
|
|
39
|
+
done
|
|
40
|
+
grep -q "<!-- CLAWS-GLOBAL:BEGIN v$VERSION -->" "$GLOBAL_MD" || fail "global: missing versioned sentinel v$VERSION"
|
|
41
|
+
|
|
42
|
+
# 6. GLOBAL absence assertions
|
|
43
|
+
for s in 'MARK_M??_OK_COLOR' 'bypass permissions' 'No marker required'; do
|
|
44
|
+
grep -q -- "$s" "$GLOBAL_MD" && fail "global: forbidden string '$s' present" || true
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
# 7. Tool-list completeness: extracted tools must equal mcp_server.js dispatch surface
|
|
48
|
+
INJECTED_TOOLS=$(grep -oE 'claws_[a-z_]+' "$PROJECT_MD" | sort -u)
|
|
49
|
+
ACTUAL_TOOLS=$(grep -oE "name === 'claws_[a-z_]+'" "$ROOT/mcp_server.js" | grep -oE 'claws_[a-z_]+' | sort -u)
|
|
50
|
+
if [ "$INJECTED_TOOLS" != "$ACTUAL_TOOLS" ]; then
|
|
51
|
+
echo 'TOOL DRIFT:' >&2
|
|
52
|
+
diff <(echo "$INJECTED_TOOLS") <(echo "$ACTUAL_TOOLS") >&2 || true
|
|
53
|
+
fail 'project: injected tool list does not match mcp_server.js surface'
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# 8. Phase completeness: phases in injected block must equal Phase enum in lifecycle-store.ts
|
|
57
|
+
ACTUAL_PHASES=$(grep -oE "'[A-Z][A-Z0-9-]+'" "$ROOT/extension/src/lifecycle-store.ts" | head -20 | tr -d "'" | sort -u)
|
|
58
|
+
for phase in $ACTUAL_PHASES; do
|
|
59
|
+
grep -q -- "$phase" "$PROJECT_MD" || fail "project: missing phase '$phase'"
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
# 9. Idempotence: second run should report unchanged
|
|
63
|
+
SECOND=$(node "$ROOT/scripts/inject-claude-md.js" "$TMPDIR")
|
|
64
|
+
echo "$SECOND" | grep -q 'already has the current Claws block' || fail "project injector not idempotent: $SECOND"
|
|
65
|
+
|
|
66
|
+
# 10. Sentinel migration: pre-seed an old unversioned sentinel and verify it's replaced
|
|
67
|
+
MIG=$(mktemp -d)
|
|
68
|
+
mkdir -p "$MIG/.claude/commands"
|
|
69
|
+
printf '# old project\n\n<!-- CLAWS:BEGIN -->\nlegacy text\n<!-- CLAWS:END -->\n' > "$MIG/CLAUDE.md"
|
|
70
|
+
node "$ROOT/scripts/inject-claude-md.js" "$MIG" >/dev/null
|
|
71
|
+
BLOCKS=$(grep -c '<!-- CLAWS:BEGIN' "$MIG/CLAUDE.md" || true)
|
|
72
|
+
[ "$BLOCKS" = '1' ] || fail "sentinel migration: expected 1 BEGIN block, found $BLOCKS"
|
|
73
|
+
grep -q "<!-- CLAWS:BEGIN v$VERSION -->" "$MIG/CLAUDE.md" || fail "sentinel migration: new versioned sentinel not present after upgrade"
|
|
74
|
+
rm -rf "$MIG"
|
|
75
|
+
|
|
76
|
+
echo 'OK — all template enforcement checks passed (v'"$VERSION"', '"$(echo "$ACTUAL_TOOLS" | wc -l | tr -d ' ')"' tools)'
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claws — uninstall script
|
|
3
|
+
# Removes all Claws artifacts from the current project and the user's shell config.
|
|
4
|
+
# Idempotent: re-running is safe even if some components were already removed.
|
|
5
|
+
#
|
|
6
|
+
# Usage (from your project root or any directory):
|
|
7
|
+
# bash ~/.claws-src/scripts/uninstall.sh
|
|
8
|
+
# bash /path/to/claws/scripts/uninstall.sh
|
|
9
|
+
#
|
|
10
|
+
# What is NOT removed automatically (requires manual steps):
|
|
11
|
+
# - The VS Code extension — run: code --uninstall-extension neunaha.claws
|
|
12
|
+
# - The Claws source repo (~/.claws-src) — remove manually if desired: rm -rf ~/.claws-src
|
|
13
|
+
|
|
14
|
+
set -eo pipefail
|
|
15
|
+
|
|
16
|
+
# ── Colour helpers ────────────────────────────────────────────────────────────
|
|
17
|
+
if [ -t 1 ]; then
|
|
18
|
+
C_RESET='\033[0m'; C_BOLD='\033[1m'
|
|
19
|
+
C_BLUE='\033[0;34m'; C_GREEN='\033[0;32m'; C_YELLOW='\033[0;33m'; C_RED='\033[0;31m'; C_DIM='\033[2m'
|
|
20
|
+
else
|
|
21
|
+
C_RESET=''; C_BOLD=''; C_BLUE=''; C_GREEN=''; C_YELLOW=''; C_RED=''; C_DIM=''
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
ok() { printf " ${C_GREEN}✓${C_RESET} %s\n" "$*"; }
|
|
25
|
+
warn() { printf " ${C_YELLOW}!${C_RESET} %s\n" "$*"; }
|
|
26
|
+
info() { printf " ${C_DIM}%s${C_RESET}\n" "$*"; }
|
|
27
|
+
step() { printf "\n${C_BOLD}${C_BLUE}%s${C_RESET}\n" "$*"; }
|
|
28
|
+
|
|
29
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
30
|
+
INSTALL_DIR="$(dirname "$SCRIPT_DIR")"
|
|
31
|
+
PROJECT_ROOT="${PWD}"
|
|
32
|
+
|
|
33
|
+
echo ""
|
|
34
|
+
printf "${C_BOLD}${C_BLUE}Claws Uninstaller${C_RESET}\n"
|
|
35
|
+
printf "${C_DIM}Project root: %s${C_RESET}\n" "$PROJECT_ROOT"
|
|
36
|
+
printf "${C_DIM}Claws source: %s${C_RESET}\n" "$INSTALL_DIR"
|
|
37
|
+
echo ""
|
|
38
|
+
|
|
39
|
+
# ── Step 1: Deregister lifecycle hooks from ~/.claude/settings.json ──────────
|
|
40
|
+
step "[1/5] Removing lifecycle hooks from ~/.claude/settings.json"
|
|
41
|
+
HOOKS_SCRIPT="$INSTALL_DIR/scripts/inject-settings-hooks.js"
|
|
42
|
+
if [ -f "$HOOKS_SCRIPT" ]; then
|
|
43
|
+
if node "$HOOKS_SCRIPT" --remove 2>/dev/null; then
|
|
44
|
+
ok "hooks deregistered"
|
|
45
|
+
else
|
|
46
|
+
warn "hook removal returned non-zero — hooks may already be absent"
|
|
47
|
+
fi
|
|
48
|
+
else
|
|
49
|
+
warn "inject-settings-hooks.js not found at $HOOKS_SCRIPT — skipping hook removal"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# ── Step 2: Strip CLAWS:BEGIN/END blocks from CLAUDE.md files ────────────────
|
|
53
|
+
step "[2/5] Stripping CLAWS:BEGIN blocks from CLAUDE.md files"
|
|
54
|
+
|
|
55
|
+
strip_claws_block() {
|
|
56
|
+
local file="$1"
|
|
57
|
+
if [ ! -f "$file" ]; then
|
|
58
|
+
info "not found: $file — skipping"
|
|
59
|
+
return
|
|
60
|
+
fi
|
|
61
|
+
if ! grep -q "CLAWS:BEGIN" "$file" 2>/dev/null; then
|
|
62
|
+
info "no CLAWS:BEGIN block in $file — nothing to strip"
|
|
63
|
+
return
|
|
64
|
+
fi
|
|
65
|
+
local tmp
|
|
66
|
+
tmp=$(mktemp)
|
|
67
|
+
awk '/# CLAWS:BEGIN/,/# CLAWS:END/{next} {print}' "$file" > "$tmp" && mv "$tmp" "$file"
|
|
68
|
+
ok "stripped CLAWS:BEGIN block from $file"
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
strip_claws_block "$PROJECT_ROOT/CLAUDE.md"
|
|
72
|
+
strip_claws_block "$HOME/.claude/CLAUDE.md"
|
|
73
|
+
|
|
74
|
+
# ── Step 3: Remove shell hook source line from rc files ──────────────────────
|
|
75
|
+
step "[3/5] Removing shell hook from rc files"
|
|
76
|
+
|
|
77
|
+
remove_hook_from_rc() {
|
|
78
|
+
local rcfile="$1"
|
|
79
|
+
if [ ! -f "$rcfile" ]; then
|
|
80
|
+
return
|
|
81
|
+
fi
|
|
82
|
+
if ! grep -q "CLAWS terminal hook\|shell-hook\.sh" "$rcfile" 2>/dev/null; then
|
|
83
|
+
return
|
|
84
|
+
fi
|
|
85
|
+
local tmp
|
|
86
|
+
tmp=$(mktemp)
|
|
87
|
+
awk '
|
|
88
|
+
/# CLAWS terminal hook/ { skip=1; next }
|
|
89
|
+
skip && /shell-hook\.sh/ { skip=0; next }
|
|
90
|
+
skip { skip=0; print }
|
|
91
|
+
{ print }
|
|
92
|
+
' "$rcfile" > "$tmp" && mv "$tmp" "$rcfile"
|
|
93
|
+
ok "removed Claws hook from $rcfile"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
remove_hook_from_rc "$HOME/.zshrc"
|
|
97
|
+
remove_hook_from_rc "$HOME/.bashrc"
|
|
98
|
+
remove_hook_from_rc "$HOME/.bash_profile"
|
|
99
|
+
|
|
100
|
+
FISH_CONF="${XDG_CONFIG_HOME:-$HOME/.config}/fish/conf.d/claws.fish"
|
|
101
|
+
if [ -f "$FISH_CONF" ]; then
|
|
102
|
+
rm -f "$FISH_CONF"
|
|
103
|
+
ok "removed $FISH_CONF"
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
NUSHELL_ENV="${XDG_CONFIG_HOME:-$HOME/.config}/nushell/env.nu"
|
|
107
|
+
if [ -f "$NUSHELL_ENV" ] && grep -q "CLAWS_DIR\|claws" "$NUSHELL_ENV" 2>/dev/null; then
|
|
108
|
+
_nu_tmp=$(mktemp)
|
|
109
|
+
grep -v "CLAWS_DIR\|claws" "$NUSHELL_ENV" > "$_nu_tmp" && mv "$_nu_tmp" "$NUSHELL_ENV"
|
|
110
|
+
ok "removed Claws lines from $NUSHELL_ENV"
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# ── Step 4: Remove project-local Claws directories ───────────────────────────
|
|
114
|
+
step "[4/5] Removing .claws-bin/ and .claws/ from project root"
|
|
115
|
+
|
|
116
|
+
if [ -d "$PROJECT_ROOT/.claws-bin" ]; then
|
|
117
|
+
rm -rf "$PROJECT_ROOT/.claws-bin"
|
|
118
|
+
ok "removed $PROJECT_ROOT/.claws-bin"
|
|
119
|
+
else
|
|
120
|
+
info ".claws-bin/ not found — already removed"
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
if [ -d "$PROJECT_ROOT/.claws" ]; then
|
|
124
|
+
rm -rf "$PROJECT_ROOT/.claws"
|
|
125
|
+
ok "removed $PROJECT_ROOT/.claws"
|
|
126
|
+
else
|
|
127
|
+
info ".claws/ not found — already removed"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# ── Step 5: Manual step — uninstall VS Code extension ────────────────────────
|
|
131
|
+
step "[5/5] VS Code extension (manual step required)"
|
|
132
|
+
echo ""
|
|
133
|
+
printf " Run this command to uninstall the Claws VS Code extension:\n\n"
|
|
134
|
+
printf " ${C_YELLOW}NOTE: this uninstalls Claws machine-wide from your editor (not just this project).${C_RESET}\n"
|
|
135
|
+
printf " ${C_YELLOW}If Claws is installed in other projects you want to keep, do NOT run this.${C_RESET}\n\n"
|
|
136
|
+
printf " ${C_BOLD}code --uninstall-extension neunaha.claws${C_RESET}\n\n"
|
|
137
|
+
printf " (If you use Cursor: ${C_BOLD}cursor --uninstall-extension neunaha.claws${C_RESET})\n"
|
|
138
|
+
printf " (If you use Windsurf: ${C_BOLD}windsurf --uninstall-extension neunaha.claws${C_RESET})\n\n"
|
|
139
|
+
|
|
140
|
+
echo ""
|
|
141
|
+
ok "Claws uninstall complete."
|
|
142
|
+
info "You may also remove the source repo: rm -rf $INSTALL_DIR"
|
|
143
|
+
echo ""
|