spidersan 0.20.1 → 0.20.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 (310) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/bin/command-registry.d.ts +25 -0
  3. package/dist/bin/command-registry.d.ts.map +1 -0
  4. package/dist/bin/command-registry.js +29 -0
  5. package/dist/bin/command-registry.js.map +1 -0
  6. package/dist/bin/spidersan.d.ts +16 -0
  7. package/dist/bin/spidersan.d.ts.map +1 -0
  8. package/dist/bin/spidersan.js +98 -0
  9. package/dist/bin/spidersan.js.map +1 -0
  10. package/dist/commands/abandon.d.ts +8 -0
  11. package/dist/commands/abandon.d.ts.map +1 -0
  12. package/dist/commands/abandon.js +43 -0
  13. package/dist/commands/abandon.js.map +1 -0
  14. package/dist/commands/cleanup.d.ts +8 -0
  15. package/dist/commands/cleanup.d.ts.map +1 -0
  16. package/dist/commands/cleanup.js +50 -0
  17. package/dist/commands/cleanup.js.map +1 -0
  18. package/dist/commands/config.d.ts +15 -0
  19. package/dist/commands/config.d.ts.map +1 -0
  20. package/dist/commands/config.js +309 -0
  21. package/dist/commands/config.js.map +1 -0
  22. package/dist/commands/conflicts.d.ts +34 -0
  23. package/dist/commands/conflicts.d.ts.map +1 -0
  24. package/dist/commands/conflicts.js +773 -0
  25. package/dist/commands/conflicts.js.map +1 -0
  26. package/dist/commands/context.d.ts +8 -0
  27. package/dist/commands/context.d.ts.map +1 -0
  28. package/dist/commands/context.js +104 -0
  29. package/dist/commands/context.js.map +1 -0
  30. package/dist/commands/cross-conflicts.d.ts +17 -0
  31. package/dist/commands/cross-conflicts.d.ts.map +1 -0
  32. package/dist/commands/cross-conflicts.js +273 -0
  33. package/dist/commands/cross-conflicts.js.map +1 -0
  34. package/dist/commands/depends.d.ts +11 -0
  35. package/dist/commands/depends.d.ts.map +1 -0
  36. package/dist/commands/depends.js +63 -0
  37. package/dist/commands/depends.js.map +1 -0
  38. package/dist/commands/doctor.d.ts +30 -0
  39. package/dist/commands/doctor.d.ts.map +1 -0
  40. package/dist/commands/doctor.js +558 -0
  41. package/dist/commands/doctor.js.map +1 -0
  42. package/dist/commands/git-watch.d.ts +24 -0
  43. package/dist/commands/git-watch.d.ts.map +1 -0
  44. package/dist/commands/git-watch.js +84 -0
  45. package/dist/commands/git-watch.js.map +1 -0
  46. package/dist/commands/github-sync.d.ts +42 -0
  47. package/dist/commands/github-sync.d.ts.map +1 -0
  48. package/dist/commands/github-sync.js +191 -0
  49. package/dist/commands/github-sync.js.map +1 -0
  50. package/dist/commands/index.d.ts +25 -0
  51. package/dist/commands/index.d.ts.map +1 -0
  52. package/dist/commands/index.js +29 -0
  53. package/dist/commands/index.js.map +1 -0
  54. package/dist/commands/init.d.ts +8 -0
  55. package/dist/commands/init.d.ts.map +1 -0
  56. package/dist/commands/init.js +23 -0
  57. package/dist/commands/init.js.map +1 -0
  58. package/dist/commands/list.d.ts +3 -0
  59. package/dist/commands/list.d.ts.map +1 -0
  60. package/dist/commands/list.js +45 -0
  61. package/dist/commands/list.js.map +1 -0
  62. package/dist/commands/log.d.ts +7 -0
  63. package/dist/commands/log.d.ts.map +1 -0
  64. package/dist/commands/log.js +110 -0
  65. package/dist/commands/log.js.map +1 -0
  66. package/dist/commands/merge-order.d.ts +9 -0
  67. package/dist/commands/merge-order.d.ts.map +1 -0
  68. package/dist/commands/merge-order.js +100 -0
  69. package/dist/commands/merge-order.js.map +1 -0
  70. package/dist/commands/merged.d.ts +8 -0
  71. package/dist/commands/merged.d.ts.map +1 -0
  72. package/dist/commands/merged.js +37 -0
  73. package/dist/commands/merged.js.map +1 -0
  74. package/dist/commands/pr-check.d.ts +24 -0
  75. package/dist/commands/pr-check.d.ts.map +1 -0
  76. package/dist/commands/pr-check.js +85 -0
  77. package/dist/commands/pr-check.js.map +1 -0
  78. package/dist/commands/ready-check.d.ts +11 -0
  79. package/dist/commands/ready-check.d.ts.map +1 -0
  80. package/dist/commands/ready-check.js +150 -0
  81. package/dist/commands/ready-check.js.map +1 -0
  82. package/dist/commands/rebase-helper.d.ts +3 -0
  83. package/dist/commands/rebase-helper.d.ts.map +1 -0
  84. package/dist/commands/rebase-helper.js +52 -0
  85. package/dist/commands/rebase-helper.js.map +1 -0
  86. package/dist/commands/register.d.ts +10 -0
  87. package/dist/commands/register.d.ts.map +1 -0
  88. package/dist/commands/register.js +176 -0
  89. package/dist/commands/register.js.map +1 -0
  90. package/dist/commands/registry-sync.d.ts +9 -0
  91. package/dist/commands/registry-sync.d.ts.map +1 -0
  92. package/dist/commands/registry-sync.js +129 -0
  93. package/dist/commands/registry-sync.js.map +1 -0
  94. package/dist/commands/stale.d.ts +17 -0
  95. package/dist/commands/stale.d.ts.map +1 -0
  96. package/dist/commands/stale.js +136 -0
  97. package/dist/commands/stale.js.map +1 -0
  98. package/dist/commands/sync.d.ts +21 -0
  99. package/dist/commands/sync.d.ts.map +1 -0
  100. package/dist/commands/sync.js +78 -0
  101. package/dist/commands/sync.js.map +1 -0
  102. package/dist/commands/verify-trunk.d.ts +18 -0
  103. package/dist/commands/verify-trunk.d.ts.map +1 -0
  104. package/dist/commands/verify-trunk.js +77 -0
  105. package/dist/commands/verify-trunk.js.map +1 -0
  106. package/dist/commands/watch.d.ts +8 -0
  107. package/dist/commands/watch.d.ts.map +1 -0
  108. package/dist/commands/watch.js +509 -0
  109. package/dist/commands/watch.js.map +1 -0
  110. package/dist/index.d.ts +8 -0
  111. package/dist/index.d.ts.map +1 -0
  112. package/dist/index.js +8 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/lib/activity.d.ts +53 -0
  115. package/dist/lib/activity.d.ts.map +1 -0
  116. package/dist/lib/activity.js +271 -0
  117. package/dist/lib/activity.js.map +1 -0
  118. package/dist/lib/agent-errors.d.ts +41 -0
  119. package/dist/lib/agent-errors.d.ts.map +1 -0
  120. package/dist/lib/agent-errors.js +145 -0
  121. package/dist/lib/agent-errors.js.map +1 -0
  122. package/dist/lib/ai/context-builder.d.ts +16 -0
  123. package/dist/lib/ai/context-builder.d.ts.map +1 -0
  124. package/dist/lib/ai/context-builder.js +229 -0
  125. package/dist/lib/ai/context-builder.js.map +1 -0
  126. package/dist/lib/ai/event-handler.d.ts +21 -0
  127. package/dist/lib/ai/event-handler.d.ts.map +1 -0
  128. package/dist/lib/ai/event-handler.js +111 -0
  129. package/dist/lib/ai/event-handler.js.map +1 -0
  130. package/dist/lib/ai/index.d.ts +13 -0
  131. package/dist/lib/ai/index.d.ts.map +1 -0
  132. package/dist/lib/ai/index.js +11 -0
  133. package/dist/lib/ai/index.js.map +1 -0
  134. package/dist/lib/ai/llm-client.d.ts +37 -0
  135. package/dist/lib/ai/llm-client.d.ts.map +1 -0
  136. package/dist/lib/ai/llm-client.js +225 -0
  137. package/dist/lib/ai/llm-client.js.map +1 -0
  138. package/dist/lib/ai/reasoner.d.ts +11 -0
  139. package/dist/lib/ai/reasoner.d.ts.map +1 -0
  140. package/dist/lib/ai/reasoner.js +227 -0
  141. package/dist/lib/ai/reasoner.js.map +1 -0
  142. package/dist/lib/ai/setup.d.ts +40 -0
  143. package/dist/lib/ai/setup.d.ts.map +1 -0
  144. package/dist/lib/ai/setup.js +154 -0
  145. package/dist/lib/ai/setup.js.map +1 -0
  146. package/dist/lib/ai/types.d.ts +135 -0
  147. package/dist/lib/ai/types.d.ts.map +1 -0
  148. package/dist/lib/ai/types.js +42 -0
  149. package/dist/lib/ai/types.js.map +1 -0
  150. package/dist/lib/ast.d.ts +44 -0
  151. package/dist/lib/ast.d.ts.map +1 -0
  152. package/dist/lib/ast.js +160 -0
  153. package/dist/lib/ast.js.map +1 -0
  154. package/dist/lib/carries.d.ts +22 -0
  155. package/dist/lib/carries.d.ts.map +1 -0
  156. package/dist/lib/carries.js +56 -0
  157. package/dist/lib/carries.js.map +1 -0
  158. package/dist/lib/colony-subscriber.d.ts +56 -0
  159. package/dist/lib/colony-subscriber.d.ts.map +1 -0
  160. package/dist/lib/colony-subscriber.js +265 -0
  161. package/dist/lib/colony-subscriber.js.map +1 -0
  162. package/dist/lib/config.d.ts +62 -0
  163. package/dist/lib/config.d.ts.map +1 -0
  164. package/dist/lib/config.js +235 -0
  165. package/dist/lib/config.js.map +1 -0
  166. package/dist/lib/conflict-analyzer.d.ts +33 -0
  167. package/dist/lib/conflict-analyzer.d.ts.map +1 -0
  168. package/dist/lib/conflict-analyzer.js +114 -0
  169. package/dist/lib/conflict-analyzer.js.map +1 -0
  170. package/dist/lib/conflict-renderer.d.ts +7 -0
  171. package/dist/lib/conflict-renderer.d.ts.map +1 -0
  172. package/dist/lib/conflict-renderer.js +145 -0
  173. package/dist/lib/conflict-renderer.js.map +1 -0
  174. package/dist/lib/conflict-tier.d.ts +20 -0
  175. package/dist/lib/conflict-tier.d.ts.map +1 -0
  176. package/dist/lib/conflict-tier.js +49 -0
  177. package/dist/lib/conflict-tier.js.map +1 -0
  178. package/dist/lib/crypto.d.ts +71 -0
  179. package/dist/lib/crypto.d.ts.map +1 -0
  180. package/dist/lib/crypto.js +176 -0
  181. package/dist/lib/crypto.js.map +1 -0
  182. package/dist/lib/ecosystem-env.d.ts +33 -0
  183. package/dist/lib/ecosystem-env.d.ts.map +1 -0
  184. package/dist/lib/ecosystem-env.js +62 -0
  185. package/dist/lib/ecosystem-env.js.map +1 -0
  186. package/dist/lib/errors.d.ts +35 -0
  187. package/dist/lib/errors.d.ts.map +1 -0
  188. package/dist/lib/errors.js +71 -0
  189. package/dist/lib/errors.js.map +1 -0
  190. package/dist/lib/git-events-subscriber.d.ts +86 -0
  191. package/dist/lib/git-events-subscriber.d.ts.map +1 -0
  192. package/dist/lib/git-events-subscriber.js +870 -0
  193. package/dist/lib/git-events-subscriber.js.map +1 -0
  194. package/dist/lib/git-merge-analyzer.d.ts +38 -0
  195. package/dist/lib/git-merge-analyzer.d.ts.map +1 -0
  196. package/dist/lib/git-merge-analyzer.js +23 -0
  197. package/dist/lib/git-merge-analyzer.js.map +1 -0
  198. package/dist/lib/git.d.ts +103 -0
  199. package/dist/lib/git.d.ts.map +1 -0
  200. package/dist/lib/git.js +670 -0
  201. package/dist/lib/git.js.map +1 -0
  202. package/dist/lib/github.d.ts +151 -0
  203. package/dist/lib/github.d.ts.map +1 -0
  204. package/dist/lib/github.js +425 -0
  205. package/dist/lib/github.js.map +1 -0
  206. package/dist/lib/graph.d.ts +38 -0
  207. package/dist/lib/graph.d.ts.map +1 -0
  208. package/dist/lib/graph.js +165 -0
  209. package/dist/lib/graph.js.map +1 -0
  210. package/dist/lib/machine.d.ts +14 -0
  211. package/dist/lib/machine.d.ts.map +1 -0
  212. package/dist/lib/machine.js +38 -0
  213. package/dist/lib/machine.js.map +1 -0
  214. package/dist/lib/notify.d.ts +68 -0
  215. package/dist/lib/notify.d.ts.map +1 -0
  216. package/dist/lib/notify.js +111 -0
  217. package/dist/lib/notify.js.map +1 -0
  218. package/dist/lib/outline.d.ts +6 -0
  219. package/dist/lib/outline.d.ts.map +1 -0
  220. package/dist/lib/outline.js +60 -0
  221. package/dist/lib/outline.js.map +1 -0
  222. package/dist/lib/push-registry.d.ts +22 -0
  223. package/dist/lib/push-registry.d.ts.map +1 -0
  224. package/dist/lib/push-registry.js +21 -0
  225. package/dist/lib/push-registry.js.map +1 -0
  226. package/dist/lib/reconcile.d.ts +100 -0
  227. package/dist/lib/reconcile.d.ts.map +1 -0
  228. package/dist/lib/reconcile.js +121 -0
  229. package/dist/lib/reconcile.js.map +1 -0
  230. package/dist/lib/regex-utils.d.ts +6 -0
  231. package/dist/lib/regex-utils.d.ts.map +1 -0
  232. package/dist/lib/regex-utils.js +24 -0
  233. package/dist/lib/regex-utils.js.map +1 -0
  234. package/dist/lib/register-renderer.d.ts +10 -0
  235. package/dist/lib/register-renderer.d.ts.map +1 -0
  236. package/dist/lib/register-renderer.js +19 -0
  237. package/dist/lib/register-renderer.js.map +1 -0
  238. package/dist/lib/remote-drift.d.ts +61 -0
  239. package/dist/lib/remote-drift.d.ts.map +1 -0
  240. package/dist/lib/remote-drift.js +227 -0
  241. package/dist/lib/remote-drift.js.map +1 -0
  242. package/dist/lib/security.d.ts +72 -0
  243. package/dist/lib/security.d.ts.map +1 -0
  244. package/dist/lib/security.js +180 -0
  245. package/dist/lib/security.js.map +1 -0
  246. package/dist/lib/semantic-analysis.d.ts +31 -0
  247. package/dist/lib/semantic-analysis.d.ts.map +1 -0
  248. package/dist/lib/semantic-analysis.js +120 -0
  249. package/dist/lib/semantic-analysis.js.map +1 -0
  250. package/dist/lib/supabase-credentials.d.ts +36 -0
  251. package/dist/lib/supabase-credentials.d.ts.map +1 -0
  252. package/dist/lib/supabase-credentials.js +43 -0
  253. package/dist/lib/supabase-credentials.js.map +1 -0
  254. package/dist/lib/trunk.d.ts +39 -0
  255. package/dist/lib/trunk.d.ts.map +1 -0
  256. package/dist/lib/trunk.js +116 -0
  257. package/dist/lib/trunk.js.map +1 -0
  258. package/dist/lib/update-check.d.ts +11 -0
  259. package/dist/lib/update-check.d.ts.map +1 -0
  260. package/dist/lib/update-check.js +113 -0
  261. package/dist/lib/update-check.js.map +1 -0
  262. package/dist/lib/watch-renderer.d.ts +13 -0
  263. package/dist/lib/watch-renderer.d.ts.map +1 -0
  264. package/dist/lib/watch-renderer.js +35 -0
  265. package/dist/lib/watch-renderer.js.map +1 -0
  266. package/dist/storage/adapter.d.ts +81 -0
  267. package/dist/storage/adapter.d.ts.map +1 -0
  268. package/dist/storage/adapter.js +8 -0
  269. package/dist/storage/adapter.js.map +1 -0
  270. package/dist/storage/branch-registry-store.d.ts +13 -0
  271. package/dist/storage/branch-registry-store.d.ts.map +1 -0
  272. package/dist/storage/branch-registry-store.js +2 -0
  273. package/dist/storage/branch-registry-store.js.map +1 -0
  274. package/dist/storage/factory.d.ts +6 -0
  275. package/dist/storage/factory.d.ts.map +1 -0
  276. package/dist/storage/factory.js +14 -0
  277. package/dist/storage/factory.js.map +1 -0
  278. package/dist/storage/index.d.ts +10 -0
  279. package/dist/storage/index.d.ts.map +1 -0
  280. package/dist/storage/index.js +11 -0
  281. package/dist/storage/index.js.map +1 -0
  282. package/dist/storage/json-branch-registry-store.d.ts +19 -0
  283. package/dist/storage/json-branch-registry-store.d.ts.map +1 -0
  284. package/dist/storage/json-branch-registry-store.js +138 -0
  285. package/dist/storage/json-branch-registry-store.js.map +1 -0
  286. package/dist/storage/local.d.ts +20 -0
  287. package/dist/storage/local.d.ts.map +1 -0
  288. package/dist/storage/local.js +40 -0
  289. package/dist/storage/local.js.map +1 -0
  290. package/dist/storage/memory-branch-registry-store.d.ts +16 -0
  291. package/dist/storage/memory-branch-registry-store.d.ts.map +1 -0
  292. package/dist/storage/memory-branch-registry-store.js +68 -0
  293. package/dist/storage/memory-branch-registry-store.js.map +1 -0
  294. package/dist/storage/supabase-registry-sync-client-impl.d.ts +40 -0
  295. package/dist/storage/supabase-registry-sync-client-impl.d.ts.map +1 -0
  296. package/dist/storage/supabase-registry-sync-client-impl.js +278 -0
  297. package/dist/storage/supabase-registry-sync-client-impl.js.map +1 -0
  298. package/dist/storage/supabase-registry-sync-client.d.ts +9 -0
  299. package/dist/storage/supabase-registry-sync-client.d.ts.map +1 -0
  300. package/dist/storage/supabase-registry-sync-client.js +2 -0
  301. package/dist/storage/supabase-registry-sync-client.js.map +1 -0
  302. package/dist/storage/supabase.d.ts +28 -0
  303. package/dist/storage/supabase.d.ts.map +1 -0
  304. package/dist/storage/supabase.js +56 -0
  305. package/dist/storage/supabase.js.map +1 -0
  306. package/dist/types/cloud.d.ts +102 -0
  307. package/dist/types/cloud.d.ts.map +1 -0
  308. package/dist/types/cloud.js +13 -0
  309. package/dist/types/cloud.js.map +1 -0
  310. package/package.json +1 -1
@@ -0,0 +1,176 @@
1
+ import { Command } from 'commander';
2
+ import { getStorage } from '../storage/index.js';
3
+ import * as readline from 'readline';
4
+ import { loadConfig } from '../lib/config.js';
5
+ import { getChangedFiles, getCurrentBranch } from '../lib/git.js';
6
+ import { getTrunkBranch } from '../lib/trunk.js';
7
+ import { validateAgentId, sanitizeFilePaths, validateFilePath } from '../lib/security.js';
8
+ import { logActivity } from '../lib/activity.js';
9
+ import { renderRegisterResult } from '../lib/register-renderer.js';
10
+ // Git execution is centralized in ../lib/git.js via execFileSync('git', [...]).
11
+ // Path segments that are never meaningful for conflict tracking (matched anywhere in the path)
12
+ const EXCLUDED_PATH_SEGMENTS = [
13
+ '/node_modules/',
14
+ '/.git/',
15
+ '/dist/',
16
+ '/build/',
17
+ '/.next/',
18
+ '/target/', // Rust/Cargo build output
19
+ '/.turbo/',
20
+ '/.cache/',
21
+ ];
22
+ export function isExcludedPath(file) {
23
+ // Normalise: wrap in slashes so segment patterns match at the start too
24
+ const normalised = `/${file}/`;
25
+ return EXCLUDED_PATH_SEGMENTS.some(seg => normalised.includes(seg));
26
+ }
27
+ /**
28
+ * The Claude Code session running this command, or undefined. The id is written to the
29
+ * registry and later printed into agent context, so accept only a plain UUID-ish token.
30
+ */
31
+ export function resolveSessionId(env = process.env) {
32
+ const id = env.CLAUDE_CODE_SESSION_ID?.trim();
33
+ return id && /^[0-9a-f][0-9a-f-]{7,63}$/i.test(id) ? id : undefined;
34
+ }
35
+ export function validateRegistrationFiles(files) {
36
+ for (const file of files) {
37
+ validateFilePath(file);
38
+ }
39
+ }
40
+ function getRelevantChangedFiles() {
41
+ return getChangedFiles({ base: getTrunkBranch() }).filter((file) => !isExcludedPath(file));
42
+ }
43
+ async function promptForFiles(detectedFiles) {
44
+ const rl = readline.createInterface({
45
+ input: process.stdin,
46
+ output: process.stdout
47
+ });
48
+ return new Promise((resolve) => {
49
+ if (detectedFiles.length > 0) {
50
+ console.log('\n🕷️ Detected changed files:');
51
+ detectedFiles.forEach((f, i) => console.log(` ${i + 1}. ${f}`));
52
+ console.log('');
53
+ rl.question('Use these files? [Y/n/edit]: ', (answer) => {
54
+ rl.close();
55
+ const a = answer.toLowerCase().trim();
56
+ if (a === '' || a === 'y' || a === 'yes') {
57
+ resolve(detectedFiles);
58
+ }
59
+ else if (a === 'n' || a === 'no') {
60
+ resolve([]);
61
+ }
62
+ else {
63
+ // Let them enter custom files
64
+ console.log(' Enter comma-separated files, or leave empty:');
65
+ const rl2 = readline.createInterface({
66
+ input: process.stdin,
67
+ output: process.stdout
68
+ });
69
+ rl2.question(' Files: ', (files) => {
70
+ rl2.close();
71
+ resolve(files ? files.split(',').map(f => f.trim()) : []);
72
+ });
73
+ }
74
+ });
75
+ }
76
+ else {
77
+ rl.question('Enter files (comma-separated) or leave empty: ', (files) => {
78
+ rl.close();
79
+ resolve(files ? files.split(',').map(f => f.trim()) : []);
80
+ });
81
+ }
82
+ });
83
+ }
84
+ export const registerCommand = new Command('register')
85
+ .description('Register the current branch with files being modified')
86
+ .option('-f, --files <files>', 'Comma-separated list of files being modified')
87
+ .option('-d, --description <desc>', 'Description of what this branch does')
88
+ .option('-a, --agent <agent>', 'Agent identifier (e.g., claude-code, cursor)')
89
+ .option('-i, --interactive', 'Interactive mode (prompt for files)')
90
+ .option('--auto', 'Auto-detect files from git diff')
91
+ .action(async (options) => {
92
+ const storage = await getStorage();
93
+ const config = await loadConfig();
94
+ if (!await storage.isInitialized()) {
95
+ console.error('❌ Spidersan not initialized. Run: spidersan init');
96
+ process.exit(1);
97
+ }
98
+ const branchName = getCurrentBranch();
99
+ let files = [];
100
+ if (options.files) {
101
+ files = sanitizeFilePaths(options.files.split(',').map((f) => f.trim()).filter((f) => f && !isExcludedPath(f)));
102
+ }
103
+ else if (options.auto) {
104
+ files = getRelevantChangedFiles();
105
+ }
106
+ else if (options.interactive) {
107
+ const detected = getRelevantChangedFiles();
108
+ files = await promptForFiles(detected);
109
+ }
110
+ // Security: Validate ALL file paths before storing (Sentinel 2026-02-18)
111
+ try {
112
+ validateRegistrationFiles(files);
113
+ }
114
+ catch (err) {
115
+ if (err instanceof Error) {
116
+ console.error(`❌ Security Error: ${err.message}`);
117
+ }
118
+ else {
119
+ console.error('❌ Security Error: Invalid file path');
120
+ }
121
+ process.exit(1);
122
+ }
123
+ const configuredAgent = config.agent.name?.trim();
124
+ const rawAgent = (options.agent || process.env.SPIDERSAN_AGENT || configuredAgent || '').trim() || undefined;
125
+ let resolvedAgent = rawAgent;
126
+ if (resolvedAgent) {
127
+ try {
128
+ resolvedAgent = validateAgentId(resolvedAgent);
129
+ }
130
+ catch {
131
+ console.error(`❌ Invalid agent ID: "${resolvedAgent}". Must be alphanumeric with - or _.`);
132
+ process.exit(1);
133
+ }
134
+ }
135
+ const sessionId = resolveSessionId();
136
+ // Check if branch already registered
137
+ const existing = await storage.get(branchName);
138
+ if (existing) {
139
+ // Update existing registration
140
+ await storage.update(branchName, {
141
+ files: [...new Set([...existing.files, ...files])],
142
+ description: options.description || existing.description,
143
+ agent: resolvedAgent ?? existing.agent,
144
+ // latest session to touch the branch is the live one
145
+ sessionId: sessionId ?? existing.sessionId,
146
+ });
147
+ console.log(renderRegisterResult({
148
+ branchName,
149
+ files,
150
+ isUpdate: true,
151
+ autoDetected: !!options.auto,
152
+ autoDetectedFiles: files,
153
+ }));
154
+ logActivity({ event: 'register', branch: branchName, agent: resolvedAgent ?? undefined, details: { files, description: options.description, updated: true } });
155
+ }
156
+ else {
157
+ // New registration
158
+ await storage.register({
159
+ name: branchName,
160
+ files,
161
+ status: 'active',
162
+ description: options.description,
163
+ agent: resolvedAgent,
164
+ ...(sessionId ? { sessionId } : {}),
165
+ });
166
+ console.log(renderRegisterResult({
167
+ branchName,
168
+ files,
169
+ isUpdate: false,
170
+ autoDetected: !!options.auto,
171
+ autoDetectedFiles: files,
172
+ }));
173
+ logActivity({ event: 'register', branch: branchName, agent: resolvedAgent ?? undefined, details: { files, description: options.description } });
174
+ }
175
+ });
176
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,gFAAgF;AAEhF,+FAA+F;AAC/F,MAAM,sBAAsB,GAAG;IAC3B,gBAAgB;IAChB,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,SAAS;IACT,UAAU,EAAO,0BAA0B;IAC3C,UAAU;IACV,UAAU;CACb,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,wEAAwE;IACxE,MAAM,UAAU,GAAG,IAAI,IAAI,GAAG,CAAC;IAC/B,OAAO,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACjE,MAAM,EAAE,GAAG,GAAG,CAAC,sBAAsB,EAAE,IAAI,EAAE,CAAC;IAC9C,OAAO,EAAE,IAAI,4BAA4B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,KAAe;IACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;AACL,CAAC;AAED,SAAS,uBAAuB;IAC5B,OAAO,eAAe,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,aAAuB;IACjD,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAChC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACzB,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC3B,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YAC7C,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;YAClE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEhB,EAAE,CAAC,QAAQ,CAAC,+BAA+B,EAAE,CAAC,MAAM,EAAE,EAAE;gBACpD,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;gBACtC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC;oBACvC,OAAO,CAAC,aAAa,CAAC,CAAC;gBAC3B,CAAC;qBAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;oBACjC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAChB,CAAC;qBAAM,CAAC;oBACJ,8BAA8B;oBAC9B,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;oBAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,eAAe,CAAC;wBACjC,KAAK,EAAE,OAAO,CAAC,KAAK;wBACpB,MAAM,EAAE,OAAO,CAAC,MAAM;qBACzB,CAAC,CAAC;oBACH,GAAG,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE;wBACjC,GAAG,CAAC,KAAK,EAAE,CAAC;wBACZ,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC9D,CAAC,CAAC,CAAC;gBACP,CAAC;YACL,CAAC,CAAC,CAAC;QACP,CAAC;aAAM,CAAC;YACJ,EAAE,CAAC,QAAQ,CAAC,gDAAgD,EAAE,CAAC,KAAK,EAAE,EAAE;gBACpE,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9D,CAAC,CAAC,CAAC;QACP,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAC,UAAU,CAAC;KACjD,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,qBAAqB,EAAE,8CAA8C,CAAC;KAC7E,MAAM,CAAC,0BAA0B,EAAE,sCAAsC,CAAC;KAC1E,MAAM,CAAC,qBAAqB,EAAE,8CAA8C,CAAC;KAC7E,MAAM,CAAC,mBAAmB,EAAE,qCAAqC,CAAC;KAClE,MAAM,CAAC,QAAQ,EAAE,iCAAiC,CAAC;KACnD,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACtB,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,UAAU,GAAG,gBAAgB,EAAE,CAAC;IACtC,IAAI,KAAK,GAAa,EAAE,CAAC;IAEzB,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,GAAG,iBAAiB,CACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CACvG,CAAC;IACN,CAAC;SAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,GAAG,uBAAuB,EAAE,CAAC;IACtC,CAAC;SAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;QAC3C,KAAK,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,yEAAyE;IACzE,IAAI,CAAC;QACD,yBAAyB,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;YACvB,OAAO,CAAC,KAAK,CAAC,qBAAqB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACJ,OAAO,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAClD,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,eAAe,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;IAC7G,IAAI,aAAa,GAAG,QAAQ,CAAC;IAC7B,IAAI,aAAa,EAAE,CAAC;QAChB,IAAI,CAAC;YACD,aAAa,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,CAAC,KAAK,CAAC,wBAAwB,aAAa,sCAAsC,CAAC,CAAC;YAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAG,gBAAgB,EAAE,CAAC;IAErC,qCAAqC;IACrC,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAE/C,IAAI,QAAQ,EAAE,CAAC;QACX,+BAA+B;QAC/B,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE;YAC7B,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;YAClD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW;YACxD,KAAK,EAAE,aAAa,IAAI,QAAQ,CAAC,KAAK;YACtC,qDAAqD;YACrD,SAAS,EAAE,SAAS,IAAI,QAAQ,CAAC,SAAS;SAC7C,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;YAC7B,UAAU;YACV,KAAK;YACL,QAAQ,EAAE,IAAI;YACd,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;YAC5B,iBAAiB,EAAE,KAAK;SAC3B,CAAC,CAAC,CAAC;QACJ,WAAW,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,IAAI,SAAS,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACnK,CAAC;SAAM,CAAC;QACJ,mBAAmB;QACnB,MAAM,OAAO,CAAC,QAAQ,CAAC;YACnB,IAAI,EAAE,UAAU;YAChB,KAAK;YACL,MAAM,EAAE,QAAQ;YAChB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,KAAK,EAAE,aAAa;YACpB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtC,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;YAC7B,UAAU;YACV,KAAK;YACL,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI;YAC5B,iBAAiB,EAAE,KAAK;SAC3B,CAAC,CAAC,CAAC;QACJ,WAAW,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,IAAI,SAAS,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACpJ,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * spidersan registry-sync
3
+ *
4
+ * Sync local registry to/from Supabase for cross-machine awareness.
5
+ * Part of F1: Supabase Registry Sync (spidersan-github-dashboard).
6
+ */
7
+ import { Command } from 'commander';
8
+ export declare const registrySyncCommand: Command;
9
+ //# sourceMappingURL=registry-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-sync.d.ts","sourceRoot":"","sources":["../../src/commands/registry-sync.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmCpC,eAAO,MAAM,mBAAmB,SA4G1B,CAAC"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * spidersan registry-sync
3
+ *
4
+ * Sync local registry to/from Supabase for cross-machine awareness.
5
+ * Part of F1: Supabase Registry Sync (spidersan-github-dashboard).
6
+ */
7
+ import { Command } from 'commander';
8
+ import { execFileSync } from 'child_process';
9
+ import { LocalStorage } from '../storage/local.js';
10
+ import { SupabaseStorage } from '../storage/supabase.js';
11
+ import { resolveSupabaseCredentials } from '../lib/supabase-credentials.js';
12
+ import { loadMachineIdentity } from '../lib/machine.js';
13
+ import { getRepoName, registryRepoNames } from '../lib/git.js';
14
+ /**
15
+ * Get the repo root path.
16
+ */
17
+ function getRepoPath() {
18
+ try {
19
+ return execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf-8' }).trim();
20
+ }
21
+ catch {
22
+ return process.cwd();
23
+ }
24
+ }
25
+ /**
26
+ * Get a SupabaseStorage instance, or null if not configured.
27
+ */
28
+ async function getSupabaseStorage() {
29
+ // COLONY_SUPABASE_* used to sit in this chain as a last-resort fallback. It
30
+ // is gone deliberately: colony is a different Supabase project, so that
31
+ // fallback could push spider_registries into the wrong database (tb-ly0b).
32
+ const creds = await resolveSupabaseCredentials();
33
+ if (!creds)
34
+ return null;
35
+ return new SupabaseStorage(creds);
36
+ }
37
+ export const registrySyncCommand = new Command('registry-sync')
38
+ .description('Sync local registry to/from Supabase (cross-machine awareness)')
39
+ .option('--push', 'Push local registry to Supabase')
40
+ .option('--pull', 'Pull other machines\' registries from Supabase')
41
+ .option('--status', 'Show sync status across all machines')
42
+ .option('--repo <name>', 'Limit to specific repo (default: current)')
43
+ .action(async (options) => {
44
+ const supabase = await getSupabaseStorage();
45
+ if (!supabase) {
46
+ console.error('❌ Supabase not configured. Set SUPABASE_URL and SUPABASE_KEY.');
47
+ console.error(' Registry sync requires cloud storage for cross-machine awareness.');
48
+ process.exit(1);
49
+ }
50
+ const machine = await loadMachineIdentity();
51
+ const repoName = options.repo || getRepoName();
52
+ // Default to --status if no flag specified
53
+ if (!options.push && !options.pull && !options.status) {
54
+ options.status = true;
55
+ }
56
+ // ── PUSH ──
57
+ if (options.push) {
58
+ console.log(`🕷️ Pushing registry from ${machine.name} (${repoName})...\n`);
59
+ const localStorage = new LocalStorage();
60
+ if (!await localStorage.isInitialized()) {
61
+ console.error('❌ Spidersan not initialized. Run: spidersan init');
62
+ process.exit(1);
63
+ }
64
+ const branches = await localStorage.list();
65
+ const repoPath = getRepoPath();
66
+ const result = await supabase.pushRegistry(machine, repoName, repoPath, branches);
67
+ if (result.errors.length > 0) {
68
+ for (const err of result.errors) {
69
+ console.error(` ❌ ${err}`);
70
+ }
71
+ process.exit(1);
72
+ }
73
+ console.log(` ✅ Pushed ${result.pushed} active branch(es)`);
74
+ if (result.updated > 0)
75
+ console.log(` 🔄 Updated ${result.updated} non-active branch(es)`);
76
+ if (result.abandoned > 0)
77
+ console.log(` 🗑️ Marked ${result.abandoned} removed branch(es) as abandoned`);
78
+ for (const name of result.abandonedBranches)
79
+ console.log(` - ${name}`);
80
+ console.log(`\n Machine: ${machine.name} (${machine.hostname})`);
81
+ console.log(` Repo: ${repoName}`);
82
+ }
83
+ // ── PULL ──
84
+ if (options.pull) {
85
+ console.log(`🕷️ Pulling registries for ${repoName} (excluding ${machine.name})...\n`);
86
+ const views = await supabase.pullRegistries(options.repo ? [options.repo] : registryRepoNames(), machine.id);
87
+ if (views.length === 0) {
88
+ console.log(' No other machines have registered branches for this repo.');
89
+ return;
90
+ }
91
+ for (const view of views) {
92
+ console.log(` 📡 ${view.machine_name} (${view.hostname}) — ${view.branches.length} branch(es)`);
93
+ console.log(` Last sync: ${new Date(view.last_synced).toLocaleString()}\n`);
94
+ for (const branch of view.branches) {
95
+ const files = branch.files.length > 0 ? ` [${branch.files.length} files]` : '';
96
+ const agent = branch.agent ? ` (${branch.agent})` : '';
97
+ console.log(` • ${branch.name}${agent}${files}`);
98
+ if (branch.description) {
99
+ console.log(` ${branch.description}`);
100
+ }
101
+ }
102
+ console.log('');
103
+ }
104
+ }
105
+ // ── STATUS ──
106
+ if (options.status) {
107
+ console.log(`🕷️ Registry sync status${options.repo ? ` (${repoName})` : ' (all repos)'}:\n`);
108
+ const statuses = await supabase.getRegistryStatus(options.repo ? repoName : undefined);
109
+ if (statuses.length === 0) {
110
+ console.log(' No registries synced yet. Run: spidersan registry-sync --push');
111
+ return;
112
+ }
113
+ // Table header
114
+ console.log(' Machine Hostname Branches Active Repos Last Sync');
115
+ console.log(' ───────── ────────── ──────── ────── ───── ─────────');
116
+ for (const s of statuses) {
117
+ const isSelf = s.machine_id === machine.id ? ' ⭐' : '';
118
+ const repos = s.repos.join(', ');
119
+ const lastSync = new Date(s.last_sync).toLocaleString();
120
+ console.log(` ${(s.machine_name + isSelf).padEnd(14)}` +
121
+ `${s.hostname.padEnd(15)}` +
122
+ `${String(s.branch_count).padEnd(10)}` +
123
+ `${String(s.active_count).padEnd(8)}` +
124
+ `${repos.padEnd(17)}` +
125
+ `${lastSync}`);
126
+ }
127
+ }
128
+ });
129
+ //# sourceMappingURL=registry-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-sync.js","sourceRoot":"","sources":["../../src/commands/registry-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * spidersan stale
3
+ *
4
+ * Show branches that haven't been updated recently.
5
+ * With --notify flag: sends notifications to branch owners via .pending_task.md updates.
6
+ */
7
+ import { Command } from 'commander';
8
+ /**
9
+ * Update agent's .pending_task.md file
10
+ * ⚡ Bolt: Batched updates to avoid N+1 file I/O
11
+ */
12
+ export declare function updatePendingTaskFile(agentId: string, branches: {
13
+ name: string;
14
+ daysOld: number;
15
+ }[]): boolean;
16
+ export declare const staleCommand: Command;
17
+ //# sourceMappingURL=stale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale.d.ts","sourceRoot":"","sources":["../../src/commands/stale.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,OAAO,CAiD7G;AAED,eAAO,MAAM,YAAY,SAwFnB,CAAC"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * spidersan stale
3
+ *
4
+ * Show branches that haven't been updated recently.
5
+ * With --notify flag: sends notifications to branch owners via .pending_task.md updates.
6
+ */
7
+ import { Command } from 'commander';
8
+ import { getStorage } from '../storage/index.js';
9
+ import { existsSync, readFileSync, appendFileSync } from 'fs';
10
+ import { resolve } from 'path';
11
+ import { validateAgentId, validateBranchName } from '../lib/security.js';
12
+ /**
13
+ * Update agent's .pending_task.md file
14
+ * ⚡ Bolt: Batched updates to avoid N+1 file I/O
15
+ */
16
+ export function updatePendingTaskFile(agentId, branches) {
17
+ if (branches.length === 0)
18
+ return true;
19
+ try {
20
+ // Security: Validate inputs
21
+ validateAgentId(agentId);
22
+ for (const b of branches) {
23
+ validateBranchName(b.name);
24
+ }
25
+ // Agent-OWNED locations only. The cwd's .pending_task.md belongs to
26
+ // whoever runs `stale --notify`, not to `agentId` — writing there
27
+ // "delivers" every agent's notifications to the wrong file.
28
+ const possiblePaths = [
29
+ resolve(process.env.HOME || '~', `Dev/treebird/agents/${agentId}/.pending_task.md`),
30
+ resolve(process.cwd(), `../${agentId}/.pending_task.md`),
31
+ resolve(process.env.HOME || '~', `Dev/${agentId}/.pending_task.md`),
32
+ ];
33
+ let taskFilePath = null;
34
+ for (const path of possiblePaths) {
35
+ if (existsSync(path)) {
36
+ taskFilePath = path;
37
+ break;
38
+ }
39
+ }
40
+ if (!taskFilePath) {
41
+ return false;
42
+ }
43
+ const content = readFileSync(taskFilePath, 'utf-8');
44
+ let newEntries = '';
45
+ for (const b of branches) {
46
+ // Check if entry already exists
47
+ if (!content.includes(b.name)) {
48
+ newEntries += `- [ ] 🕷️ Stale branch: \`${b.name}\` (${b.daysOld}d inactive) - run \`spidersan cleanup\`\n`;
49
+ }
50
+ }
51
+ if (newEntries.length > 0) {
52
+ appendFileSync(taskFilePath, newEntries, 'utf-8');
53
+ }
54
+ return true;
55
+ }
56
+ catch {
57
+ return false;
58
+ }
59
+ }
60
+ export const staleCommand = new Command('stale')
61
+ .description('Show stale branches (not updated recently)')
62
+ .option('--days <n>', 'Days threshold for staleness', '7')
63
+ .option('--notify', 'Send notifications to branch owners')
64
+ .option('--auto-cleanup', 'Automatically remove stale branches after listing')
65
+ .option('--json', 'Output as JSON')
66
+ .action(async (options) => {
67
+ const storage = await getStorage();
68
+ if (!await storage.isInitialized()) {
69
+ console.error('❌ Spidersan not initialized. Run: spidersan init');
70
+ process.exit(1);
71
+ }
72
+ const days = parseInt(options.days, 10);
73
+ if (!Number.isFinite(days) || days < 0) {
74
+ console.error(`❌ Invalid --days value: ${options.days}`);
75
+ process.exit(1);
76
+ }
77
+ const threshold = new Date();
78
+ threshold.setDate(threshold.getDate() - days);
79
+ const branches = await storage.list();
80
+ const stale = branches.filter(b => new Date(b.registeredAt) < threshold);
81
+ // Group by agent if notifying
82
+ const byAgent = new Map();
83
+ if (options.notify) {
84
+ for (const branch of stale) {
85
+ const agent = branch.agent || 'unknown';
86
+ if (!byAgent.has(agent)) {
87
+ byAgent.set(agent, []);
88
+ }
89
+ byAgent.get(agent).push(branch);
90
+ }
91
+ }
92
+ if (options.json) {
93
+ console.log(JSON.stringify(stale, null, 2));
94
+ return;
95
+ }
96
+ if (stale.length === 0) {
97
+ console.log(`🕷️ No stale branches (older than ${days} days)`);
98
+ return;
99
+ }
100
+ console.log(`🕷️ Stale Branches (>${days} days old):\n`);
101
+ for (const branch of stale) {
102
+ const age = Math.floor((Date.now() - new Date(branch.registeredAt).getTime()) / 86400000);
103
+ const agentTag = branch.agent ? ` [@${branch.agent}]` : '';
104
+ console.log(` ⚠️ ${branch.name}${agentTag} (${age} days old)`);
105
+ }
106
+ // Send notifications if requested
107
+ if (options.notify) {
108
+ console.log(`\n📨 Sending notifications...`);
109
+ let fileSuccess = 0;
110
+ for (const [agent, branches] of byAgent) {
111
+ if (agent === 'unknown')
112
+ continue;
113
+ // ⚡ Bolt: Batch notification per agent to avoid N+1 slow calls
114
+ const branchData = branches.map(branch => ({
115
+ name: branch.name,
116
+ daysOld: Math.floor((Date.now() - new Date(branch.registeredAt).getTime()) / 86400000)
117
+ }));
118
+ // Try .pending_task.md update
119
+ if (updatePendingTaskFile(agent, branchData)) {
120
+ fileSuccess += branches.length;
121
+ }
122
+ }
123
+ console.log(`✅ Notifications sent:`);
124
+ console.log(` - File updates: ${fileSuccess}/${stale.length}`);
125
+ }
126
+ if (options.autoCleanup) {
127
+ console.log(`\n🗑️ Auto-cleaning ${stale.length} stale branch(es)...`);
128
+ const removedNames = await storage.cleanup(threshold);
129
+ removedNames.forEach(name => console.log(` Removed: ${name}`));
130
+ console.log(`✅ Cleaned up ${removedNames.length} branch(es).`);
131
+ }
132
+ else {
133
+ console.log(`\nRun 'spidersan cleanup' to remove these.`);
134
+ }
135
+ });
136
+ //# sourceMappingURL=stale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stale.js","sourceRoot":"","sources":["../../src/commands/stale.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * spidersan sync
3
+ *
4
+ * Reconcile the local registry against git truth and prune dead entries.
5
+ *
6
+ * Prunes BOTH:
7
+ * - orphaned — no local or tracking ref AND `git ls-remote` confirms the
8
+ * branch is gone from origin (or status `abandoned`)
9
+ * - merged — branch tip is an ancestor of trunk (or status `completed`)
10
+ *
11
+ * A missing ref alone only proves "not fetched here": the branch may be live on
12
+ * another machine. Those entries are kept, and so is every orphan when origin
13
+ * can't be asked (sp-slemub).
14
+ *
15
+ * Previously sync only removed orphans, so a merged branch lingered in the
16
+ * registry forever and kept producing phantom conflicts (tb-8sa.1 / §1.2).
17
+ * Merged entries are now deleted, not just marked.
18
+ */
19
+ import { Command } from 'commander';
20
+ export declare const syncCommand: Command;
21
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,WAAW,SA0DlB,CAAC"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * spidersan sync
3
+ *
4
+ * Reconcile the local registry against git truth and prune dead entries.
5
+ *
6
+ * Prunes BOTH:
7
+ * - orphaned — no local or tracking ref AND `git ls-remote` confirms the
8
+ * branch is gone from origin (or status `abandoned`)
9
+ * - merged — branch tip is an ancestor of trunk (or status `completed`)
10
+ *
11
+ * A missing ref alone only proves "not fetched here": the branch may be live on
12
+ * another machine. Those entries are kept, and so is every orphan when origin
13
+ * can't be asked (sp-slemub).
14
+ *
15
+ * Previously sync only removed orphans, so a merged branch lingered in the
16
+ * registry forever and kept producing phantom conflicts (tb-8sa.1 / §1.2).
17
+ * Merged entries are now deleted, not just marked.
18
+ */
19
+ import { Command } from 'commander';
20
+ import { getStorage } from '../storage/index.js';
21
+ import { logActivity } from '../lib/activity.js';
22
+ import { reconcileBranches, splitOrphans } from '../lib/reconcile.js';
23
+ export const syncCommand = new Command('sync')
24
+ .description('Sync registry with actual git branches')
25
+ .option('--dry-run', 'Show what would be synced without syncing')
26
+ .action(async (options) => {
27
+ const storage = await getStorage();
28
+ if (!await storage.isInitialized()) {
29
+ console.error('❌ Spidersan not initialized. Run: spidersan init');
30
+ process.exit(1);
31
+ }
32
+ const branches = await storage.list();
33
+ const { merged, orphaned: noRef } = reconcileBranches(branches);
34
+ // `abandoned` is terminal registry status — prune it without asking origin.
35
+ const abandoned = new Set(branches.filter(b => b.status === 'abandoned').map(b => b.name));
36
+ const { gone, kept, remoteChecked } = splitOrphans(noRef.filter(n => !abandoned.has(n)));
37
+ const orphaned = [...noRef.filter(n => abandoned.has(n)), ...gone];
38
+ if (kept.length > 0) {
39
+ console.log(remoteChecked
40
+ ? `🕷️ Kept ${kept.length} entr${kept.length === 1 ? 'y' : 'ies'} with no ref here but still on origin (unfetched): ${kept.join(', ')}`
41
+ : `⚠️ Could not reach origin — kept ${kept.length} entr${kept.length === 1 ? 'y' : 'ies'} with no ref here (deleted, or just unfetched). Fetch and re-run to prune.`);
42
+ }
43
+ const stale = [
44
+ ...merged.map(name => ({ name, reason: 'merged' })),
45
+ ...orphaned.map(name => ({ name, reason: 'orphaned' })),
46
+ ];
47
+ if (stale.length === 0) {
48
+ console.log('🕷️ Registry is in sync with git.');
49
+ logActivity({ event: 'sync', details: { merged: 0, orphaned: 0, action: 'clean' } });
50
+ return;
51
+ }
52
+ console.log(`🕷️ Found ${stale.length} stale entr${stale.length === 1 ? 'y' : 'ies'} (${merged.length} merged, ${orphaned.length} orphaned):\n`);
53
+ let failed = 0;
54
+ for (const { name, reason } of stale) {
55
+ if (options.dryRun) {
56
+ console.log(` Would remove (${reason}): ${name}`);
57
+ }
58
+ else if (await storage.unregister(name)) {
59
+ console.log(` 🗑️ Removed (${reason}): ${name}`);
60
+ logActivity({ event: 'sync', branch: name, details: { action: `removed_${reason}` } });
61
+ }
62
+ else {
63
+ // Don't claim "Removed" for a no-op — a delete that misses means
64
+ // the entry vanished mid-sync or the registry is corrupt (tb-orpt).
65
+ failed++;
66
+ console.log(` ⚠️ Could not remove (${reason}): ${name} — not found in registry`);
67
+ logActivity({ event: 'sync', branch: name, details: { action: `remove_failed_${reason}` } });
68
+ }
69
+ }
70
+ if (!options.dryRun) {
71
+ if (failed > 0) {
72
+ console.log(`\n⚠️ Synced with ${failed} failed removal${failed === 1 ? '' : 's'} — registry may be corrupt (check .spidersan/registry.json).`);
73
+ process.exit(1);
74
+ }
75
+ console.log(`\n✅ Synced registry with git.`);
76
+ }
77
+ });
78
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * spidersan verify-trunk
3
+ *
4
+ * Detect (and optionally fix) registry "trunk-poison": the trunk branch
5
+ * (main/master/develop…) claiming files in the spidersan registry. A clean
6
+ * auto-merge can silently re-poison main, so the post-merge hook gates on this.
7
+ *
8
+ * Promotes the 2026-06-15 `spidersan-post.sh` hook into a first-class command.
9
+ */
10
+ import { Command } from 'commander';
11
+ /**
12
+ * The set of branch names that MUST claim no files: the resolved trunk plus the
13
+ * literal `main`/`master` (a repo can have stray entries for either even when
14
+ * trunk resolves to something else). De-duplicated, order-stable.
15
+ */
16
+ export declare function trunkEquivalentNames(trunk: string): string[];
17
+ export declare const verifyTrunkCommand: Command;
18
+ //# sourceMappingURL=verify-trunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify-trunk.d.ts","sourceRoot":"","sources":["../../src/commands/verify-trunk.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAG5D;AAED,eAAO,MAAM,kBAAkB,SA2DzB,CAAC"}