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.
Files changed (180) hide show
  1. package/.claude/commands/claws-auto.md +90 -0
  2. package/.claude/commands/claws-bin.md +28 -0
  3. package/.claude/commands/claws-cleanup.md +28 -0
  4. package/.claude/commands/claws-do.md +82 -0
  5. package/.claude/commands/claws-fix.md +40 -0
  6. package/.claude/commands/claws-goal.md +111 -0
  7. package/.claude/commands/claws-help.md +54 -0
  8. package/.claude/commands/claws-plan.md +103 -0
  9. package/.claude/commands/claws-report.md +29 -0
  10. package/.claude/commands/claws-status.md +37 -0
  11. package/.claude/commands/claws-update.md +32 -0
  12. package/.claude/commands/claws.md +64 -0
  13. package/.claude/rules/claws-default-behavior.md +76 -0
  14. package/.claude/settings.json +112 -0
  15. package/.claude/settings.local.json +19 -0
  16. package/.claude/skills/claws-auto-engine/SKILL.md +97 -0
  17. package/.claude/skills/claws-goal-tracker/SKILL.md +106 -0
  18. package/.claude/skills/claws-prompt-templates/SKILL.md +203 -0
  19. package/.claude/skills/claws-wave-lead/SKILL.md +126 -0
  20. package/.claude/skills/claws-wave-subworker/SKILL.md +60 -0
  21. package/CHANGELOG.md +1949 -0
  22. package/LICENSE +21 -0
  23. package/README.md +420 -0
  24. package/bin/cli.js +84 -0
  25. package/cli.js +223 -0
  26. package/docs/ARCHITECTURE.md +511 -0
  27. package/docs/event-protocol.md +588 -0
  28. package/docs/features.md +562 -0
  29. package/docs/guide.md +891 -0
  30. package/docs/index.html +716 -0
  31. package/docs/protocol.md +323 -0
  32. package/extension/.vscodeignore +15 -0
  33. package/extension/CHANGELOG.md +1906 -0
  34. package/extension/LICENSE +21 -0
  35. package/extension/README.md +137 -0
  36. package/extension/docs/features.md +424 -0
  37. package/extension/docs/protocol.md +197 -0
  38. package/extension/esbuild.mjs +25 -0
  39. package/extension/icon.png +0 -0
  40. package/extension/native/.metadata.json +10 -0
  41. package/extension/native/node-pty/LICENSE +69 -0
  42. package/extension/native/node-pty/README.md +165 -0
  43. package/extension/native/node-pty/lib/conpty_console_list_agent.js +16 -0
  44. package/extension/native/node-pty/lib/conpty_console_list_agent.js.map +1 -0
  45. package/extension/native/node-pty/lib/eventEmitter2.js +47 -0
  46. package/extension/native/node-pty/lib/eventEmitter2.js.map +1 -0
  47. package/extension/native/node-pty/lib/index.js +52 -0
  48. package/extension/native/node-pty/lib/index.js.map +1 -0
  49. package/extension/native/node-pty/lib/interfaces.js +7 -0
  50. package/extension/native/node-pty/lib/interfaces.js.map +1 -0
  51. package/extension/native/node-pty/lib/shared/conout.js +11 -0
  52. package/extension/native/node-pty/lib/shared/conout.js.map +1 -0
  53. package/extension/native/node-pty/lib/terminal.js +190 -0
  54. package/extension/native/node-pty/lib/terminal.js.map +1 -0
  55. package/extension/native/node-pty/lib/types.js +7 -0
  56. package/extension/native/node-pty/lib/types.js.map +1 -0
  57. package/extension/native/node-pty/lib/unixTerminal.js +346 -0
  58. package/extension/native/node-pty/lib/unixTerminal.js.map +1 -0
  59. package/extension/native/node-pty/lib/utils.js +39 -0
  60. package/extension/native/node-pty/lib/utils.js.map +1 -0
  61. package/extension/native/node-pty/lib/windowsConoutConnection.js +125 -0
  62. package/extension/native/node-pty/lib/windowsConoutConnection.js.map +1 -0
  63. package/extension/native/node-pty/lib/windowsPtyAgent.js +320 -0
  64. package/extension/native/node-pty/lib/windowsPtyAgent.js.map +1 -0
  65. package/extension/native/node-pty/lib/windowsTerminal.js +199 -0
  66. package/extension/native/node-pty/lib/windowsTerminal.js.map +1 -0
  67. package/extension/native/node-pty/lib/worker/conoutSocketWorker.js +22 -0
  68. package/extension/native/node-pty/lib/worker/conoutSocketWorker.js.map +1 -0
  69. package/extension/native/node-pty/package.json +64 -0
  70. package/extension/native/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
  71. package/extension/native/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
  72. package/extension/native/node-pty/prebuilds/darwin-x64/pty.node +0 -0
  73. package/extension/native/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
  74. package/extension/native/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
  75. package/extension/native/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
  76. package/extension/native/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
  77. package/extension/native/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  78. package/extension/native/node-pty/prebuilds/win32-arm64/pty.node +0 -0
  79. package/extension/native/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
  80. package/extension/native/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
  81. package/extension/native/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
  82. package/extension/native/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
  83. package/extension/native/node-pty/prebuilds/win32-x64/conpty.node +0 -0
  84. package/extension/native/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
  85. package/extension/native/node-pty/prebuilds/win32-x64/pty.node +0 -0
  86. package/extension/native/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
  87. package/extension/native/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
  88. package/extension/package-lock.json +605 -0
  89. package/extension/package.json +343 -0
  90. package/extension/scripts/bundle-native.mjs +104 -0
  91. package/extension/scripts/deploy-dev.mjs +60 -0
  92. package/extension/src/ansi-strip.ts +52 -0
  93. package/extension/src/backends/vscode/claws-pty.ts +483 -0
  94. package/extension/src/backends/vscode/status-bar.ts +99 -0
  95. package/extension/src/backends/vscode/vscode-backend.ts +282 -0
  96. package/extension/src/capture-store.ts +125 -0
  97. package/extension/src/event-log.ts +629 -0
  98. package/extension/src/event-schemas.ts +478 -0
  99. package/extension/src/extension.js +492 -0
  100. package/extension/src/extension.ts +873 -0
  101. package/extension/src/lifecycle-engine.ts +60 -0
  102. package/extension/src/lifecycle-rules.ts +171 -0
  103. package/extension/src/lifecycle-store.ts +506 -0
  104. package/extension/src/peer-registry.ts +176 -0
  105. package/extension/src/pipeline-registry.ts +82 -0
  106. package/extension/src/platform.ts +64 -0
  107. package/extension/src/protocol.ts +532 -0
  108. package/extension/src/server-config.ts +98 -0
  109. package/extension/src/server.ts +2210 -0
  110. package/extension/src/task-registry.ts +51 -0
  111. package/extension/src/terminal-backend.ts +211 -0
  112. package/extension/src/terminal-manager.ts +395 -0
  113. package/extension/src/topic-registry.ts +70 -0
  114. package/extension/src/topic-utils.ts +46 -0
  115. package/extension/src/transport.ts +45 -0
  116. package/extension/src/uninstall-cleanup.ts +232 -0
  117. package/extension/src/wave-registry.ts +314 -0
  118. package/extension/src/websocket-transport.ts +153 -0
  119. package/extension/tsconfig.json +23 -0
  120. package/lib/capabilities.js +145 -0
  121. package/lib/dry-run.js +43 -0
  122. package/lib/install.js +1018 -0
  123. package/lib/mcp-setup.js +92 -0
  124. package/lib/platform.js +240 -0
  125. package/lib/preflight.js +152 -0
  126. package/lib/shell-hook.js +343 -0
  127. package/lib/uninstall.js +162 -0
  128. package/lib/verify.js +166 -0
  129. package/mcp_server.js +3529 -0
  130. package/package.json +48 -0
  131. package/rules/claws-default-behavior.md +72 -0
  132. package/scripts/_helpers/atomic-file.mjs +137 -0
  133. package/scripts/_helpers/fix-repair.js +64 -0
  134. package/scripts/_helpers/json-safe.mjs +218 -0
  135. package/scripts/bump-version.sh +84 -0
  136. package/scripts/codegen/gen-docs.mjs +61 -0
  137. package/scripts/codegen/gen-json-schema.mjs +62 -0
  138. package/scripts/codegen/gen-mcp-tools.mjs +358 -0
  139. package/scripts/codegen/gen-types.mjs +172 -0
  140. package/scripts/codegen/index.mjs +42 -0
  141. package/scripts/dev-hooks/check-extension-dirs.js +77 -0
  142. package/scripts/dev-hooks/check-open-claws-terminals.js +70 -0
  143. package/scripts/dev-hooks/check-stale-main.js +55 -0
  144. package/scripts/dev-hooks/check-tag-pushed.js +51 -0
  145. package/scripts/dev-hooks/check-tag-vs-main.js +56 -0
  146. package/scripts/dev-vsix-install.sh +60 -0
  147. package/scripts/fix.sh +702 -0
  148. package/scripts/gen-client-types.mjs +81 -0
  149. package/scripts/git-hooks/pre-commit +31 -0
  150. package/scripts/hooks/lifecycle-state.js +61 -0
  151. package/scripts/hooks/package.json +4 -0
  152. package/scripts/hooks/post-tool-use-claws.js +292 -0
  153. package/scripts/hooks/pre-bash-no-verify-block.js +72 -0
  154. package/scripts/hooks/pre-tool-use-claws.js +206 -0
  155. package/scripts/hooks/session-start-claws.js +97 -0
  156. package/scripts/hooks/stop-claws.js +88 -0
  157. package/scripts/inject-claude-md.js +205 -0
  158. package/scripts/inject-dev-hooks.js +96 -0
  159. package/scripts/inject-global-claude-md.js +140 -0
  160. package/scripts/inject-settings-hooks.js +370 -0
  161. package/scripts/install.ps1 +146 -0
  162. package/scripts/install.sh +1729 -0
  163. package/scripts/monitor-arm-watch.js +155 -0
  164. package/scripts/rebuild-node-pty.sh +245 -0
  165. package/scripts/report.sh +232 -0
  166. package/scripts/shell-hook.fish +164 -0
  167. package/scripts/shell-hook.ps1 +33 -0
  168. package/scripts/shell-hook.sh +232 -0
  169. package/scripts/stream-events.js +399 -0
  170. package/scripts/terminal-wrapper.sh +36 -0
  171. package/scripts/test-enforcement.sh +132 -0
  172. package/scripts/test-install.sh +174 -0
  173. package/scripts/test-installer-parity.sh +135 -0
  174. package/scripts/test-template-enforcement.sh +76 -0
  175. package/scripts/uninstall.sh +143 -0
  176. package/scripts/update.sh +337 -0
  177. package/scripts/verify-release.sh +323 -0
  178. package/scripts/verify-wrapped.sh +194 -0
  179. package/templates/CLAUDE.global.md +135 -0
  180. package/templates/CLAUDE.project.md +37 -0
@@ -0,0 +1,164 @@
1
+ # CLAWS — Terminal Control Bridge
2
+ # Native fish hook — sourced from ~/.config/fish/conf.d/claws.fish
3
+ # No bass dependency. Pure fish syntax.
4
+
5
+ if not status is-interactive
6
+ exit
7
+ end
8
+
9
+ # Avoid showing banner more than once per session
10
+ if set -q CLAWS_BANNER_SHOWN
11
+ # Still define functions even if banner already shown
12
+ else
13
+ set -gx CLAWS_BANNER_SHOWN 1
14
+
15
+ # Detect socket status.
16
+ # Walk up from $PWD — the extension creates the socket at
17
+ # <workspace-root>/.claws/claws.sock, not relative to $PWD.
18
+ set -l sock ""
19
+ if test -n "$CLAWS_SOCKET"
20
+ set sock $CLAWS_SOCKET
21
+ else
22
+ set -l _walk (pwd)
23
+ while test -n "$_walk"; and test "$_walk" != "/"
24
+ if test -S "$_walk/.claws/claws.sock"
25
+ set sock "$_walk/.claws/claws.sock"
26
+ break
27
+ end
28
+ set -l _parent (dirname $_walk)
29
+ if test "$_parent" = "$_walk"
30
+ break
31
+ end
32
+ set _walk $_parent
33
+ end
34
+ end
35
+ set -l claws_status ""
36
+ set -l claws_terms "-"
37
+
38
+ if test -n "$sock"; and test -S $sock
39
+ set claws_status "\033[32m● connected\033[0m"
40
+ set claws_terms (node -e "
41
+ const net=require('net');
42
+ const s=net.createConnection('$sock');
43
+ s.on('connect',()=>s.write(JSON.stringify({id:0,cmd:'list'})+'\n'));
44
+ let b='';
45
+ s.on('data',d=>{b+=d;if(b.includes('\n')){try{process.stdout.write(String(JSON.parse(b.split('\n')[0]).terminals.length))}catch(e){process.stdout.write('?')};s.destroy()}});
46
+ s.on('error',()=>{process.stdout.write('?');s.destroy()});
47
+ setTimeout(()=>{process.stdout.write('?');s.destroy()},2000);
48
+ " 2>/dev/null; or echo "?")
49
+ else
50
+ set claws_status "\033[33m○ socket not found\033[0m"
51
+ end
52
+
53
+ # Detect wrapped
54
+ set -l claws_wrap ""
55
+ if test -n "$CLAWS_WRAPPED" && test "$CLAWS_WRAPPED" = "1"
56
+ set claws_wrap "\033[32m● wrapped\033[0m (pty logged)"
57
+ else
58
+ set claws_wrap "\033[90m○ unwrapped\033[0m"
59
+ end
60
+
61
+ set -l T "\033[38;2;200;90;62m"
62
+ set -l W "\033[1;37m"
63
+ set -l D "\033[90m"
64
+ set -l R "\033[0m"
65
+
66
+ printf "\n"
67
+ printf " $T╔═══════════════════════════════════════════════╗$R\n"
68
+ printf " $T║$R $T║$R\n"
69
+ printf " $T║$R $T ██████╗██╗ █████╗ ██╗ ██╗███████╗$R $T║$R\n"
70
+ printf " $T║$R $T██╔════╝██║ ██╔══██╗██║ ██║██╔════╝$R $T║$R\n"
71
+ printf " $T║$R $T██║ ██║ ███████║██║ █╗ ██║███████╗$R $T║$R\n"
72
+ printf " $T║$R $T██║ ██║ ██╔══██║██║███╗██║╚════██║$R $T║$R\n"
73
+ printf " $T║$R $T╚██████╗███████╗██║ ██║╚███╔███╔╝███████║$R $T║$R\n"
74
+ printf " $T║$R $T ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚══════╝$R $T║$R\n"
75
+ printf " $T║$R $T║$R\n"
76
+ printf " $T║$R ${D}Terminal Control Bridge$R $T║$R\n"
77
+ printf " $T║$R $T║$R\n"
78
+ printf " $T║$R Bridge: $claws_status $T║$R\n"
79
+ printf " $T║$R Terminals: $W$claws_terms$R active $T║$R\n"
80
+ printf " $T║$R This term: $claws_wrap $T║$R\n"
81
+ printf " $T║$R $T║$R\n"
82
+ printf " $T║$R ${D}claws-ls$R list terminals $T║$R\n"
83
+ printf " $T║$R ${D}claws-new$R create wrapped terminal $T║$R\n"
84
+ printf " $T║$R ${D}claws-run$R exec command in terminal $T║$R\n"
85
+ printf " $T║$R ${D}claws-log$R read wrapped terminal log $T║$R\n"
86
+ printf " $T║$R $T║$R\n"
87
+ printf " $T╚═══════════════════════════════════════════════╝$R\n"
88
+ printf "\n"
89
+ end
90
+
91
+ # ── Shell functions ─────────────────────────────────────────────────────────
92
+
93
+ function _claws_find_sock
94
+ if test -n "$CLAWS_SOCKET"
95
+ echo $CLAWS_SOCKET; return
96
+ end
97
+ set -l _w (pwd)
98
+ while test -n "$_w"; and test "$_w" != "/"
99
+ if test -S "$_w/.claws/claws.sock"
100
+ echo "$_w/.claws/claws.sock"; return
101
+ end
102
+ set -l _p (dirname $_w)
103
+ if test "$_p" = "$_w"
104
+ break
105
+ end
106
+ set _w $_p
107
+ end
108
+ echo ".claws/claws.sock"
109
+ end
110
+
111
+ function claws-ls
112
+ set -l sock (_claws_find_sock)
113
+ node -e "
114
+ const net=require('net');
115
+ const s=net.createConnection('$sock');
116
+ s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'list'})+'\n'));
117
+ let b='';
118
+ s.on('data',d=>{b+=d;if(b.includes('\n')){try{const d2=JSON.parse(b.split('\n')[0]);(d2.terminals||[]).forEach(t=>{const w=t.logPath?'WRAPPED':' ';const a=t.active?'*':' ';console.log(a+' '+String(t.id).padStart(3)+' '+String(t.name||'').padEnd(25)+' pid='+t.pid+' ['+w+']')})}catch(e){console.log('error: '+e.message)};s.destroy()}});
119
+ s.on('error',e=>{console.log('error: '+e.message+' — is the Claws extension running?');s.destroy()});
120
+ setTimeout(()=>{console.log('error: timeout');s.destroy()},5000);
121
+ " 2>/dev/null; or echo "error: node not available"
122
+ end
123
+
124
+ function claws-new
125
+ set -l name (test -n "$argv[1]" && echo $argv[1] || echo "claws")
126
+ set -l sock (_claws_find_sock)
127
+ node -e "
128
+ const net=require('net');
129
+ const s=net.createConnection('$sock');
130
+ s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'create',name:'$name',wrapped:true})+'\n'));
131
+ let b='';
132
+ s.on('data',d=>{b+=d;if(b.includes('\n')){try{const r=JSON.parse(b.split('\n')[0]);console.log('created terminal id='+r.id+(r.logPath?' log='+r.logPath:''))}catch(e){console.log('error: '+e.message)};s.destroy()}});
133
+ s.on('error',e=>{console.log('error: '+e.message);s.destroy()});
134
+ setTimeout(()=>{console.log('error: timeout');s.destroy()},5000);
135
+ " 2>/dev/null; or echo "error: node not available"
136
+ end
137
+
138
+ function claws-run
139
+ set -l cmd (string join " " $argv)
140
+ set -l sock (_claws_find_sock)
141
+ node -e "
142
+ const net=require('net');
143
+ const s=net.createConnection('$sock');
144
+ s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'exec',command:'$cmd'})+'\n'));
145
+ let b='';
146
+ s.on('data',d=>{b+=d;if(b.includes('\n')){try{const r=JSON.parse(b.split('\n')[0]);console.log(r.output||'');process.exit(r.exitCode||0)}catch(e){console.log('error: '+e.message)};s.destroy()}});
147
+ s.on('error',e=>{console.log('error: '+e.message);s.destroy()});
148
+ setTimeout(()=>{console.log('error: timeout');s.destroy()},30000);
149
+ " 2>/dev/null; or echo "error: node not available"
150
+ end
151
+
152
+ function claws-log
153
+ set -l id $argv[1]
154
+ set -l sock (_claws_find_sock)
155
+ node -e "
156
+ const net=require('net');
157
+ const s=net.createConnection('$sock');
158
+ s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'readLog',id:'$id',strip:true})+'\n'));
159
+ let b='';
160
+ s.on('data',d=>{b+=d;if(b.includes('\n')){try{const r=JSON.parse(b.split('\n')[0]);process.stdout.write(r.bytes||'')}catch(e){console.log('error: '+e.message)};s.destroy()}});
161
+ s.on('error',e=>{console.log('error: '+e.message);s.destroy()});
162
+ setTimeout(()=>{console.log('error: timeout');s.destroy()},5000);
163
+ " 2>/dev/null; or echo "error: node not available"
164
+ end
@@ -0,0 +1,33 @@
1
+ # CLAWS terminal hook (auto-generated — do not edit)
2
+ # Sourced from $PROFILE on PowerShell startup.
3
+ # Only shows banner when running inside a Claws-wrapped terminal.
4
+ # CLAWS_WRAPPED is set by the VS Code extension (claws-pty.ts) when a real
5
+ # pty session is active; it is never set in ordinary PowerShell sessions.
6
+
7
+ if ($env:CLAWS_WRAPPED -ne '1') { return }
8
+ if ($env:CLAWS_BANNER_SHOWN -eq '1') { return }
9
+ $env:CLAWS_BANNER_SHOWN = '1'
10
+
11
+ # ASCII-only banner — Unicode box chars render as ? in PS 5.1 / legacy CP437 consoles.
12
+ # Matches install.ps1 format.
13
+ Write-Host ""
14
+ Write-Host " +-------------------------------------------+" -ForegroundColor DarkYellow
15
+ Write-Host " | |" -ForegroundColor DarkYellow
16
+ Write-Host " | CLAWS Terminal Control Bridge |" -ForegroundColor DarkYellow
17
+ Write-Host " | |" -ForegroundColor DarkYellow
18
+ Write-Host " +-------------------------------------------+" -ForegroundColor DarkYellow
19
+ Write-Host ""
20
+
21
+ # Wrap / pipe-mode state
22
+ $_wrapState = if ($env:CLAWS_PIPE_MODE -eq '1') {
23
+ "pipe-mode (degraded)"
24
+ } else {
25
+ "wrapped (pty logged)"
26
+ }
27
+ Write-Host (" This term " + $_wrapState)
28
+ if ($env:CLAWS_TERMINAL_ID) {
29
+ Write-Host (" Term ID " + $env:CLAWS_TERMINAL_ID) -ForegroundColor DarkGray
30
+ }
31
+ Write-Host ""
32
+
33
+ Remove-Variable -Name '_wrapState' -ErrorAction SilentlyContinue
@@ -0,0 +1,232 @@
1
+ # ═══════════════════════════════════════════════════════════════
2
+ # CLAWS — Terminal Control Bridge
3
+ # This hook is sourced by .zshrc/.bashrc after install.
4
+ # It displays a startup banner and adds claws shell functions.
5
+ # ═══════════════════════════════════════════════════════════════
6
+
7
+ # Export CLAWS_DIR so slash commands (/claws-fix, /claws-update) can locate scripts
8
+ # without hardcoding ~/.claws-src. Shell-hook.sh lives at $INSTALL_DIR/scripts/,
9
+ # so we walk up one level to get the repo root.
10
+ if [ -z "${CLAWS_DIR:-}" ]; then
11
+ _hook_dir=""
12
+ [ -n "${BASH_SOURCE[0]:-}" ] && _hook_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)"
13
+ [ -z "$_hook_dir" ] && [ -n "${ZSH_SCRIPT:-}" ] && _hook_dir="$(cd "$(dirname "$ZSH_SCRIPT")" 2>/dev/null && pwd -P)"
14
+ if [ -n "$_hook_dir" ]; then
15
+ export CLAWS_DIR="${_hook_dir%/scripts}"
16
+ else
17
+ export CLAWS_DIR="$HOME/.claws-src"
18
+ fi
19
+ unset _hook_dir
20
+ fi
21
+
22
+ # Only show banner in interactive shells
23
+ if [[ $- == *i* ]] && [[ -z "${CLAWS_BANNER_SHOWN:-}" ]]; then
24
+ # NOTE: do NOT export — the flag must scope to the current shell only.
25
+ # Exporting leaks into every child process (including VS Code itself if
26
+ # VS Code was launched from a banner-painted shell), and every terminal
27
+ # VS Code spawns inherits the flag pre-set, suppressing the banner
28
+ # forever in that window. Plain shell variable: child processes start
29
+ # fresh and paint their own banner once.
30
+ CLAWS_BANNER_SHOWN=1
31
+
32
+ # ── Version: CLAWS_VERSION env > nearest package.json from script dir ──
33
+ if [ -n "${CLAWS_VERSION:-}" ]; then
34
+ _CLAWS_VERSION="$CLAWS_VERSION"
35
+ elif command -v node >/dev/null 2>&1; then
36
+ # BASH_SOURCE[0] in bash; ZSH_SCRIPT (zsh 5.3+) in zsh; fallback to common install path
37
+ _csd=""
38
+ [ -n "${BASH_SOURCE[0]:-}" ] && _csd="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)"
39
+ [ -z "$_csd" ] && [ -n "${ZSH_SCRIPT:-}" ] && _csd="$(cd "$(dirname "$ZSH_SCRIPT")" 2>/dev/null && pwd -P)"
40
+ [ -z "$_csd" ] && _csd="$HOME/.claws-src/scripts"
41
+ _CLAWS_VERSION=$(node -e "
42
+ const path=require('path'),fs=require('fs');
43
+ let d=path.resolve('$_csd');
44
+ for(let i=0;i<8&&d&&d!=='/';i++,d=path.dirname(d)){
45
+ try{const v=JSON.parse(fs.readFileSync(path.join(d,'package.json'),'utf8')).version;
46
+ if(v){process.stdout.write(v);process.exit(0)}}catch(e){}
47
+ }
48
+ process.stdout.write('?.?.?');
49
+ " 2>/dev/null || echo "?.?.?")
50
+ unset _csd
51
+ else
52
+ _CLAWS_VERSION="?.?.?"
53
+ fi
54
+
55
+ # ── Socket detection ──
56
+ CLAWS_SOCK="${CLAWS_SOCKET:-}"
57
+ if [ -z "$CLAWS_SOCK" ]; then
58
+ _walk="$PWD"
59
+ while [ -n "$_walk" ] && [ "$_walk" != "/" ]; do
60
+ if [ -S "$_walk/.claws/claws.sock" ]; then
61
+ CLAWS_SOCK="$_walk/.claws/claws.sock"
62
+ break
63
+ fi
64
+ _walk="${_walk%/*}"
65
+ done
66
+ unset _walk
67
+ fi
68
+
69
+ # ── Colors (ANSI-C quoting — expand cleanly in printf) ──
70
+ if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
71
+ _GRN=$'\033[32m'; _AMB=$'\033[33m'
72
+ _ORG=$'\033[38;5;208m'; _BLD=$'\033[1;37m'; _DIM=$'\033[2m'; _RST=$'\033[0m'
73
+ else
74
+ _GRN=''; _AMB=''; _ORG=''; _BLD=''; _DIM=''; _RST=''
75
+ fi
76
+
77
+ # ── Bridge status ──
78
+ if [ -S "${CLAWS_SOCK:-}" ] 2>/dev/null; then
79
+ _bstxt="● connected"
80
+ _bsansi="${_GRN}● connected${_RST}"
81
+ _CLAWS_TERMS=$(node -e "
82
+ const net=require('net');
83
+ const s=net.createConnection('$CLAWS_SOCK');
84
+ let done=false;
85
+ const finish=(out)=>{if(done)return;done=true;process.stdout.write(out);try{s.destroy()}catch(e){};process.exit(0)};
86
+ s.on('connect',()=>s.write(JSON.stringify({id:0,cmd:'list'})+'\n'));
87
+ let b='';
88
+ s.on('data',d=>{b+=d;if(b.includes('\n')){
89
+ try{finish(String(JSON.parse(b.split('\n')[0]).terminals.length))}
90
+ catch(e){finish('?')}}});
91
+ s.on('error',()=>finish('?'));
92
+ setTimeout(()=>finish('?'),2000);
93
+ " 2>/dev/null || echo "?")
94
+ else
95
+ _bstxt="○ socket not found"
96
+ _bsansi="${_AMB}○ socket not found${_RST}"
97
+ _CLAWS_TERMS="-"
98
+ fi
99
+
100
+ # ── Wrap / pipe-mode state ──
101
+ if [ "${CLAWS_WRAPPED:-}" = "1" ]; then
102
+ if [ "${CLAWS_PIPE_MODE:-}" = "1" ]; then
103
+ _wrtxt="◑ pipe-mode (degraded)"
104
+ _wransi="${_AMB}◑ pipe-mode (degraded)${_RST}"
105
+ else
106
+ _wrtxt="● wrapped (pty logged)"
107
+ _wransi="${_GRN}● wrapped (pty logged)${_RST}"
108
+ fi
109
+ else
110
+ _wrtxt="○ unwrapped"
111
+ _wransi="${_DIM}○ unwrapped${_RST}"
112
+ fi
113
+
114
+ # ── Banner — orange CLAWS ASCII, no border ──
115
+ printf "\n"
116
+ printf " ${_ORG} ██████╗██╗ █████╗ ██╗ ██╗███████╗${_RST}\n"
117
+ printf " ${_ORG}██╔════╝██║ ██╔══██╗██║ ██║██╔════╝${_RST}\n"
118
+ printf " ${_ORG}██║ ██║ ███████║██║ █╗ ██║███████╗${_RST}\n"
119
+ printf " ${_ORG}██║ ██║ ██╔══██║██║███╗██║╚════██║${_RST}\n"
120
+ printf " ${_ORG}╚██████╗███████╗██║ ██║╚███╔███╔╝███████║${_RST}\n"
121
+ printf " ${_ORG} ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚══════╝${_RST}\n"
122
+ printf "\n"
123
+ printf " ${_DIM}Terminal Control Bridge v%s${_RST}\n" "$_CLAWS_VERSION"
124
+ printf "\n"
125
+ printf " %-11s %s\n" "Bridge" "$_bsansi"
126
+ printf " %-11s %s active\n" "Terminals" "$_CLAWS_TERMS"
127
+ printf " %-11s %s\n" "This term" "$_wransi"
128
+ printf "\n"
129
+
130
+ unset _GRN _AMB _ORG _BLD _DIM _RST
131
+ unset _bstxt _bsansi _CLAWS_TERMS _wrtxt _wransi
132
+ unset CLAWS_SOCK _CLAWS_VERSION
133
+ fi
134
+
135
+ # ═══════════════════════════════════════════════════════════════
136
+ # Shell commands — type these in any terminal
137
+ # ═══════════════════════════════════════════════════════════════
138
+
139
+ _claws_find_sock() {
140
+ if [ -n "${CLAWS_SOCKET:-}" ]; then echo "$CLAWS_SOCKET"; return; fi
141
+ local _w="$PWD"
142
+ while [ -n "$_w" ] && [ "$_w" != "/" ]; do
143
+ [ -S "$_w/.claws/claws.sock" ] && { echo "$_w/.claws/claws.sock"; return; }
144
+ _w="${_w%/*}"
145
+ done
146
+ echo ""
147
+ }
148
+
149
+ _claws_require_sock() {
150
+ local _s; _s="$(_claws_find_sock)"
151
+ if [ -z "$_s" ]; then
152
+ echo "claws: no socket found — open a Claws project in VS Code first" >&2
153
+ return 1
154
+ fi
155
+ echo "$_s"
156
+ }
157
+
158
+ claws-ls() {
159
+ local sock; sock="$(_claws_require_sock)" || return 1
160
+ node -e "
161
+ const net=require('net');
162
+ const s=net.createConnection('$sock');
163
+ s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'list'})+'\n'));
164
+ let b='';
165
+ const t=setTimeout(()=>{console.log('error: timeout — is VS Code open with the Claws extension?');s.destroy()},5000);
166
+ s.on('data',d=>{b+=d;if(b.includes('\n')){clearTimeout(t);try{const d2=JSON.parse(b.split('\n')[0]);(d2.terminals||[]).forEach(t=>{const w=t.logPath?'WRAPPED':' ';const a=t.active?'*':' ';console.log(a+' '+String(t.id).padStart(3)+' '+String(t.name||'').padEnd(25)+' pid='+t.pid+' ['+w+']')})}catch(e){console.log('error: '+e.message)};s.destroy()}});
167
+ s.on('error',e=>{clearTimeout(t);console.log('error: '+e.message+' — is the Claws extension running?');s.destroy()});
168
+ " 2>/dev/null || echo "error: node not available"
169
+ }
170
+
171
+ claws-new() {
172
+ local name="${1:-claws}"
173
+ local sock; sock="$(_claws_require_sock)" || return 1
174
+ node -e "
175
+ const net=require('net');
176
+ const s=net.createConnection('$sock');
177
+ s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'create',name:'$name',wrapped:true})+'\n'));
178
+ let b='';
179
+ const t=setTimeout(()=>{console.log('error: timeout');s.destroy()},5000);
180
+ s.on('data',d=>{b+=d;if(b.includes('\n')){clearTimeout(t);try{const d2=JSON.parse(b.split('\n')[0]);if(d2.ok){console.log('created terminal '+d2.id+' — log: '+(d2.logPath||'none'))}else{console.log('error: '+d2.error)}}catch(e){console.log('error: '+e.message)};s.destroy()}});
181
+ s.on('error',e=>{clearTimeout(t);console.log('error: '+e.message);s.destroy()});
182
+ " 2>/dev/null || echo "error: node not available"
183
+ }
184
+
185
+ claws-run() {
186
+ if [ -z "$1" ] || [ -z "$2" ]; then
187
+ echo "usage: claws-run <terminal-id> <command>"
188
+ return 1
189
+ fi
190
+ local id="$1"; shift
191
+ local cmd="$*"
192
+ local sock; sock="$(_claws_require_sock)" || return 1
193
+ # Write command to temp file to avoid shell injection via $cmd interpolation
194
+ local tmpf="/tmp/claws-cmd-$$.txt"
195
+ printf '%s' "$cmd" > "$tmpf"
196
+ node -e "
197
+ const net=require('net'),fs=require('fs'),path=require('path'),crypto=require('crypto');
198
+ const sockPath='$sock',termId='$id',cmdFile='$tmpf';
199
+ const cmd=fs.readFileSync(cmdFile,'utf8');
200
+ try{fs.unlinkSync(cmdFile)}catch(e){}
201
+ const s=net.createConnection(sockPath);
202
+ const eid=crypto.randomBytes(4).toString('hex');
203
+ const base='/tmp/claws-exec';
204
+ try{fs.mkdirSync(base,{recursive:true})}catch(e){}
205
+ const outF=path.join(base,eid+'.out'),doneF=path.join(base,eid+'.done');
206
+ const wrapper='{ '+cmd+'; } > '+outF+' 2>&1; echo \$? > '+doneF;
207
+ s.on('connect',()=>{s.write(JSON.stringify({id:1,cmd:'send',id:termId,text:wrapper})+'\n')});
208
+ let b='';
209
+ s.on('data',d=>{b+=d;if(b.includes('\n')){poll()}});
210
+ function poll(){const deadline=Date.now()+180000;const iv=setInterval(()=>{try{if(fs.existsSync(doneF)){clearInterval(iv);console.log('exit '+fs.readFileSync(doneF,'utf8').trim());try{console.log(fs.readFileSync(outF,'utf8'))}catch(e){};try{fs.unlinkSync(outF)}catch(e){};try{fs.unlinkSync(doneF)}catch(e){};s.destroy()}}catch(e){}if(Date.now()>deadline){clearInterval(iv);console.log('timeout');s.destroy()}},200)}
211
+ s.on('error',e=>{console.log('error: '+e.message);s.destroy()});
212
+ " 2>/dev/null || echo "error: node not available"
213
+ }
214
+
215
+ claws-log() {
216
+ local id="${1:-}"
217
+ local lines="${2:-30}"
218
+ if [ -z "$id" ]; then
219
+ echo "usage: claws-log <terminal-id> [lines]"
220
+ return 1
221
+ fi
222
+ local sock; sock="$(_claws_require_sock)" || return 1
223
+ node -e "
224
+ const net=require('net');
225
+ const s=net.createConnection('$sock');
226
+ s.on('connect',()=>s.write(JSON.stringify({id:1,cmd:'readLog',id:'$id',strip:true})+'\n'));
227
+ let b='';
228
+ const t=setTimeout(()=>{console.log('error: timeout');s.destroy()},10000);
229
+ s.on('data',d=>{b+=d;if(b.includes('\n')){clearTimeout(t);try{const d2=JSON.parse(b.split('\n')[0]);if(d2.ok){const lines=(d2.bytes||'').split('\n');lines.slice(-$lines).forEach(l=>console.log(l));console.log('\n['+(d2.totalSize||0)+' bytes total]')}else{console.log('error: '+d2.error)}}catch(e){console.log('error: '+e.message)};s.destroy()}});
230
+ s.on('error',e=>{clearTimeout(t);console.log('error: '+e.message);s.destroy()});
231
+ " 2>/dev/null || echo "error: node not available"
232
+ }