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,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Layer 1 of per-worker Monitor enforcement.
|
|
3
|
+
//
|
|
4
|
+
// Catches the gap where lifecycle.monitors[] is pre-populated by mcp_server
|
|
5
|
+
// atomically at spawn time, so the PostToolUse hook's monitors.some() check
|
|
6
|
+
// is vacuously satisfied even when no OS-level stream-events.js process is
|
|
7
|
+
// actually arming. This script sleeps grace_ms, then checks via pgrep whether
|
|
8
|
+
// a real stream-events.js --wait <corrId> process is alive. If not, it
|
|
9
|
+
// connects to the claws socket and publishes system.monitor.unarmed.
|
|
10
|
+
//
|
|
11
|
+
// Layer 2 (planned: hello-with-monitorCorrelationId) will close the loophole
|
|
12
|
+
// structurally by having stream-events.js register its corrId via hello;
|
|
13
|
+
// Layer 1 detects and emits a warning event.
|
|
14
|
+
//
|
|
15
|
+
// Idempotent: publishing system.monitor.unarmed twice for the same corrId is
|
|
16
|
+
// harmless — consumers can dedupe on correlation_id.
|
|
17
|
+
//
|
|
18
|
+
// Usage: node monitor-arm-watch.js --corr-id <uuid> --term-id <id>
|
|
19
|
+
// [--grace-ms <ms>] --socket <path>
|
|
20
|
+
// Exit codes: 0 = monitor found, 1 = unarmed (event published), 2 = error
|
|
21
|
+
'use strict';
|
|
22
|
+
|
|
23
|
+
const { spawnSync } = require('child_process');
|
|
24
|
+
const net = require('net');
|
|
25
|
+
|
|
26
|
+
const rawArgs = process.argv.slice(2);
|
|
27
|
+
let corrId = null;
|
|
28
|
+
let termId = null;
|
|
29
|
+
let graceMs = 10000;
|
|
30
|
+
let socketPath = null;
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
33
|
+
const a = rawArgs[i];
|
|
34
|
+
if (a === '--corr-id') { corrId = rawArgs[++i] || null; }
|
|
35
|
+
else if (a === '--term-id') { termId = String(rawArgs[++i] ?? ''); }
|
|
36
|
+
else if (a === '--grace-ms') { graceMs = parseInt(rawArgs[++i], 10) || 10000; }
|
|
37
|
+
else if (a === '--socket') { socketPath = rawArgs[++i] || null; }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (!corrId || !socketPath) {
|
|
41
|
+
process.stderr.write(`monitor-arm-watch: exit 2 | reason=missing-args | corr=${corrId}\n`);
|
|
42
|
+
process.exit(2);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Emit a startup line immediately (before the grace-period sleep) so the log
|
|
46
|
+
// file is non-empty even if we crash during the sleep or pgrep phases.
|
|
47
|
+
process.stderr.write(
|
|
48
|
+
`monitor-arm-watch: starting | corr=${corrId} | term=${termId}` +
|
|
49
|
+
` | socket=${socketPath} | cwd=${process.cwd()}\n`
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
(async () => {
|
|
53
|
+
await sleep(graceMs);
|
|
54
|
+
|
|
55
|
+
let pg;
|
|
56
|
+
try {
|
|
57
|
+
pg = spawnSync('/usr/bin/pgrep', ['-f', `stream-events.js.*--wait ${corrId}`], {
|
|
58
|
+
encoding: 'utf8',
|
|
59
|
+
timeout: 5000,
|
|
60
|
+
});
|
|
61
|
+
} catch (e) {
|
|
62
|
+
process.stderr.write(`monitor-arm-watch: exit 2 | reason=pgrep-spawn-failed:${e.message} | corr=${corrId}\n`);
|
|
63
|
+
process.exit(2);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (pg.error) {
|
|
67
|
+
process.stderr.write(`monitor-arm-watch: exit 2 | reason=pgrep-error:${pg.error.message} | corr=${corrId}\n`);
|
|
68
|
+
process.exit(2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (pg.status === 0) {
|
|
72
|
+
// Monitor process is alive — nothing to do.
|
|
73
|
+
process.stderr.write(`monitor-arm-watch: exit 0 | reason=monitor-found | corr=${corrId}\n`);
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (pg.status === 1) {
|
|
78
|
+
// No matching process — publish warning event.
|
|
79
|
+
try {
|
|
80
|
+
await publishUnarmed(socketPath, {
|
|
81
|
+
terminal_id: termId,
|
|
82
|
+
correlation_id: corrId,
|
|
83
|
+
grace_ms: graceMs,
|
|
84
|
+
detected_at: new Date().toISOString(),
|
|
85
|
+
});
|
|
86
|
+
} catch (e) {
|
|
87
|
+
process.stderr.write(`monitor-arm-watch: exit 2 | reason=socket-error:${e.message} | corr=${corrId}\n`);
|
|
88
|
+
process.exit(2);
|
|
89
|
+
}
|
|
90
|
+
process.stderr.write(`monitor-arm-watch: exit 1 | reason=unarmed-published | corr=${corrId}\n`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
process.stderr.write(`monitor-arm-watch: exit 2 | reason=pgrep-unexpected-status:${pg.status} | corr=${corrId}\n`);
|
|
95
|
+
process.exit(2);
|
|
96
|
+
})();
|
|
97
|
+
|
|
98
|
+
function publishUnarmed(sockPath, payload) {
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
const sock = net.createConnection(sockPath);
|
|
101
|
+
let buf = '';
|
|
102
|
+
let state = 'hello'; // 'hello' → 'publish' → done
|
|
103
|
+
let done = false;
|
|
104
|
+
|
|
105
|
+
const finish = (err) => {
|
|
106
|
+
if (done) return;
|
|
107
|
+
done = true;
|
|
108
|
+
clearTimeout(timer);
|
|
109
|
+
try { sock.destroy(); } catch {}
|
|
110
|
+
if (err) reject(err);
|
|
111
|
+
else resolve();
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const timer = setTimeout(() => finish(new Error('socket timeout')), 5000);
|
|
115
|
+
|
|
116
|
+
const send = (obj) => {
|
|
117
|
+
const id = Math.random().toString(36).slice(2);
|
|
118
|
+
try { sock.write(JSON.stringify({ id, ...obj }) + '\n'); } catch (e) { finish(e); }
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
sock.on('connect', () => {
|
|
122
|
+
send({ cmd: 'hello', protocol: 'claws/2', peerName: 'monitor-arm-watch', role: 'observer' });
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
sock.on('data', (chunk) => {
|
|
126
|
+
buf += chunk.toString('utf8');
|
|
127
|
+
let nl;
|
|
128
|
+
while ((nl = buf.indexOf('\n')) !== -1) {
|
|
129
|
+
const line = buf.slice(0, nl).trim();
|
|
130
|
+
buf = buf.slice(nl + 1);
|
|
131
|
+
if (!line) continue;
|
|
132
|
+
try { JSON.parse(line); } catch { continue; }
|
|
133
|
+
if (state === 'hello') {
|
|
134
|
+
state = 'publish';
|
|
135
|
+
send({
|
|
136
|
+
cmd: 'publish', protocol: 'claws/2',
|
|
137
|
+
topic: 'system.monitor.unarmed',
|
|
138
|
+
payload,
|
|
139
|
+
});
|
|
140
|
+
} else if (state === 'publish') {
|
|
141
|
+
finish(null);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
sock.on('error', (e) => finish(e));
|
|
147
|
+
sock.on('close', () => {
|
|
148
|
+
if (!done) finish(new Error('connection closed before publish ack'));
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function sleep(ms) {
|
|
154
|
+
return new Promise(r => setTimeout(r, ms));
|
|
155
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claws — force-rebuild node-pty against VS Code's Electron ABI
|
|
3
|
+
#
|
|
4
|
+
# Run when the extension keeps saying "[claws] running in pipe-mode
|
|
5
|
+
# (node-pty unavailable)" and /claws-update didn't fix it. This script is
|
|
6
|
+
# deliberately independent of /claws-update / /claws-fix — pure bash, shows
|
|
7
|
+
# every step, so you (and I) can see exactly where things go wrong.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# # From repo clone:
|
|
11
|
+
# bash ~/.claws-src/scripts/rebuild-node-pty.sh
|
|
12
|
+
#
|
|
13
|
+
# # Direct from GitHub (no clone needed):
|
|
14
|
+
# bash <(curl -fsSL https://raw.githubusercontent.com/neunaha/claws/main/scripts/rebuild-node-pty.sh)
|
|
15
|
+
#
|
|
16
|
+
# Env overrides:
|
|
17
|
+
# CLAWS_DIR=/path Override ~/.claws-src location
|
|
18
|
+
# ELECTRON_VERSION=X.Y.Z Force a specific Electron target (otherwise auto-detected)
|
|
19
|
+
|
|
20
|
+
# Deliberately NOT using `set -e` — we want to continue past individual
|
|
21
|
+
# step failures so the user sees the full diagnostic.
|
|
22
|
+
|
|
23
|
+
INSTALL_DIR="${CLAWS_DIR:-$HOME/.claws-src}"
|
|
24
|
+
C_RESET=$'\033[0m'; C_BOLD=$'\033[1m'
|
|
25
|
+
C_GREEN=$'\033[0;32m'; C_YELLOW=$'\033[0;33m'; C_RED=$'\033[0;31m'; C_BLUE=$'\033[0;34m'; C_DIM=$'\033[2m'
|
|
26
|
+
|
|
27
|
+
h1() { printf "\n${C_BOLD}${C_BLUE}═══ %s ═══${C_RESET}\n" "$*"; }
|
|
28
|
+
ok() { printf " ${C_GREEN}✓${C_RESET} %s\n" "$*"; }
|
|
29
|
+
warn() { printf " ${C_YELLOW}!${C_RESET} %s\n" "$*"; }
|
|
30
|
+
bad() { printf " ${C_RED}✗${C_RESET} %s\n" "$*"; }
|
|
31
|
+
info() { printf " ${C_DIM}%s${C_RESET}\n" "$*"; }
|
|
32
|
+
|
|
33
|
+
# ─── 0. Pre-flight ─────────────────────────────────────────────────────────
|
|
34
|
+
h1 "Pre-flight"
|
|
35
|
+
info "PLATFORM: $(uname -s) $(uname -r) $(uname -m)"
|
|
36
|
+
info "node: $(command -v node 2>/dev/null) $(node --version 2>/dev/null)"
|
|
37
|
+
info "npm: $(command -v npm 2>/dev/null) $(npm --version 2>/dev/null)"
|
|
38
|
+
info "npx: $(command -v npx 2>/dev/null)"
|
|
39
|
+
if [ "$(uname -s)" = "Darwin" ]; then
|
|
40
|
+
if xcode-select -p &>/dev/null; then
|
|
41
|
+
ok "Xcode CLT at $(xcode-select -p)"
|
|
42
|
+
else
|
|
43
|
+
bad "Xcode Command Line Tools NOT installed"
|
|
44
|
+
warn "without them node-pty cannot compile. Install with:"
|
|
45
|
+
echo " xcode-select --install"
|
|
46
|
+
echo " then re-run this script."
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
if [ ! -d "$INSTALL_DIR/extension" ]; then
|
|
52
|
+
bad "Claws source not found at $INSTALL_DIR/extension"
|
|
53
|
+
warn "install Claws first: bash <(curl -fsSL https://raw.githubusercontent.com/neunaha/claws/main/scripts/install.sh)"
|
|
54
|
+
exit 1
|
|
55
|
+
fi
|
|
56
|
+
ok "source clone at $INSTALL_DIR"
|
|
57
|
+
|
|
58
|
+
NPTY_DIR="$INSTALL_DIR/extension/node_modules/node-pty"
|
|
59
|
+
NPTY_BIN="$NPTY_DIR/build/Release/pty.node"
|
|
60
|
+
ABI_FILE="$INSTALL_DIR/extension/dist/.electron-abi"
|
|
61
|
+
|
|
62
|
+
# ─── 1. Detect VS Code's Electron version ──────────────────────────────────
|
|
63
|
+
h1 "Detect VS Code Electron version"
|
|
64
|
+
if [ -n "$ELECTRON_VERSION" ]; then
|
|
65
|
+
info "ELECTRON_VERSION env override: $ELECTRON_VERSION"
|
|
66
|
+
elif [ "$(uname -s)" = "Darwin" ]; then
|
|
67
|
+
# M-36: TERM_PROGRAM-aware ordering + CURSOR_CHANNEL secondary signal.
|
|
68
|
+
_rn_tp="${TERM_PROGRAM:-}"
|
|
69
|
+
[ "$_rn_tp" = "vscode" ] && [ -n "${CURSOR_CHANNEL:-}" ] && _rn_tp="cursor"
|
|
70
|
+
_rn_tp=$(echo "$_rn_tp" | tr '[:upper:]' '[:lower:]')
|
|
71
|
+
case "$_rn_tp" in
|
|
72
|
+
cursor) _rn_darwin_apps=('/Applications/Cursor.app' '/Applications/Visual Studio Code.app' '/Applications/Visual Studio Code - Insiders.app' '/Applications/Windsurf.app') ;;
|
|
73
|
+
windsurf) _rn_darwin_apps=('/Applications/Windsurf.app' '/Applications/Visual Studio Code.app' '/Applications/Visual Studio Code - Insiders.app' '/Applications/Cursor.app') ;;
|
|
74
|
+
*) _rn_darwin_apps=('/Applications/Visual Studio Code.app' '/Applications/Visual Studio Code - Insiders.app' '/Applications/Cursor.app' '/Applications/Windsurf.app') ;;
|
|
75
|
+
esac
|
|
76
|
+
for _rn_app in "${_rn_darwin_apps[@]}"; do
|
|
77
|
+
plist="$_rn_app/Contents/Frameworks/Electron Framework.framework/Resources/Info.plist"
|
|
78
|
+
if [ -f "$plist" ]; then
|
|
79
|
+
v=$(plutil -extract CFBundleVersion raw "$plist" 2>/dev/null || true)
|
|
80
|
+
if [ -n "$v" ]; then
|
|
81
|
+
ELECTRON_VERSION="$v"
|
|
82
|
+
ok "$(basename "$_rn_app") uses Electron $v"
|
|
83
|
+
break
|
|
84
|
+
fi
|
|
85
|
+
else
|
|
86
|
+
info "$(basename "$_rn_app"): not installed"
|
|
87
|
+
fi
|
|
88
|
+
done
|
|
89
|
+
elif [ "$(uname -s)" = "Linux" ]; then
|
|
90
|
+
# M-36: Linux Cursor/Windsurf paths + TERM_PROGRAM ordering.
|
|
91
|
+
_rn_tp="${TERM_PROGRAM:-}"
|
|
92
|
+
[ "$_rn_tp" = "vscode" ] && [ -n "${CURSOR_CHANNEL:-}" ] && _rn_tp="cursor"
|
|
93
|
+
_rn_tp=$(echo "$_rn_tp" | tr '[:upper:]' '[:lower:]')
|
|
94
|
+
_rn_linux_vscode=('/usr/share/code/electron' '/usr/lib/code/electron' '/opt/visual-studio-code/electron' '/snap/code/current/electron')
|
|
95
|
+
_rn_linux_cursor=('/usr/share/cursor/electron' '/opt/cursor/electron' '/snap/cursor/current/usr/share/cursor/electron')
|
|
96
|
+
_rn_linux_windsurf=('/usr/share/windsurf/electron' '/opt/windsurf/electron')
|
|
97
|
+
_rn_linux_candidates=()
|
|
98
|
+
case "$_rn_tp" in
|
|
99
|
+
cursor) _rn_linux_candidates=("${_rn_linux_cursor[@]}" "${_rn_linux_vscode[@]}" "${_rn_linux_windsurf[@]}") ;;
|
|
100
|
+
windsurf) _rn_linux_candidates=("${_rn_linux_windsurf[@]}" "${_rn_linux_vscode[@]}" "${_rn_linux_cursor[@]}") ;;
|
|
101
|
+
*) _rn_linux_candidates=("${_rn_linux_vscode[@]}" "${_rn_linux_cursor[@]}" "${_rn_linux_windsurf[@]}") ;;
|
|
102
|
+
esac
|
|
103
|
+
for _rn_ep in "${_rn_linux_candidates[@]}"; do
|
|
104
|
+
if [ -x "$_rn_ep" ]; then
|
|
105
|
+
v=$("$_rn_ep" --version 2>/dev/null | sed 's/^v//' || true)
|
|
106
|
+
if echo "$v" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
|
|
107
|
+
ELECTRON_VERSION="$v"
|
|
108
|
+
ok "detected Electron $v from $_rn_ep"
|
|
109
|
+
break
|
|
110
|
+
fi
|
|
111
|
+
fi
|
|
112
|
+
done
|
|
113
|
+
fi
|
|
114
|
+
if [ -z "$ELECTRON_VERSION" ]; then
|
|
115
|
+
ELECTRON_VERSION="39.8.5"
|
|
116
|
+
warn "couldn't auto-detect — using fallback $ELECTRON_VERSION"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# ─── 2. Current binary state ───────────────────────────────────────────────
|
|
120
|
+
h1 "Current node-pty state"
|
|
121
|
+
if [ -d "$NPTY_DIR" ]; then
|
|
122
|
+
ok "node-pty package installed at $NPTY_DIR"
|
|
123
|
+
pkg_ver=$(node -p "require('$NPTY_DIR/package.json').version" 2>/dev/null)
|
|
124
|
+
info "node-pty version: $pkg_ver"
|
|
125
|
+
else
|
|
126
|
+
warn "node-pty not installed — running npm install first"
|
|
127
|
+
( cd "$INSTALL_DIR/extension" && npm install --no-audit --no-fund --loglevel=error 2>&1 | tail -5 )
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [ -f "$NPTY_BIN" ]; then
|
|
131
|
+
size=$(wc -c < "$NPTY_BIN" | tr -d ' ')
|
|
132
|
+
mtime=$(stat -f '%Sm' "$NPTY_BIN" 2>/dev/null || stat -c '%y' "$NPTY_BIN" 2>/dev/null)
|
|
133
|
+
info "binary exists: $size bytes, mtime $mtime"
|
|
134
|
+
else
|
|
135
|
+
warn "binary NOT present at $NPTY_BIN"
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
if [ -f "$ABI_FILE" ]; then
|
|
139
|
+
last_abi=$(cat "$ABI_FILE")
|
|
140
|
+
info "last-built ABI: Electron $last_abi"
|
|
141
|
+
if [ "$last_abi" = "$ELECTRON_VERSION" ]; then
|
|
142
|
+
ok "recorded ABI matches current Electron"
|
|
143
|
+
else
|
|
144
|
+
warn "recorded ABI '$last_abi' ≠ current Electron '$ELECTRON_VERSION' — rebuild needed"
|
|
145
|
+
fi
|
|
146
|
+
else
|
|
147
|
+
warn "no ABI marker — treating as stale"
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# ─── 3. Force-rebuild with @electron/rebuild ───────────────────────────────
|
|
151
|
+
h1 "Rebuilding node-pty for Electron $ELECTRON_VERSION"
|
|
152
|
+
info "removing old binary + ABI marker to force a clean rebuild"
|
|
153
|
+
rm -f "$NPTY_BIN" "$ABI_FILE" 2>/dev/null
|
|
154
|
+
|
|
155
|
+
info "running: npx --yes @electron/rebuild --version=$ELECTRON_VERSION --only=node-pty --force"
|
|
156
|
+
# M-36: 5-minute timeout ceiling — prevents indefinite hang on slow Electron header fetch.
|
|
157
|
+
_rn_timeout_cmd=""
|
|
158
|
+
if command -v timeout >/dev/null 2>&1; then _rn_timeout_cmd="timeout 300"
|
|
159
|
+
elif command -v gtimeout >/dev/null 2>&1; then _rn_timeout_cmd="gtimeout 300"
|
|
160
|
+
fi
|
|
161
|
+
rebuild_log=$(mktemp -t claws-rebuild.XXXXXX.log)
|
|
162
|
+
if ( cd "$INSTALL_DIR/extension" && $_rn_timeout_cmd npx --yes @electron/rebuild --version="$ELECTRON_VERSION" --only=node-pty --force ) >"$rebuild_log" 2>&1; then
|
|
163
|
+
ok "@electron/rebuild completed"
|
|
164
|
+
info "log: $rebuild_log (last 5 lines below)"
|
|
165
|
+
tail -5 "$rebuild_log" | sed 's/^/ /'
|
|
166
|
+
else
|
|
167
|
+
_rn_rc=$?
|
|
168
|
+
if [ "$_rn_rc" = "124" ]; then
|
|
169
|
+
bad "@electron/rebuild timed out after 5 min — likely a slow Electron headers download. Check network / proxy settings."
|
|
170
|
+
else
|
|
171
|
+
bad "@electron/rebuild FAILED"
|
|
172
|
+
fi
|
|
173
|
+
info "full log: $rebuild_log"
|
|
174
|
+
info "last 20 lines:"
|
|
175
|
+
tail -20 "$rebuild_log" | sed 's/^/ /'
|
|
176
|
+
echo ""
|
|
177
|
+
bad "cannot proceed — node-pty will not work until the build succeeds"
|
|
178
|
+
exit 1
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
# ─── 4. Verify the new binary ──────────────────────────────────────────────
|
|
182
|
+
h1 "Verify new binary"
|
|
183
|
+
if [ ! -f "$NPTY_BIN" ]; then
|
|
184
|
+
bad "rebuild reported success but $NPTY_BIN is still missing"
|
|
185
|
+
exit 1
|
|
186
|
+
fi
|
|
187
|
+
new_size=$(wc -c < "$NPTY_BIN" | tr -d ' ')
|
|
188
|
+
new_mtime=$(stat -f '%Sm' "$NPTY_BIN" 2>/dev/null || stat -c '%y' "$NPTY_BIN" 2>/dev/null)
|
|
189
|
+
ok "binary: $NPTY_BIN ($new_size bytes, mtime $new_mtime)"
|
|
190
|
+
|
|
191
|
+
echo "$ELECTRON_VERSION" > "$ABI_FILE"
|
|
192
|
+
ok "recorded Electron ABI → $ABI_FILE"
|
|
193
|
+
|
|
194
|
+
# ─── 5. ABI sanity check ───────────────────────────────────────────────────
|
|
195
|
+
# We can't fully simulate Electron's Node from a plain shell. But we can
|
|
196
|
+
# detect the NODE_MODULE_VERSION embedded in the .node binary by looking at
|
|
197
|
+
# raw bytes. Matching ABIs:
|
|
198
|
+
# Node 22 (Electron 39) → NODE_MODULE_VERSION=127
|
|
199
|
+
# Node 24 (system) → NODE_MODULE_VERSION=131
|
|
200
|
+
h1 "ABI sanity check"
|
|
201
|
+
info "system node would load the binary as:"
|
|
202
|
+
sys_load=$(node -e "try{require('$NPTY_BIN');console.log('LOADS IN SYSTEM NODE')}catch(e){console.log('FAILS IN SYSTEM NODE:',e.message.split('\\n')[0])}" 2>&1)
|
|
203
|
+
info " $sys_load"
|
|
204
|
+
|
|
205
|
+
if echo "$sys_load" | grep -q "FAILS IN SYSTEM NODE.*NODE_MODULE_VERSION"; then
|
|
206
|
+
ok "binary REJECTED by system Node — this is the GOOD sign"
|
|
207
|
+
info " it means the binary's ABI doesn't match system Node 24,"
|
|
208
|
+
info " which is exactly what we want for Electron 39 (Node 22)"
|
|
209
|
+
elif echo "$sys_load" | grep -q "LOADS IN SYSTEM NODE"; then
|
|
210
|
+
if [ "$ELECTRON_VERSION" = "39.8.5" ] || echo "$ELECTRON_VERSION" | grep -qE "^(3[0-9]|4[0-9])\."; then
|
|
211
|
+
bad "binary LOADS in system Node — that's WRONG for Electron $ELECTRON_VERSION"
|
|
212
|
+
warn "it means the rebuild actually targeted system Node, not Electron."
|
|
213
|
+
warn "this is the bug that keeps pipe-mode warnings active. Try:"
|
|
214
|
+
echo ""
|
|
215
|
+
echo " cd $INSTALL_DIR/extension"
|
|
216
|
+
echo " rm -rf node_modules/node-pty"
|
|
217
|
+
echo " npm install node-pty"
|
|
218
|
+
echo " npx @electron/rebuild --version=$ELECTRON_VERSION --only=node-pty --force"
|
|
219
|
+
echo ""
|
|
220
|
+
exit 1
|
|
221
|
+
else
|
|
222
|
+
ok "binary loads in system Node (expected for Electron versions that share Node ABI)"
|
|
223
|
+
fi
|
|
224
|
+
else
|
|
225
|
+
warn "couldn't interpret result: $sys_load"
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
# ─── 6. Done ───────────────────────────────────────────────────────────────
|
|
229
|
+
h1 "Next step"
|
|
230
|
+
echo ""
|
|
231
|
+
printf " ${C_BOLD}1. Reload VS Code${C_RESET}\n"
|
|
232
|
+
echo " Cmd+Shift+P → Developer: Reload Window"
|
|
233
|
+
echo ""
|
|
234
|
+
printf " ${C_BOLD}2. Open the Output panel${C_RESET}\n"
|
|
235
|
+
echo " Cmd+Shift+U → dropdown → 'Claws'"
|
|
236
|
+
echo " You should see 'activating (typescript)' with NO pipe-mode warning."
|
|
237
|
+
echo ""
|
|
238
|
+
printf " ${C_BOLD}3. Spawn a wrapped terminal${C_RESET}\n"
|
|
239
|
+
echo " + dropdown → 'Claws Wrapped Terminal'"
|
|
240
|
+
echo " Should open cleanly, no '[claws] running in pipe-mode' line."
|
|
241
|
+
echo ""
|
|
242
|
+
printf " ${C_BOLD}If it still shows pipe-mode after reload:${C_RESET}\n"
|
|
243
|
+
echo " bash $INSTALL_DIR/scripts/report.sh \"\$(pwd)\""
|
|
244
|
+
echo " and share the generated ~/claws-report-*.txt"
|
|
245
|
+
echo ""
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Claws — diagnostic bundle generator
|
|
3
|
+
# Usage: bash ~/.claws-src/scripts/report.sh [project-dir]
|
|
4
|
+
#
|
|
5
|
+
# Produces a single file with everything needed to diagnose install/runtime
|
|
6
|
+
# issues: OS info, Node version, install log, extension state, VS Code
|
|
7
|
+
# extension logs, project-local file presence. The output file path is
|
|
8
|
+
# printed at the end — share it in a GitHub issue.
|
|
9
|
+
|
|
10
|
+
set -eo pipefail
|
|
11
|
+
|
|
12
|
+
PROJECT_ROOT="${1:-$(pwd)}"
|
|
13
|
+
INSTALL_DIR="${CLAWS_DIR:-$HOME/.claws-src}"
|
|
14
|
+
REPORT_DIR="${CLAWS_REPORT_DIR:-$HOME}"
|
|
15
|
+
REPORT="$REPORT_DIR/claws-report-$(date +%Y%m%d-%H%M%S).txt"
|
|
16
|
+
|
|
17
|
+
redact() {
|
|
18
|
+
# Replace the user's home path with $HOME to reduce leaked info in pastes.
|
|
19
|
+
# Also strip anything that looks like a token/key.
|
|
20
|
+
sed -e "s|$HOME|\$HOME|g" \
|
|
21
|
+
-e 's|[A-Za-z0-9]\{32,\}|<redacted>|g'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
say() { echo "$@" >> "$REPORT"; }
|
|
25
|
+
section() { echo "" >> "$REPORT"; echo "═════ $1 ═════" >> "$REPORT"; }
|
|
26
|
+
|
|
27
|
+
{
|
|
28
|
+
echo "Claws Diagnostic Report"
|
|
29
|
+
echo "Generated: $(date)"
|
|
30
|
+
echo "Project: $PROJECT_ROOT"
|
|
31
|
+
echo "Install: $INSTALL_DIR"
|
|
32
|
+
} > "$REPORT"
|
|
33
|
+
|
|
34
|
+
section "System dependencies"
|
|
35
|
+
PLATFORM="$(uname -s)"
|
|
36
|
+
say "OS: $(uname -a)"
|
|
37
|
+
say "Shell: $SHELL ($(basename "$SHELL"))"
|
|
38
|
+
say "bash: $BASH_VERSION"
|
|
39
|
+
say ""
|
|
40
|
+
say "git: $(command -v git 2>/dev/null || echo '—') $(git --version 2>/dev/null || echo 'NOT INSTALLED')"
|
|
41
|
+
say "node: $(command -v node 2>/dev/null || echo '—') $(node --version 2>/dev/null || echo 'NOT INSTALLED')"
|
|
42
|
+
if command -v node &>/dev/null; then
|
|
43
|
+
nm=$(node -e "console.log(process.versions.node.split('.')[0])" 2>/dev/null)
|
|
44
|
+
say "node major: $nm$([ "$nm" -lt 18 ] 2>/dev/null && echo ' (TOO OLD — requires 18+)')"
|
|
45
|
+
fi
|
|
46
|
+
say "npm: $(command -v npm 2>/dev/null || echo '—') $(npm --version 2>/dev/null || echo 'NOT INSTALLED')"
|
|
47
|
+
say "python3: $(command -v python3 2>/dev/null || echo '—') $(python3 --version 2>&1 | awk '{print $2}' || echo 'NOT INSTALLED')"
|
|
48
|
+
say "npx: $(command -v npx 2>/dev/null || echo '—')"
|
|
49
|
+
case "$PLATFORM" in
|
|
50
|
+
Darwin)
|
|
51
|
+
say "xcode-select: $(xcode-select -p 2>/dev/null || echo 'NOT INSTALLED')"
|
|
52
|
+
;;
|
|
53
|
+
Linux)
|
|
54
|
+
say "g++: $(command -v g++ 2>/dev/null || echo '—') $(g++ -dumpversion 2>/dev/null || echo '')"
|
|
55
|
+
say "make: $(command -v make 2>/dev/null || echo '—')"
|
|
56
|
+
;;
|
|
57
|
+
esac
|
|
58
|
+
|
|
59
|
+
section "Editor CLIs"
|
|
60
|
+
for pair in \
|
|
61
|
+
"code:/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" \
|
|
62
|
+
"code-insiders:/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code-insiders" \
|
|
63
|
+
"cursor:/Applications/Cursor.app/Contents/Resources/app/bin/cursor" \
|
|
64
|
+
"windsurf:/Applications/Windsurf.app/Contents/Resources/app/bin/windsurf"; do
|
|
65
|
+
label="${pair%%:*}"
|
|
66
|
+
bundled="${pair#*:}"
|
|
67
|
+
if command -v "$label" &>/dev/null; then
|
|
68
|
+
say " ✓ $label ($(command -v "$label")) — $("$label" --version 2>&1 | head -1)"
|
|
69
|
+
elif [ -x "$bundled" ]; then
|
|
70
|
+
say " ✓ $label (bundled: $bundled) — $("$bundled" --version 2>&1 | head -1)"
|
|
71
|
+
else
|
|
72
|
+
say " — $label not found"
|
|
73
|
+
fi
|
|
74
|
+
done
|
|
75
|
+
|
|
76
|
+
section "Claws source clone"
|
|
77
|
+
if [ -d "$INSTALL_DIR/.git" ]; then
|
|
78
|
+
say "Exists: $INSTALL_DIR"
|
|
79
|
+
say "HEAD: $(cd "$INSTALL_DIR" && git log --oneline -1 2>/dev/null)"
|
|
80
|
+
say "Branch: $(cd "$INSTALL_DIR" && git rev-parse --abbrev-ref HEAD 2>/dev/null)"
|
|
81
|
+
say "Remote: $(cd "$INSTALL_DIR" && git config --get remote.origin.url 2>/dev/null)"
|
|
82
|
+
else
|
|
83
|
+
say "MISSING: $INSTALL_DIR (no git clone — installer may have failed at step 1)"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
section "Extension manifest + bundle"
|
|
87
|
+
if [ -f "$INSTALL_DIR/extension/package.json" ]; then
|
|
88
|
+
say "Version: $(node -e "console.log(require('$INSTALL_DIR/extension/package.json').version)" 2>/dev/null)"
|
|
89
|
+
say "Main: $(node -e "console.log(require('$INSTALL_DIR/extension/package.json').main)" 2>/dev/null)"
|
|
90
|
+
say "Bundle: $([ -f "$INSTALL_DIR/extension/dist/extension.js" ] && wc -c < "$INSTALL_DIR/extension/dist/extension.js" | tr -d ' ' || echo 'MISSING')"
|
|
91
|
+
say "Build SHA: $(cat "$INSTALL_DIR/extension/dist/.build-sha" 2>/dev/null || echo 'unknown')"
|
|
92
|
+
|
|
93
|
+
# Detailed node-pty state: installed? binary built? against which ABI?
|
|
94
|
+
# The Electron version matters — a binary built against system Node
|
|
95
|
+
# loads from `node` fine but fails inside VS Code's extension host.
|
|
96
|
+
NPTY_DIR="$INSTALL_DIR/extension/node_modules/node-pty"
|
|
97
|
+
NPTY_BIN="$NPTY_DIR/build/Release/pty.node"
|
|
98
|
+
NPTY_ABI=$(cat "$INSTALL_DIR/extension/dist/.electron-abi" 2>/dev/null || echo "unknown")
|
|
99
|
+
if [ -f "$NPTY_BIN" ]; then
|
|
100
|
+
say "node-pty: ✓ installed, binary present ($(wc -c < "$NPTY_BIN" | tr -d ' ') bytes)"
|
|
101
|
+
say " built for Electron $NPTY_ABI"
|
|
102
|
+
elif [ -d "$NPTY_DIR" ]; then
|
|
103
|
+
say "node-pty: ✗ installed but BINARY MISSING — extension in pipe-mode fallback"
|
|
104
|
+
say " fix with: /claws-fix"
|
|
105
|
+
else
|
|
106
|
+
say "node-pty: ✗ not installed — pipe-mode fallback active"
|
|
107
|
+
fi
|
|
108
|
+
else
|
|
109
|
+
say "MISSING manifest at $INSTALL_DIR/extension/package.json"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
section "Editor extension symlinks"
|
|
113
|
+
for dir in "$HOME/.vscode/extensions" "$HOME/.vscode-insiders/extensions" "$HOME/.cursor/extensions" "$HOME/.windsurf/extensions"; do
|
|
114
|
+
if [ -d "$dir" ]; then
|
|
115
|
+
matches=$(find "$dir" -maxdepth 1 -name 'neunaha.claws-*' 2>/dev/null)
|
|
116
|
+
if [ -n "$matches" ]; then
|
|
117
|
+
echo "$dir:" >> "$REPORT"
|
|
118
|
+
ls -la "$dir" 2>/dev/null | grep 'neunaha.claws' >> "$REPORT" 2>&1 || true
|
|
119
|
+
fi
|
|
120
|
+
fi
|
|
121
|
+
done
|
|
122
|
+
|
|
123
|
+
section "Project-local files"
|
|
124
|
+
for f in .mcp.json .claws-bin/mcp_server.js .claws-bin/shell-hook.sh .vscode/extensions.json CLAUDE.md; do
|
|
125
|
+
if [ -e "$PROJECT_ROOT/$f" ]; then
|
|
126
|
+
say " ✓ $f ($(wc -c < "$PROJECT_ROOT/$f" | tr -d ' ') bytes)"
|
|
127
|
+
else
|
|
128
|
+
say " ✗ $f MISSING"
|
|
129
|
+
fi
|
|
130
|
+
done
|
|
131
|
+
# Confirm neunaha.claws is in the recommendations list specifically
|
|
132
|
+
if [ -f "$PROJECT_ROOT/.vscode/extensions.json" ]; then
|
|
133
|
+
if grep -q "neunaha.claws" "$PROJECT_ROOT/.vscode/extensions.json" 2>/dev/null; then
|
|
134
|
+
say " ✓ .vscode/extensions.json recommends neunaha.claws"
|
|
135
|
+
else
|
|
136
|
+
say " ✗ .vscode/extensions.json MISSING claws recommendation"
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
for d in .claude/commands .claude/rules .claude/skills; do
|
|
140
|
+
if [ -d "$PROJECT_ROOT/$d" ]; then
|
|
141
|
+
count=$(find "$PROJECT_ROOT/$d" -type f 2>/dev/null | wc -l | tr -d ' ')
|
|
142
|
+
say " ✓ $d/ ($count files)"
|
|
143
|
+
else
|
|
144
|
+
say " ✗ $d/ MISSING"
|
|
145
|
+
fi
|
|
146
|
+
done
|
|
147
|
+
|
|
148
|
+
section "Socket state"
|
|
149
|
+
SOCK_PATH="$PROJECT_ROOT/.claws/claws.sock"
|
|
150
|
+
if [ -S "$SOCK_PATH" ]; then
|
|
151
|
+
say "Socket: $SOCK_PATH"
|
|
152
|
+
say "Mtime: $(stat -f '%Sm' "$SOCK_PATH" 2>/dev/null || stat -c '%y' "$SOCK_PATH" 2>/dev/null)"
|
|
153
|
+
if command -v nc &>/dev/null; then
|
|
154
|
+
if echo '{"id":1,"cmd":"list"}' | nc -U "$SOCK_PATH" 2>/dev/null | head -c 200 | grep -q '"ok"'; then
|
|
155
|
+
say "Status: LIVE — extension is listening"
|
|
156
|
+
else
|
|
157
|
+
say "Status: STALE — file exists but no process listening"
|
|
158
|
+
fi
|
|
159
|
+
fi
|
|
160
|
+
else
|
|
161
|
+
say "Socket: NOT PRESENT at $SOCK_PATH (extension not activated in this project yet)"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
section "MCP server handshake test"
|
|
165
|
+
MCP_PATH="$INSTALL_DIR/mcp_server.js"
|
|
166
|
+
[ -f "$PROJECT_ROOT/.claws-bin/mcp_server.js" ] && MCP_PATH="$PROJECT_ROOT/.claws-bin/mcp_server.js"
|
|
167
|
+
if command -v node &>/dev/null && [ -f "$MCP_PATH" ]; then
|
|
168
|
+
say "Testing: $MCP_PATH"
|
|
169
|
+
HANDSHAKE=$(node --no-deprecation -e '
|
|
170
|
+
const { spawn } = require("child_process");
|
|
171
|
+
const mcp = spawn("node", [process.argv[1]], { stdio: ["pipe", "pipe", "ignore"] });
|
|
172
|
+
const req = JSON.stringify({ jsonrpc: "2.0", id: 1, method: "initialize", params: {} });
|
|
173
|
+
const msg = `Content-Length: ${Buffer.byteLength(req)}\r\n\r\n${req}`;
|
|
174
|
+
let buf = "";
|
|
175
|
+
const done = (c, o) => { try { mcp.kill(); } catch {}; process.stdout.write(o); process.exit(c); };
|
|
176
|
+
const timer = setTimeout(() => done(1, "TIMEOUT"), 4000);
|
|
177
|
+
mcp.stdout.on("data", d => { buf += d.toString("utf8"); if (buf.includes("claws")) { clearTimeout(timer); done(0, buf.slice(0, 200)); } });
|
|
178
|
+
mcp.on("error", e => { clearTimeout(timer); done(1, "SPAWN_ERROR: " + e.message); });
|
|
179
|
+
mcp.stdin.write(msg);
|
|
180
|
+
' "$MCP_PATH" 2>&1)
|
|
181
|
+
say "Response: ${HANDSHAKE:0:300}"
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
section "Shell hook state"
|
|
185
|
+
for rc in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile"; do
|
|
186
|
+
if [ -f "$rc" ]; then
|
|
187
|
+
if grep -q "CLAWS terminal hook" "$rc" 2>/dev/null; then
|
|
188
|
+
say " ✓ $(basename "$rc") — hook installed"
|
|
189
|
+
else
|
|
190
|
+
say " ✗ $(basename "$rc") — hook NOT installed"
|
|
191
|
+
fi
|
|
192
|
+
fi
|
|
193
|
+
done
|
|
194
|
+
|
|
195
|
+
section "Latest install log"
|
|
196
|
+
LATEST_LOG=$(ls -t /tmp/claws-install-*.log 2>/dev/null | head -1)
|
|
197
|
+
if [ -n "$LATEST_LOG" ] && [ -f "$LATEST_LOG" ]; then
|
|
198
|
+
say "File: $LATEST_LOG"
|
|
199
|
+
say "Last 100 lines:"
|
|
200
|
+
tail -100 "$LATEST_LOG" | redact >> "$REPORT"
|
|
201
|
+
else
|
|
202
|
+
say "No recent install log found in /tmp/claws-install-*.log"
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
section "VS Code extension host logs (claws only, last 50 matches)"
|
|
206
|
+
LOGDIR=$(ls -dt "$HOME/Library/Application Support/Code/logs/"*/ 2>/dev/null | head -1)
|
|
207
|
+
if [ -n "$LOGDIR" ] && [ -d "$LOGDIR" ]; then
|
|
208
|
+
say "From: $LOGDIR"
|
|
209
|
+
grep -r "claws\|neunaha" "$LOGDIR" 2>/dev/null | tail -50 | redact >> "$REPORT" || say "(no claws references)"
|
|
210
|
+
else
|
|
211
|
+
say "No VS Code logs found at ~/Library/Application Support/Code/logs/"
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
section "Report location"
|
|
215
|
+
echo "" >> "$REPORT"
|
|
216
|
+
echo "Share this file in an issue: https://github.com/neunaha/claws/issues/new" >> "$REPORT"
|
|
217
|
+
echo "File path: $REPORT" >> "$REPORT"
|
|
218
|
+
|
|
219
|
+
# Print to stdout for the caller
|
|
220
|
+
echo ""
|
|
221
|
+
echo "╔════════════════════════════════════════════════════════╗"
|
|
222
|
+
echo "║ Claws diagnostic report written to: ║"
|
|
223
|
+
echo "╚════════════════════════════════════════════════════════╝"
|
|
224
|
+
echo " $REPORT"
|
|
225
|
+
echo ""
|
|
226
|
+
echo "Summary of checks:"
|
|
227
|
+
grep -E '✓|✗|MISSING|STALE|LIVE|Status:' "$REPORT" | head -30 | sed 's/^/ /'
|
|
228
|
+
echo ""
|
|
229
|
+
echo "Next steps:"
|
|
230
|
+
echo " 1. Open the report: cat \"$REPORT\""
|
|
231
|
+
echo " 2. Share it: https://github.com/neunaha/claws/issues/new"
|
|
232
|
+
echo " 3. Or paste contents into a new issue — HOMEDIR already redacted."
|