spidersan 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/LICENSE +21 -0
  3. package/LICENSE.md +85 -0
  4. package/README.md +217 -0
  5. package/dist/bin/spidersan.d.ts +9 -0
  6. package/dist/bin/spidersan.d.ts.map +1 -0
  7. package/dist/bin/spidersan.js +152 -0
  8. package/dist/bin/spidersan.js.map +1 -0
  9. package/dist/commands/abandon.d.ts +8 -0
  10. package/dist/commands/abandon.d.ts.map +1 -0
  11. package/dist/commands/abandon.js +49 -0
  12. package/dist/commands/abandon.js.map +1 -0
  13. package/dist/commands/activate.d.ts +9 -0
  14. package/dist/commands/activate.d.ts.map +1 -0
  15. package/dist/commands/activate.js +45 -0
  16. package/dist/commands/activate.js.map +1 -0
  17. package/dist/commands/active-windows.d.ts +16 -0
  18. package/dist/commands/active-windows.d.ts.map +1 -0
  19. package/dist/commands/active-windows.js +373 -0
  20. package/dist/commands/active-windows.js.map +1 -0
  21. package/dist/commands/audit-mark.d.ts +12 -0
  22. package/dist/commands/audit-mark.d.ts.map +1 -0
  23. package/dist/commands/audit-mark.js +204 -0
  24. package/dist/commands/audit-mark.js.map +1 -0
  25. package/dist/commands/cleanup.d.ts +8 -0
  26. package/dist/commands/cleanup.d.ts.map +1 -0
  27. package/dist/commands/cleanup.js +41 -0
  28. package/dist/commands/cleanup.js.map +1 -0
  29. package/dist/commands/close.d.ts +9 -0
  30. package/dist/commands/close.d.ts.map +1 -0
  31. package/dist/commands/close.js +129 -0
  32. package/dist/commands/close.js.map +1 -0
  33. package/dist/commands/collab-sync.d.ts +14 -0
  34. package/dist/commands/collab-sync.d.ts.map +1 -0
  35. package/dist/commands/collab-sync.js +240 -0
  36. package/dist/commands/collab-sync.js.map +1 -0
  37. package/dist/commands/collab.d.ts +6 -0
  38. package/dist/commands/collab.d.ts.map +1 -0
  39. package/dist/commands/collab.js +103 -0
  40. package/dist/commands/collab.js.map +1 -0
  41. package/dist/commands/completions.d.ts +8 -0
  42. package/dist/commands/completions.d.ts.map +1 -0
  43. package/dist/commands/completions.js +83 -0
  44. package/dist/commands/completions.js.map +1 -0
  45. package/dist/commands/conflicts.d.ts +12 -0
  46. package/dist/commands/conflicts.d.ts.map +1 -0
  47. package/dist/commands/conflicts.js +426 -0
  48. package/dist/commands/conflicts.js.map +1 -0
  49. package/dist/commands/demo.d.ts +3 -0
  50. package/dist/commands/demo.d.ts.map +1 -0
  51. package/dist/commands/demo.js +113 -0
  52. package/dist/commands/demo.js.map +1 -0
  53. package/dist/commands/depends.d.ts +8 -0
  54. package/dist/commands/depends.d.ts.map +1 -0
  55. package/dist/commands/depends.js +44 -0
  56. package/dist/commands/depends.js.map +1 -0
  57. package/dist/commands/doctor.d.ts +8 -0
  58. package/dist/commands/doctor.d.ts.map +1 -0
  59. package/dist/commands/doctor.js +249 -0
  60. package/dist/commands/doctor.js.map +1 -0
  61. package/dist/commands/inbox.d.ts +3 -0
  62. package/dist/commands/inbox.d.ts.map +1 -0
  63. package/dist/commands/inbox.js +66 -0
  64. package/dist/commands/inbox.js.map +1 -0
  65. package/dist/commands/index.d.ts +43 -0
  66. package/dist/commands/index.d.ts.map +1 -0
  67. package/dist/commands/index.js +61 -0
  68. package/dist/commands/index.js.map +1 -0
  69. package/dist/commands/init.d.ts +8 -0
  70. package/dist/commands/init.d.ts.map +1 -0
  71. package/dist/commands/init.js +23 -0
  72. package/dist/commands/init.js.map +1 -0
  73. package/dist/commands/intent-scan.d.ts +17 -0
  74. package/dist/commands/intent-scan.d.ts.map +1 -0
  75. package/dist/commands/intent-scan.js +336 -0
  76. package/dist/commands/intent-scan.js.map +1 -0
  77. package/dist/commands/key-import.d.ts +3 -0
  78. package/dist/commands/key-import.d.ts.map +1 -0
  79. package/dist/commands/key-import.js +54 -0
  80. package/dist/commands/key-import.js.map +1 -0
  81. package/dist/commands/keygen.d.ts +3 -0
  82. package/dist/commands/keygen.d.ts.map +1 -0
  83. package/dist/commands/keygen.js +53 -0
  84. package/dist/commands/keygen.js.map +1 -0
  85. package/dist/commands/keys.d.ts +3 -0
  86. package/dist/commands/keys.d.ts.map +1 -0
  87. package/dist/commands/keys.js +56 -0
  88. package/dist/commands/keys.js.map +1 -0
  89. package/dist/commands/list.d.ts +3 -0
  90. package/dist/commands/list.d.ts.map +1 -0
  91. package/dist/commands/list.js +45 -0
  92. package/dist/commands/list.js.map +1 -0
  93. package/dist/commands/lock.d.ts +11 -0
  94. package/dist/commands/lock.d.ts.map +1 -0
  95. package/dist/commands/lock.js +220 -0
  96. package/dist/commands/lock.js.map +1 -0
  97. package/dist/commands/log.d.ts +8 -0
  98. package/dist/commands/log.d.ts.map +1 -0
  99. package/dist/commands/log.js +95 -0
  100. package/dist/commands/log.js.map +1 -0
  101. package/dist/commands/mcp-health.d.ts +3 -0
  102. package/dist/commands/mcp-health.d.ts.map +1 -0
  103. package/dist/commands/mcp-health.js +305 -0
  104. package/dist/commands/mcp-health.js.map +1 -0
  105. package/dist/commands/mcp-restart.d.ts +3 -0
  106. package/dist/commands/mcp-restart.d.ts.map +1 -0
  107. package/dist/commands/mcp-restart.js +176 -0
  108. package/dist/commands/mcp-restart.js.map +1 -0
  109. package/dist/commands/merge-order.d.ts +9 -0
  110. package/dist/commands/merge-order.d.ts.map +1 -0
  111. package/dist/commands/merge-order.js +138 -0
  112. package/dist/commands/merge-order.js.map +1 -0
  113. package/dist/commands/merged.d.ts +8 -0
  114. package/dist/commands/merged.d.ts.map +1 -0
  115. package/dist/commands/merged.js +39 -0
  116. package/dist/commands/merged.js.map +1 -0
  117. package/dist/commands/msg-read.d.ts +3 -0
  118. package/dist/commands/msg-read.d.ts.map +1 -0
  119. package/dist/commands/msg-read.js +70 -0
  120. package/dist/commands/msg-read.js.map +1 -0
  121. package/dist/commands/pulse.d.ts +9 -0
  122. package/dist/commands/pulse.d.ts.map +1 -0
  123. package/dist/commands/pulse.js +232 -0
  124. package/dist/commands/pulse.js.map +1 -0
  125. package/dist/commands/radar.d.ts +3 -0
  126. package/dist/commands/radar.d.ts.map +1 -0
  127. package/dist/commands/radar.js +147 -0
  128. package/dist/commands/radar.js.map +1 -0
  129. package/dist/commands/ready-check.d.ts +9 -0
  130. package/dist/commands/ready-check.d.ts.map +1 -0
  131. package/dist/commands/ready-check.js +156 -0
  132. package/dist/commands/ready-check.js.map +1 -0
  133. package/dist/commands/register.d.ts +3 -0
  134. package/dist/commands/register.d.ts.map +1 -0
  135. package/dist/commands/register.js +124 -0
  136. package/dist/commands/register.js.map +1 -0
  137. package/dist/commands/send.d.ts +3 -0
  138. package/dist/commands/send.d.ts.map +1 -0
  139. package/dist/commands/send.js +134 -0
  140. package/dist/commands/send.js.map +1 -0
  141. package/dist/commands/stale.d.ts +8 -0
  142. package/dist/commands/stale.d.ts.map +1 -0
  143. package/dist/commands/stale.js +38 -0
  144. package/dist/commands/stale.js.map +1 -0
  145. package/dist/commands/status.d.ts +9 -0
  146. package/dist/commands/status.d.ts.map +1 -0
  147. package/dist/commands/status.js +41 -0
  148. package/dist/commands/status.js.map +1 -0
  149. package/dist/commands/sync-all.d.ts +9 -0
  150. package/dist/commands/sync-all.d.ts.map +1 -0
  151. package/dist/commands/sync-all.js +180 -0
  152. package/dist/commands/sync-all.js.map +1 -0
  153. package/dist/commands/sync.d.ts +8 -0
  154. package/dist/commands/sync.d.ts.map +1 -0
  155. package/dist/commands/sync.js +49 -0
  156. package/dist/commands/sync.js.map +1 -0
  157. package/dist/commands/tension.d.ts +12 -0
  158. package/dist/commands/tension.d.ts.map +1 -0
  159. package/dist/commands/tension.js +242 -0
  160. package/dist/commands/tension.js.map +1 -0
  161. package/dist/commands/torrent.d.ts +9 -0
  162. package/dist/commands/torrent.d.ts.map +1 -0
  163. package/dist/commands/torrent.js +431 -0
  164. package/dist/commands/torrent.js.map +1 -0
  165. package/dist/commands/tui.d.ts +8 -0
  166. package/dist/commands/tui.d.ts.map +1 -0
  167. package/dist/commands/tui.js +15 -0
  168. package/dist/commands/tui.js.map +1 -0
  169. package/dist/commands/wake.d.ts +9 -0
  170. package/dist/commands/wake.d.ts.map +1 -0
  171. package/dist/commands/wake.js +188 -0
  172. package/dist/commands/wake.js.map +1 -0
  173. package/dist/commands/watch.d.ts +3 -0
  174. package/dist/commands/watch.d.ts.map +1 -0
  175. package/dist/commands/watch.js +245 -0
  176. package/dist/commands/watch.js.map +1 -0
  177. package/dist/commands/who-touched.d.ts +9 -0
  178. package/dist/commands/who-touched.d.ts.map +1 -0
  179. package/dist/commands/who-touched.js +186 -0
  180. package/dist/commands/who-touched.js.map +1 -0
  181. package/dist/index.d.ts +6 -0
  182. package/dist/index.d.ts.map +1 -0
  183. package/dist/index.js +6 -0
  184. package/dist/index.js.map +1 -0
  185. package/dist/lib/agent-errors.d.ts +41 -0
  186. package/dist/lib/agent-errors.d.ts.map +1 -0
  187. package/dist/lib/agent-errors.js +143 -0
  188. package/dist/lib/agent-errors.js.map +1 -0
  189. package/dist/lib/ast.d.ts +56 -0
  190. package/dist/lib/ast.d.ts.map +1 -0
  191. package/dist/lib/ast.js +134 -0
  192. package/dist/lib/ast.js.map +1 -0
  193. package/dist/lib/config.d.ts +33 -0
  194. package/dist/lib/config.d.ts.map +1 -0
  195. package/dist/lib/config.js +127 -0
  196. package/dist/lib/config.js.map +1 -0
  197. package/dist/lib/crdt.d.ts +83 -0
  198. package/dist/lib/crdt.d.ts.map +1 -0
  199. package/dist/lib/crdt.js +160 -0
  200. package/dist/lib/crdt.js.map +1 -0
  201. package/dist/lib/crypto.d.ts +71 -0
  202. package/dist/lib/crypto.d.ts.map +1 -0
  203. package/dist/lib/crypto.js +172 -0
  204. package/dist/lib/crypto.js.map +1 -0
  205. package/dist/lib/errors.d.ts +35 -0
  206. package/dist/lib/errors.d.ts.map +1 -0
  207. package/dist/lib/errors.js +71 -0
  208. package/dist/lib/errors.js.map +1 -0
  209. package/dist/lib/license.d.ts +61 -0
  210. package/dist/lib/license.d.ts.map +1 -0
  211. package/dist/lib/license.js +171 -0
  212. package/dist/lib/license.js.map +1 -0
  213. package/dist/lib/security.d.ts +53 -0
  214. package/dist/lib/security.d.ts.map +1 -0
  215. package/dist/lib/security.js +122 -0
  216. package/dist/lib/security.js.map +1 -0
  217. package/dist/lib/update-check.d.ts +11 -0
  218. package/dist/lib/update-check.d.ts.map +1 -0
  219. package/dist/lib/update-check.js +113 -0
  220. package/dist/lib/update-check.js.map +1 -0
  221. package/dist/storage/adapter.d.ts +58 -0
  222. package/dist/storage/adapter.d.ts.map +1 -0
  223. package/dist/storage/adapter.js +8 -0
  224. package/dist/storage/adapter.js.map +1 -0
  225. package/dist/storage/factory.d.ts +6 -0
  226. package/dist/storage/factory.d.ts.map +1 -0
  227. package/dist/storage/factory.js +22 -0
  228. package/dist/storage/factory.js.map +1 -0
  229. package/dist/storage/index.d.ts +5 -0
  230. package/dist/storage/index.d.ts.map +1 -0
  231. package/dist/storage/index.js +5 -0
  232. package/dist/storage/index.js.map +1 -0
  233. package/dist/storage/local.d.ts +24 -0
  234. package/dist/storage/local.d.ts.map +1 -0
  235. package/dist/storage/local.js +101 -0
  236. package/dist/storage/local.js.map +1 -0
  237. package/dist/storage/supabase.d.ts +52 -0
  238. package/dist/storage/supabase.d.ts.map +1 -0
  239. package/dist/storage/supabase.js +221 -0
  240. package/dist/storage/supabase.js.map +1 -0
  241. package/dist/tui/screen.d.ts +14 -0
  242. package/dist/tui/screen.d.ts.map +1 -0
  243. package/dist/tui/screen.js +136 -0
  244. package/dist/tui/screen.js.map +1 -0
  245. package/package.json +89 -0
@@ -0,0 +1,188 @@
1
+ /**
2
+ * spidersan wake
3
+ *
4
+ * Start a session with branch context.
5
+ * "Weaving into the Web" - the spider feels its threads.
6
+ */
7
+ import { Command } from 'commander';
8
+ import { execSync } from 'child_process';
9
+ import { execa } from 'execa';
10
+ import { getStorage } from '../storage/index.js';
11
+ function getCurrentBranch() {
12
+ try {
13
+ return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ function getGitBranches() {
20
+ try {
21
+ const output = execSync('git branch --format="%(refname:short)"', { encoding: 'utf-8' });
22
+ return output.trim().split('\n').filter(Boolean);
23
+ }
24
+ catch {
25
+ return [];
26
+ }
27
+ }
28
+ function hasMycmail() {
29
+ try {
30
+ execSync('which mycmail', { stdio: 'ignore' });
31
+ return true;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ async function getInboxCount() {
38
+ try {
39
+ const result = await execa('mycmail', ['inbox', '--count'], {
40
+ timeout: 10000, // 10 second timeout
41
+ reject: false,
42
+ });
43
+ const match = result.stdout?.match(/(\d+)/);
44
+ return match ? parseInt(match[1], 10) : 0;
45
+ }
46
+ catch {
47
+ return 0;
48
+ }
49
+ }
50
+ export const wakeCommand = new Command('wake')
51
+ .description('Start a session - weave into the web, feel the threads')
52
+ .option('--json', 'Output as JSON')
53
+ .option('-q, --quiet', 'Minimal output')
54
+ .option('--skip-mail', 'Skip mycmail integration')
55
+ .action(async (options) => {
56
+ const storage = await getStorage();
57
+ const currentBranch = getCurrentBranch();
58
+ const result = {
59
+ synced: 0,
60
+ branches: [],
61
+ conflicts: [],
62
+ inboxCount: 0,
63
+ mycmailCalled: false,
64
+ };
65
+ // Step 1: Sync registry with git (remove orphaned branches)
66
+ if (await storage.isInitialized()) {
67
+ const gitBranches = new Set(getGitBranches());
68
+ const registeredBranches = await storage.list();
69
+ for (const branch of registeredBranches) {
70
+ if (!gitBranches.has(branch.name) && branch.status === 'active') {
71
+ await storage.unregister(branch.name);
72
+ result.synced++;
73
+ }
74
+ }
75
+ // Get current branches after sync
76
+ const branches = await storage.list();
77
+ result.branches = branches
78
+ .filter(b => b.status === 'active')
79
+ .map(b => ({ name: b.name, files: b.files, status: b.status, agent: b.agent }));
80
+ // Step 2: Check conflicts for current branch
81
+ if (currentBranch) {
82
+ const target = await storage.get(currentBranch);
83
+ if (target) {
84
+ for (const branch of branches) {
85
+ if (branch.name === currentBranch || branch.status !== 'active')
86
+ continue;
87
+ const overlappingFiles = branch.files.filter(f => target.files.includes(f));
88
+ if (overlappingFiles.length > 0) {
89
+ result.conflicts.push({ branch: branch.name, files: overlappingFiles, agent: branch.agent });
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+ // Step 3: Call mycmail wake (with timeout protection!)
96
+ if (!options.skipMail && hasMycmail()) {
97
+ try {
98
+ await execa('mycmail', ['wake', '--quiet'], {
99
+ timeout: 30000, // 30 second timeout - prevents hanging!
100
+ reject: false, // Don't throw on non-zero exit
101
+ });
102
+ result.mycmailCalled = true;
103
+ result.inboxCount = await getInboxCount();
104
+ }
105
+ catch {
106
+ // Ignore mycmail errors - but we won't hang!
107
+ }
108
+ }
109
+ // JSON output
110
+ if (options.json) {
111
+ console.log(JSON.stringify(result, null, 2));
112
+ return;
113
+ }
114
+ // Quiet output
115
+ if (options.quiet) {
116
+ console.log(`🕷️ Wake: ${result.branches.length} threads, ${result.conflicts.length} tensions`);
117
+ return;
118
+ }
119
+ // ═══════════════════════════════════════════════════════════
120
+ // CEREMONIAL OUTPUT: "Weaving into the Web"
121
+ // ═══════════════════════════════════════════════════════════
122
+ console.log('');
123
+ console.log('🕷️ Spidersan Awakens...');
124
+ console.log('');
125
+ console.log(' ╭─────────────────────────────────────╮');
126
+ console.log(' │ Feeling the threads... │');
127
+ console.log(' ╰─────────────────────────────────────╯');
128
+ console.log('');
129
+ // Web status
130
+ const agentCount = new Set(result.branches.map(b => b.agent).filter(Boolean)).size;
131
+ console.log(' 📡 Web Status:');
132
+ console.log(` • ${result.branches.length} thread${result.branches.length !== 1 ? 's' : ''} active`);
133
+ if (agentCount > 0) {
134
+ console.log(` • ${agentCount} agent${agentCount !== 1 ? 's' : ''} weaving`);
135
+ }
136
+ if (result.synced > 0) {
137
+ console.log(` • ${result.synced} broken thread${result.synced !== 1 ? 's' : ''} cleared`);
138
+ }
139
+ // Tensions (conflicts)
140
+ if (result.conflicts.length > 0) {
141
+ console.log('');
142
+ console.log(` ⚠️ Tension${result.conflicts.length !== 1 ? 's' : ''} detected:`);
143
+ for (const conflict of result.conflicts) {
144
+ const agentInfo = conflict.agent ? ` (${conflict.agent})` : '';
145
+ console.log(` └─ ${conflict.files[0]}${agentInfo}`);
146
+ if (conflict.files.length > 1) {
147
+ console.log(` +${conflict.files.length - 1} more file${conflict.files.length > 2 ? 's' : ''}`);
148
+ }
149
+ }
150
+ }
151
+ // Active threads
152
+ if (result.branches.length > 0) {
153
+ console.log('');
154
+ console.log(' 🕸️ Active Threads:');
155
+ for (const branch of result.branches.slice(0, 4)) {
156
+ const isCurrent = branch.name === currentBranch ? ' ← you' : '';
157
+ const agentInfo = branch.agent && branch.name !== currentBranch ? ` (${branch.agent})` : '';
158
+ console.log(` • ${branch.name}${agentInfo}${isCurrent}`);
159
+ }
160
+ if (result.branches.length > 4) {
161
+ console.log(` • ...and ${result.branches.length - 4} more`);
162
+ }
163
+ }
164
+ // Messages
165
+ if (result.mycmailCalled) {
166
+ console.log('');
167
+ if (result.inboxCount > 0) {
168
+ console.log(` 📬 ${result.inboxCount} message${result.inboxCount !== 1 ? 's' : ''} waiting`);
169
+ }
170
+ else {
171
+ console.log(' 📭 No new messages');
172
+ }
173
+ }
174
+ // Closing
175
+ console.log('');
176
+ if (result.conflicts.length === 0) {
177
+ console.log(' ╭─────────────────────────────────────╮');
178
+ console.log(' │ The web is calm. Ready to hunt. 🎯 │');
179
+ console.log(' ╰─────────────────────────────────────╯');
180
+ }
181
+ else {
182
+ console.log(' ╭─────────────────────────────────────╮');
183
+ console.log(' │ Tensions on the web. Tread softly. │');
184
+ console.log(' ╰─────────────────────────────────────╯');
185
+ }
186
+ console.log('');
187
+ });
188
+ //# sourceMappingURL=wake.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wake.js","sourceRoot":"","sources":["../../src/commands/wake.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const watchCommand: Command;
3
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqEpC,eAAO,MAAM,YAAY,SAuNnB,CAAC"}
@@ -0,0 +1,245 @@
1
+ import { Command } from 'commander';
2
+ import { execSync } from 'child_process';
3
+ import { getStorage } from '../storage/index.js';
4
+ import * as chokidar from 'chokidar';
5
+ import * as path from 'path';
6
+ import { io } from 'socket.io-client';
7
+ // Config
8
+ const HUB_URL = process.env.HUB_URL || 'https://hub.treebird.uk';
9
+ const DEBOUNCE_MS = 1000; // Debounce file changes
10
+ function getCurrentBranch() {
11
+ try {
12
+ return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
13
+ }
14
+ catch {
15
+ throw new Error('Not in a git repository');
16
+ }
17
+ }
18
+ function getRepoRoot() {
19
+ try {
20
+ return execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
21
+ }
22
+ catch {
23
+ return process.cwd();
24
+ }
25
+ }
26
+ // Post conflict warning to Hub chat API
27
+ async function postConflictToChat(branch, agent, conflicts) {
28
+ const conflictDetails = conflicts
29
+ .map(c => `• **${c.branch}**: ${c.files.join(', ')}`)
30
+ .join('\n');
31
+ const message = `🕷️⚠️ **CONFLICT DETECTED** on branch \`${branch}\`\n\n${conflictDetails}`;
32
+ try {
33
+ const response = await fetch(`${HUB_URL}/api/chat`, {
34
+ method: 'POST',
35
+ headers: { 'Content-Type': 'application/json' },
36
+ body: JSON.stringify({
37
+ agent: 'ssan',
38
+ name: 'Spidersan',
39
+ message,
40
+ glyph: '🕷️'
41
+ })
42
+ });
43
+ if (!response.ok) {
44
+ console.log(`⚠️ Failed to post to Hub chat: ${response.status}`);
45
+ }
46
+ }
47
+ catch (err) {
48
+ // Silently fail - Hub might not be running
49
+ }
50
+ }
51
+ export const watchCommand = new Command('watch')
52
+ .description('🕷️ Watch files and auto-register changes (daemon mode)')
53
+ .argument('[directory]', 'Directory to watch (default: current repo)')
54
+ .option('-d, --dir <directory>', 'Directory to watch (alias for positional arg)')
55
+ .option('-a, --agent <agent>', 'Agent identifier for registration')
56
+ .option('--hub', 'Connect to Hub and emit real-time conflict warnings')
57
+ .option('--hub-sync', 'Post conflicts to Hub chat via REST API')
58
+ .option('-q, --quiet', 'Only log conflicts, not file changes')
59
+ .option('--legacy', 'Legacy mode: use old watcher settings (more file descriptors)')
60
+ .action(async (directory, options) => {
61
+ const storage = await getStorage();
62
+ if (!await storage.isInitialized()) {
63
+ console.error('❌ Spidersan not initialized. Run: spidersan init');
64
+ process.exit(1);
65
+ }
66
+ const branch = getCurrentBranch();
67
+ const repoRoot = directory || options.dir || getRepoRoot();
68
+ const agent = options.agent || process.env.SPIDERSAN_AGENT || 'unknown';
69
+ console.log(`
70
+ 🕷️ SPIDERSAN WATCH MODE
71
+ ━━━━━━━━━━━━━━━━━━━━━━━
72
+ Branch: ${branch}
73
+ Agent: ${agent}
74
+ Watching: ${repoRoot}
75
+ Hub: ${options.hub ? HUB_URL : 'disabled'}
76
+ Hub Sync: ${options.hubSync ? 'enabled (posts to chat)' : 'disabled'}
77
+ ━━━━━━━━━━━━━━━━━━━━━━━
78
+ Press Ctrl+C to stop.
79
+ `);
80
+ // Hub socket connection (optional)
81
+ let hubSocket = null;
82
+ if (options.hub) {
83
+ try {
84
+ hubSocket = io(HUB_URL, {
85
+ reconnection: true,
86
+ reconnectionAttempts: 5,
87
+ timeout: 5000
88
+ });
89
+ hubSocket.on('connect', () => {
90
+ console.log('🔌 Connected to Hub');
91
+ });
92
+ hubSocket.on('disconnect', () => {
93
+ console.log('🔌 Disconnected from Hub');
94
+ });
95
+ hubSocket.on('connect_error', (err) => {
96
+ if (!options.quiet) {
97
+ console.log(`⚠️ Hub connection failed: ${err.message}`);
98
+ }
99
+ });
100
+ }
101
+ catch (e) {
102
+ console.log('⚠️ Could not connect to Hub');
103
+ }
104
+ }
105
+ // Track recently changed files for debouncing
106
+ const pendingFiles = new Set();
107
+ let debounceTimer = null;
108
+ // Process accumulated file changes
109
+ async function processChanges() {
110
+ if (pendingFiles.size === 0)
111
+ return;
112
+ const files = Array.from(pendingFiles);
113
+ pendingFiles.clear();
114
+ // Register files
115
+ const existing = await storage.get(branch);
116
+ const allFiles = existing
117
+ ? [...new Set([...existing.files, ...files])]
118
+ : files;
119
+ if (existing) {
120
+ await storage.update(branch, { files: allFiles, agent });
121
+ }
122
+ else {
123
+ await storage.register({
124
+ name: branch,
125
+ files: allFiles,
126
+ status: 'active',
127
+ agent,
128
+ });
129
+ }
130
+ if (!options.quiet) {
131
+ console.log(`📝 Registered: ${files.join(', ')}`);
132
+ }
133
+ // Check for conflicts
134
+ const allBranches = await storage.list();
135
+ const conflicts = [];
136
+ for (const otherBranch of allBranches) {
137
+ if (otherBranch.name === branch || otherBranch.status !== 'active')
138
+ continue;
139
+ const overlapping = files.filter(f => otherBranch.files.includes(f));
140
+ if (overlapping.length > 0) {
141
+ conflicts.push({ branch: otherBranch.name, files: overlapping });
142
+ }
143
+ }
144
+ if (conflicts.length > 0) {
145
+ console.log(`\n⚠️ CONFLICT DETECTED!`);
146
+ conflicts.forEach(c => {
147
+ console.log(` 🔴 ${c.branch}: ${c.files.join(', ')}`);
148
+ });
149
+ console.log('');
150
+ // Emit to Hub via socket if connected
151
+ if (hubSocket?.connected) {
152
+ hubSocket.emit('conflicts:warning', {
153
+ branch,
154
+ agent,
155
+ files,
156
+ conflicts,
157
+ timestamp: new Date().toISOString()
158
+ });
159
+ }
160
+ // Post to Hub chat if --hub-sync enabled
161
+ if (options.hubSync) {
162
+ await postConflictToChat(branch, agent, conflicts);
163
+ console.log('📤 Posted conflict to Hub chat');
164
+ }
165
+ }
166
+ }
167
+ // Build extended ignore patterns for smart mode
168
+ const smartIgnores = [
169
+ '**/.next/**', '**/build/**', '**/out/**', '**/coverage/**',
170
+ '**/.cache/**', '**/__pycache__/**', '**/target/**',
171
+ '**/vendor/**', '**/bower_components/**', '**/.pnpm/**',
172
+ '**/.idea/**', '**/.vscode/**', '**/*.swp', '**/*.swo',
173
+ '**/.DS_Store', '**/Thumbs.db',
174
+ '**/package-lock.json', '**/yarn.lock', '**/pnpm-lock.yaml',
175
+ '**/*.png', '**/*.jpg', '**/*.jpeg', '**/*.gif', '**/*.ico',
176
+ '**/*.woff', '**/*.woff2', '**/*.ttf', '**/*.pdf',
177
+ ];
178
+ if (options.legacy) {
179
+ console.log('⚠️ Legacy mode: Using old watcher settings (more file descriptors)');
180
+ }
181
+ // Start watching
182
+ // SECURITY FIX: Always limit depth to prevent EMFILE errors (Sherlocksan 2026-01-02)
183
+ const watcher = chokidar.watch(repoRoot, {
184
+ ignored: !options.legacy ? [
185
+ ...smartIgnores,
186
+ /(^|[/\\])\../, // dotfiles
187
+ '**/node_modules/**',
188
+ '**/dist/**',
189
+ '**/*.log',
190
+ '**/.git/**', // ALWAYS ignore .git
191
+ ] : [
192
+ /(^|[/\\])\../, // dotfiles (ALWAYS ignore)
193
+ '**/node_modules/**',
194
+ '**/dist/**',
195
+ '**/*.log',
196
+ '**/.git/**', // ALWAYS ignore .git
197
+ ],
198
+ persistent: true,
199
+ ignoreInitial: true,
200
+ awaitWriteFinish: {
201
+ stabilityThreshold: 500,
202
+ pollInterval: 100
203
+ },
204
+ // ALWAYS limit depth to prevent EMFILE (default: 5, legacy: 10)
205
+ depth: !options.legacy ? 5 : 10,
206
+ // Smart mode (default): use polling to reduce file descriptor usage
207
+ ...(!options.legacy && {
208
+ usePolling: true,
209
+ interval: 1000, // Check every 1 second
210
+ binaryInterval: 3000,
211
+ })
212
+ });
213
+ watcher.on('change', (filePath) => {
214
+ const relativePath = path.relative(repoRoot, filePath);
215
+ pendingFiles.add(relativePath);
216
+ // Debounce: wait for more changes before processing
217
+ if (debounceTimer)
218
+ clearTimeout(debounceTimer);
219
+ debounceTimer = setTimeout(processChanges, DEBOUNCE_MS);
220
+ });
221
+ watcher.on('add', (filePath) => {
222
+ const relativePath = path.relative(repoRoot, filePath);
223
+ pendingFiles.add(relativePath);
224
+ if (debounceTimer)
225
+ clearTimeout(debounceTimer);
226
+ debounceTimer = setTimeout(processChanges, DEBOUNCE_MS);
227
+ });
228
+ watcher.on('error', (err) => {
229
+ const errorMsg = err instanceof Error ? err.message : String(err);
230
+ console.error(`❌ Watcher error: ${errorMsg}`);
231
+ });
232
+ // Handle graceful shutdown
233
+ process.on('SIGINT', () => {
234
+ console.log('\n🕷️ Watch mode stopped.');
235
+ watcher.close();
236
+ hubSocket?.disconnect();
237
+ process.exit(0);
238
+ });
239
+ process.on('SIGTERM', () => {
240
+ watcher.close();
241
+ hubSocket?.disconnect();
242
+ process.exit(0);
243
+ });
244
+ });
245
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * spidersan who-touched <file>
3
+ *
4
+ * Show git history of who touched a file, enriched with agent info.
5
+ * Quick forensics for multi-agent coordination.
6
+ */
7
+ import { Command } from 'commander';
8
+ export declare const whoTouchedCommand: Command;
9
+ //# sourceMappingURL=who-touched.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"who-touched.d.ts","sourceRoot":"","sources":["../../src/commands/who-touched.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+HpC,eAAO,MAAM,iBAAiB,SAyFxB,CAAC"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * spidersan who-touched <file>
3
+ *
4
+ * Show git history of who touched a file, enriched with agent info.
5
+ * Quick forensics for multi-agent coordination.
6
+ */
7
+ import { Command } from 'commander';
8
+ import { execSync } from 'child_process';
9
+ import { existsSync } from 'fs';
10
+ // Security: Input validation
11
+ const VALID_FILE_PATH = /^[./a-zA-Z0-9][a-zA-Z0-9/_.@-]{0,200}$/;
12
+ function validateFilePath(path) {
13
+ if (!VALID_FILE_PATH.test(path)) {
14
+ throw new Error(`Invalid file path: "${path.slice(0, 50)}..."`);
15
+ }
16
+ return path;
17
+ }
18
+ /**
19
+ * Extract agent ID from commit message or author
20
+ * Looks for patterns like:
21
+ * - 🕷️ Spidersan: ...
22
+ * - [mappersan] ...
23
+ * - Author email containing agent name
24
+ */
25
+ function extractAgentFromCommit(entry) {
26
+ const message = entry.subject.toLowerCase();
27
+ const author = entry.author.toLowerCase();
28
+ const email = entry.email.toLowerCase();
29
+ // Known agent patterns in commit messages
30
+ const agentPatterns = [
31
+ /🕷️\s*(\w+san)/i,
32
+ /🕵️\s*(\w+san)/i,
33
+ /🗺️\s*(\w+san)/i,
34
+ /🌊\s*(\w+san)/i,
35
+ /🐦\s*(\w+san)/i,
36
+ /🎨\s*(\w+san)/i,
37
+ /📣\s*(\w+san)/i,
38
+ /📿\s*(\w+san)/i,
39
+ /🍄\s*(\w+san)/i,
40
+ /🌳\s*(\w+san)/i,
41
+ /🥷\s*(\w+san)/i,
42
+ /\[(\w+san)\]/i,
43
+ /^(\w+san):/i,
44
+ ];
45
+ for (const pattern of agentPatterns) {
46
+ const match = message.match(pattern);
47
+ if (match)
48
+ return match[1].toLowerCase();
49
+ }
50
+ // Check author/email for agent names
51
+ const knownAgents = [
52
+ 'spidersan', 'sherlocksan', 'mappersan', 'watsan', 'birdsan',
53
+ 'artisan', 'marksan', 'yosef', 'myceliumail', 'sasusan', 'treesan'
54
+ ];
55
+ for (const agent of knownAgents) {
56
+ if (author.includes(agent) || email.includes(agent)) {
57
+ return agent;
58
+ }
59
+ }
60
+ return undefined;
61
+ }
62
+ function getAgentGlyph(agent) {
63
+ const glyphs = {
64
+ 'spidersan': '🕷️',
65
+ 'sherlocksan': '🕵️',
66
+ 'mappersan': '🗺️',
67
+ 'watsan': '🌊',
68
+ 'birdsan': '🐦',
69
+ 'artisan': '🎨',
70
+ 'marksan': '📣',
71
+ 'yosef': '📿',
72
+ 'myceliumail': '🍄',
73
+ 'sasusan': '🥷',
74
+ 'treesan': '🌳',
75
+ 'treebird': '🌳',
76
+ };
77
+ return glyphs[agent.toLowerCase()] || '👤';
78
+ }
79
+ function getFileHistory(filePath, limit) {
80
+ try {
81
+ // Use %x00 as delimiter for safety
82
+ const format = '%H%x00%h%x00%an%x00%ae%x00%ai%x00%ar%x00%s';
83
+ const output = execSync(`git log -n ${limit} --follow --format="${format}" -- "${filePath}"`, { encoding: 'utf-8', maxBuffer: 1024 * 1024 });
84
+ const entries = [];
85
+ const lines = output.trim().split('\n').filter(l => l);
86
+ for (const line of lines) {
87
+ const parts = line.split('\0');
88
+ if (parts.length >= 7) {
89
+ const entry = {
90
+ hash: parts[0],
91
+ shortHash: parts[1],
92
+ author: parts[2],
93
+ email: parts[3],
94
+ date: parts[4],
95
+ relativeDate: parts[5],
96
+ subject: parts[6],
97
+ };
98
+ entry.agent = extractAgentFromCommit(entry);
99
+ entries.push(entry);
100
+ }
101
+ }
102
+ return entries;
103
+ }
104
+ catch (error) {
105
+ throw new Error(`Failed to get git history for "${filePath}"`);
106
+ }
107
+ }
108
+ export const whoTouchedCommand = new Command('who-touched')
109
+ .description('Show who touched a file (git history with agent detection)')
110
+ .argument('<file>', 'File path to check history for')
111
+ .option('-n, --limit <count>', 'Number of commits to show', '10')
112
+ .option('--json', 'Output as JSON')
113
+ .option('--agents-only', 'Only show commits from detected agents')
114
+ .option('--since <date>', 'Show commits since date (e.g., "2 days ago")')
115
+ .action(async (file, options) => {
116
+ // Validate input
117
+ const safePath = validateFilePath(file);
118
+ const limit = parseInt(options.limit, 10) || 10;
119
+ // Check if file exists or is tracked
120
+ if (!existsSync(safePath)) {
121
+ try {
122
+ execSync(`git ls-files --error-unmatch "${safePath}"`, {
123
+ encoding: 'utf-8',
124
+ stdio: 'pipe'
125
+ });
126
+ }
127
+ catch {
128
+ console.error(`❌ File not found: ${safePath}`);
129
+ process.exit(1);
130
+ }
131
+ }
132
+ let entries = getFileHistory(safePath, limit * 2); // Get extra to filter
133
+ // Filter by --agents-only
134
+ if (options.agentsOnly) {
135
+ entries = entries.filter(e => e.agent);
136
+ }
137
+ // Filter by --since
138
+ if (options.since) {
139
+ try {
140
+ const sinceDate = execSync(`date -d "${options.since}" +%s 2>/dev/null || date -j -f "%Y-%m-%d" "${options.since}" +%s`, { encoding: 'utf-8' }).trim();
141
+ const sinceTimestamp = parseInt(sinceDate, 10);
142
+ entries = entries.filter(e => {
143
+ const commitDate = new Date(e.date).getTime() / 1000;
144
+ return commitDate >= sinceTimestamp;
145
+ });
146
+ }
147
+ catch {
148
+ // If date parsing fails, skip the filter
149
+ }
150
+ }
151
+ // Limit results
152
+ entries = entries.slice(0, limit);
153
+ if (entries.length === 0) {
154
+ console.log(`🕷️ No history found for "${safePath}"`);
155
+ return;
156
+ }
157
+ if (options.json) {
158
+ console.log(JSON.stringify({ file: safePath, history: entries }, null, 2));
159
+ return;
160
+ }
161
+ // Count unique authors/agents
162
+ const authors = new Set(entries.map(e => e.author));
163
+ const agents = new Set(entries.filter(e => e.agent).map(e => e.agent));
164
+ console.log(`
165
+ 🕷️ WHO TOUCHED: ${safePath}
166
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
167
+ `);
168
+ for (const entry of entries) {
169
+ const glyph = entry.agent ? getAgentGlyph(entry.agent) : '👤';
170
+ const agentTag = entry.agent ? ` (${entry.agent})` : '';
171
+ const subject = entry.subject.length > 50
172
+ ? entry.subject.slice(0, 47) + '...'
173
+ : entry.subject;
174
+ console.log(`${glyph} ${entry.shortHash} | ${entry.relativeDate.padEnd(15)} | ${entry.author}${agentTag}`);
175
+ console.log(` └─ ${subject}`);
176
+ }
177
+ console.log(`
178
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
179
+ 📊 ${entries.length} commits | ${authors.size} authors | ${agents.size} agents detected
180
+ `);
181
+ if (agents.size > 0) {
182
+ const agentList = Array.from(agents).map(a => `${getAgentGlyph(a)} ${a}`).join(' ');
183
+ console.log(`🤖 Agents: ${agentList}`);
184
+ }
185
+ });
186
+ //# sourceMappingURL=who-touched.js.map