@cluesmith/codev 2.0.2 → 2.0.6

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 (312) hide show
  1. package/dashboard/dist/assets/index-B-s8BA2l.js +135 -0
  2. package/dashboard/dist/assets/index-B-s8BA2l.js.map +1 -0
  3. package/dashboard/dist/assets/index-DB2AxRP7.css +32 -0
  4. package/dashboard/dist/index.html +2 -2
  5. package/dist/agent-farm/cli.d.ts.map +1 -1
  6. package/dist/agent-farm/cli.js +32 -14
  7. package/dist/agent-farm/cli.js.map +1 -1
  8. package/dist/agent-farm/commands/architect.d.ts +1 -1
  9. package/dist/agent-farm/commands/architect.js +3 -3
  10. package/dist/agent-farm/commands/architect.js.map +1 -1
  11. package/dist/agent-farm/commands/attach.d.ts +19 -0
  12. package/dist/agent-farm/commands/attach.d.ts.map +1 -1
  13. package/dist/agent-farm/commands/attach.js +172 -12
  14. package/dist/agent-farm/commands/attach.js.map +1 -1
  15. package/dist/agent-farm/commands/cleanup.js +6 -6
  16. package/dist/agent-farm/commands/cleanup.js.map +1 -1
  17. package/dist/agent-farm/commands/open.js +5 -5
  18. package/dist/agent-farm/commands/open.js.map +1 -1
  19. package/dist/agent-farm/commands/send.d.ts +22 -2
  20. package/dist/agent-farm/commands/send.d.ts.map +1 -1
  21. package/dist/agent-farm/commands/send.js +100 -181
  22. package/dist/agent-farm/commands/send.js.map +1 -1
  23. package/dist/agent-farm/commands/shell.js +5 -5
  24. package/dist/agent-farm/commands/shell.js.map +1 -1
  25. package/dist/agent-farm/commands/spawn-roles.d.ts +3 -9
  26. package/dist/agent-farm/commands/spawn-roles.d.ts.map +1 -1
  27. package/dist/agent-farm/commands/spawn-roles.js +14 -53
  28. package/dist/agent-farm/commands/spawn-roles.js.map +1 -1
  29. package/dist/agent-farm/commands/spawn-worktree.d.ts +11 -17
  30. package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
  31. package/dist/agent-farm/commands/spawn-worktree.js +32 -13
  32. package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
  33. package/dist/agent-farm/commands/spawn.d.ts +8 -6
  34. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  35. package/dist/agent-farm/commands/spawn.js +183 -69
  36. package/dist/agent-farm/commands/spawn.js.map +1 -1
  37. package/dist/agent-farm/commands/start.d.ts +4 -4
  38. package/dist/agent-farm/commands/start.js +16 -16
  39. package/dist/agent-farm/commands/start.js.map +1 -1
  40. package/dist/agent-farm/commands/status.d.ts +1 -1
  41. package/dist/agent-farm/commands/status.d.ts.map +1 -1
  42. package/dist/agent-farm/commands/status.js +15 -26
  43. package/dist/agent-farm/commands/status.js.map +1 -1
  44. package/dist/agent-farm/commands/stop.d.ts +4 -4
  45. package/dist/agent-farm/commands/stop.js +9 -9
  46. package/dist/agent-farm/commands/stop.js.map +1 -1
  47. package/dist/agent-farm/db/index.d.ts.map +1 -1
  48. package/dist/agent-farm/db/index.js +82 -7
  49. package/dist/agent-farm/db/index.js.map +1 -1
  50. package/dist/agent-farm/db/schema.d.ts +2 -2
  51. package/dist/agent-farm/db/schema.d.ts.map +1 -1
  52. package/dist/agent-farm/db/schema.js +21 -4
  53. package/dist/agent-farm/db/schema.js.map +1 -1
  54. package/dist/agent-farm/lib/tower-client.d.ts +36 -26
  55. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  56. package/dist/agent-farm/lib/tower-client.js +50 -25
  57. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  58. package/dist/agent-farm/lib/tunnel-client.d.ts +12 -2
  59. package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
  60. package/dist/agent-farm/lib/tunnel-client.js +59 -1
  61. package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
  62. package/dist/agent-farm/servers/overview.d.ts +111 -0
  63. package/dist/agent-farm/servers/overview.d.ts.map +1 -0
  64. package/dist/agent-farm/servers/overview.js +385 -0
  65. package/dist/agent-farm/servers/overview.js.map +1 -0
  66. package/dist/agent-farm/servers/tower-instances.d.ts +18 -20
  67. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  68. package/dist/agent-farm/servers/tower-instances.js +97 -100
  69. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  70. package/dist/agent-farm/servers/tower-messages.d.ts +87 -0
  71. package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -0
  72. package/dist/agent-farm/servers/tower-messages.js +202 -0
  73. package/dist/agent-farm/servers/tower-messages.js.map +1 -0
  74. package/dist/agent-farm/servers/tower-routes.d.ts +1 -1
  75. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  76. package/dist/agent-farm/servers/tower-routes.js +343 -174
  77. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  78. package/dist/agent-farm/servers/tower-server.js +50 -21
  79. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  80. package/dist/agent-farm/servers/tower-terminals.d.ts +35 -31
  81. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  82. package/dist/agent-farm/servers/tower-terminals.js +208 -184
  83. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  84. package/dist/agent-farm/servers/tower-tunnel.d.ts +2 -2
  85. package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -1
  86. package/dist/agent-farm/servers/tower-tunnel.js +12 -12
  87. package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
  88. package/dist/agent-farm/servers/tower-types.d.ts +8 -12
  89. package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
  90. package/dist/agent-farm/servers/tower-utils.d.ts +9 -9
  91. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
  92. package/dist/agent-farm/servers/tower-utils.js +18 -18
  93. package/dist/agent-farm/servers/tower-utils.js.map +1 -1
  94. package/dist/agent-farm/servers/tower-websocket.d.ts +2 -2
  95. package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
  96. package/dist/agent-farm/servers/tower-websocket.js +39 -18
  97. package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
  98. package/dist/agent-farm/types.d.ts +5 -6
  99. package/dist/agent-farm/types.d.ts.map +1 -1
  100. package/dist/agent-farm/utils/agent-names.d.ts +85 -0
  101. package/dist/agent-farm/utils/agent-names.d.ts.map +1 -0
  102. package/dist/agent-farm/utils/agent-names.js +140 -0
  103. package/dist/agent-farm/utils/agent-names.js.map +1 -0
  104. package/dist/agent-farm/utils/config.d.ts +1 -1
  105. package/dist/agent-farm/utils/config.d.ts.map +1 -1
  106. package/dist/agent-farm/utils/config.js +16 -16
  107. package/dist/agent-farm/utils/config.js.map +1 -1
  108. package/dist/agent-farm/utils/file-tabs.d.ts +3 -3
  109. package/dist/agent-farm/utils/file-tabs.d.ts.map +1 -1
  110. package/dist/agent-farm/utils/file-tabs.js +9 -9
  111. package/dist/agent-farm/utils/file-tabs.js.map +1 -1
  112. package/dist/agent-farm/utils/index.d.ts +0 -1
  113. package/dist/agent-farm/utils/index.d.ts.map +1 -1
  114. package/dist/agent-farm/utils/index.js +0 -1
  115. package/dist/agent-farm/utils/index.js.map +1 -1
  116. package/dist/agent-farm/utils/message-format.d.ts +17 -0
  117. package/dist/agent-farm/utils/message-format.d.ts.map +1 -0
  118. package/dist/agent-farm/utils/message-format.js +41 -0
  119. package/dist/agent-farm/utils/message-format.js.map +1 -0
  120. package/dist/agent-farm/utils/notifications.d.ts +4 -4
  121. package/dist/agent-farm/utils/notifications.d.ts.map +1 -1
  122. package/dist/agent-farm/utils/notifications.js +18 -18
  123. package/dist/agent-farm/utils/notifications.js.map +1 -1
  124. package/dist/cli.d.ts.map +1 -1
  125. package/dist/cli.js +26 -1
  126. package/dist/cli.js.map +1 -1
  127. package/dist/commands/adopt.d.ts +2 -2
  128. package/dist/commands/adopt.d.ts.map +1 -1
  129. package/dist/commands/adopt.js +13 -15
  130. package/dist/commands/adopt.js.map +1 -1
  131. package/dist/commands/consult/index.d.ts +26 -2
  132. package/dist/commands/consult/index.d.ts.map +1 -1
  133. package/dist/commands/consult/index.js +296 -83
  134. package/dist/commands/consult/index.js.map +1 -1
  135. package/dist/commands/consult/metrics.d.ts +90 -0
  136. package/dist/commands/consult/metrics.d.ts.map +1 -0
  137. package/dist/commands/consult/metrics.js +203 -0
  138. package/dist/commands/consult/metrics.js.map +1 -0
  139. package/dist/commands/consult/stats.d.ts +18 -0
  140. package/dist/commands/consult/stats.d.ts.map +1 -0
  141. package/dist/commands/consult/stats.js +150 -0
  142. package/dist/commands/consult/stats.js.map +1 -0
  143. package/dist/commands/consult/usage-extractor.d.ts +38 -0
  144. package/dist/commands/consult/usage-extractor.d.ts.map +1 -0
  145. package/dist/commands/consult/usage-extractor.js +99 -0
  146. package/dist/commands/consult/usage-extractor.js.map +1 -0
  147. package/dist/commands/doctor.d.ts.map +1 -1
  148. package/dist/commands/doctor.js +11 -9
  149. package/dist/commands/doctor.js.map +1 -1
  150. package/dist/commands/import.js +4 -4
  151. package/dist/commands/import.js.map +1 -1
  152. package/dist/commands/init.d.ts +2 -2
  153. package/dist/commands/init.d.ts.map +1 -1
  154. package/dist/commands/init.js +13 -15
  155. package/dist/commands/init.js.map +1 -1
  156. package/dist/commands/porch/index.d.ts +6 -6
  157. package/dist/commands/porch/index.d.ts.map +1 -1
  158. package/dist/commands/porch/index.js +37 -37
  159. package/dist/commands/porch/index.js.map +1 -1
  160. package/dist/commands/porch/next.d.ts +1 -1
  161. package/dist/commands/porch/next.d.ts.map +1 -1
  162. package/dist/commands/porch/next.js +86 -92
  163. package/dist/commands/porch/next.js.map +1 -1
  164. package/dist/commands/porch/notify.d.ts +11 -0
  165. package/dist/commands/porch/notify.d.ts.map +1 -0
  166. package/dist/commands/porch/notify.js +30 -0
  167. package/dist/commands/porch/notify.js.map +1 -0
  168. package/dist/commands/porch/plan.d.ts +1 -1
  169. package/dist/commands/porch/plan.d.ts.map +1 -1
  170. package/dist/commands/porch/plan.js +3 -3
  171. package/dist/commands/porch/plan.js.map +1 -1
  172. package/dist/commands/porch/prompts.d.ts +10 -1
  173. package/dist/commands/porch/prompts.d.ts.map +1 -1
  174. package/dist/commands/porch/prompts.js +59 -35
  175. package/dist/commands/porch/prompts.js.map +1 -1
  176. package/dist/commands/porch/protocol.d.ts +1 -1
  177. package/dist/commands/porch/protocol.d.ts.map +1 -1
  178. package/dist/commands/porch/protocol.js +8 -8
  179. package/dist/commands/porch/protocol.js.map +1 -1
  180. package/dist/commands/porch/state.d.ts +6 -6
  181. package/dist/commands/porch/state.d.ts.map +1 -1
  182. package/dist/commands/porch/state.js +14 -12
  183. package/dist/commands/porch/state.js.map +1 -1
  184. package/dist/commands/update.d.ts.map +1 -1
  185. package/dist/commands/update.js +10 -11
  186. package/dist/commands/update.js.map +1 -1
  187. package/dist/lib/github.d.ts +81 -0
  188. package/dist/lib/github.d.ts.map +1 -0
  189. package/dist/lib/github.js +141 -0
  190. package/dist/lib/github.js.map +1 -0
  191. package/dist/lib/scaffold.d.ts +13 -21
  192. package/dist/lib/scaffold.d.ts.map +1 -1
  193. package/dist/lib/scaffold.js +34 -57
  194. package/dist/lib/scaffold.js.map +1 -1
  195. package/dist/lib/skeleton.d.ts +7 -7
  196. package/dist/lib/skeleton.d.ts.map +1 -1
  197. package/dist/lib/skeleton.js +10 -10
  198. package/dist/lib/skeleton.js.map +1 -1
  199. package/dist/terminal/index.d.ts +14 -0
  200. package/dist/terminal/index.d.ts.map +1 -1
  201. package/dist/terminal/index.js +12 -0
  202. package/dist/terminal/index.js.map +1 -1
  203. package/dist/terminal/pty-manager.d.ts +1 -1
  204. package/dist/terminal/pty-manager.d.ts.map +1 -1
  205. package/dist/terminal/pty-manager.js +10 -7
  206. package/dist/terminal/pty-manager.js.map +1 -1
  207. package/dist/terminal/pty-session.js +3 -3
  208. package/dist/terminal/pty-session.js.map +1 -1
  209. package/dist/terminal/session-manager.d.ts +64 -0
  210. package/dist/terminal/session-manager.d.ts.map +1 -1
  211. package/dist/terminal/session-manager.js +299 -10
  212. package/dist/terminal/session-manager.js.map +1 -1
  213. package/dist/terminal/shellper-client.d.ts +2 -1
  214. package/dist/terminal/shellper-client.d.ts.map +1 -1
  215. package/dist/terminal/shellper-client.js +4 -2
  216. package/dist/terminal/shellper-client.js.map +1 -1
  217. package/dist/terminal/shellper-main.js +33 -4
  218. package/dist/terminal/shellper-main.js.map +1 -1
  219. package/dist/terminal/shellper-process.d.ts +24 -7
  220. package/dist/terminal/shellper-process.d.ts.map +1 -1
  221. package/dist/terminal/shellper-process.js +139 -36
  222. package/dist/terminal/shellper-process.js.map +1 -1
  223. package/dist/terminal/shellper-protocol.d.ts +1 -0
  224. package/dist/terminal/shellper-protocol.d.ts.map +1 -1
  225. package/dist/terminal/shellper-protocol.js.map +1 -1
  226. package/package.json +4 -1
  227. package/skeleton/.claude/skills/af/SKILL.md +7 -7
  228. package/skeleton/.claude/skills/consult/SKILL.md +1 -1
  229. package/skeleton/builders.md +2 -2
  230. package/skeleton/maintain/.gitkeep +1 -1
  231. package/skeleton/porch/prompts/specify.md +1 -1
  232. package/skeleton/protocols/bugfix/prompts/pr.md +15 -4
  233. package/skeleton/protocols/experiment/protocol.md +17 -17
  234. package/skeleton/protocols/maintain/prompts/audit.md +2 -2
  235. package/skeleton/protocols/maintain/prompts/sync.md +1 -1
  236. package/skeleton/protocols/maintain/prompts/verify.md +1 -1
  237. package/skeleton/protocols/maintain/protocol.md +8 -9
  238. package/skeleton/protocols/maintain/templates/maintenance-run.md +2 -2
  239. package/skeleton/protocols/spir/protocol.json +5 -5
  240. package/skeleton/protocols/spir/protocol.md +8 -8
  241. package/skeleton/protocols/tick/protocol.md +31 -31
  242. package/skeleton/resources/commands/agent-farm.md +14 -14
  243. package/skeleton/resources/commands/codev.md +0 -1
  244. package/skeleton/resources/commands/consult.md +3 -3
  245. package/skeleton/resources/spikes.md +3 -3
  246. package/skeleton/resources/workflow-reference.md +14 -14
  247. package/skeleton/roles/architect.md +25 -25
  248. package/skeleton/roles/builder.md +1 -1
  249. package/skeleton/roles/consultant.md +6 -0
  250. package/skeleton/templates/AGENTS.md +5 -5
  251. package/skeleton/templates/CLAUDE.md +5 -5
  252. package/skeleton/templates/lifecycle.md +9 -9
  253. package/templates/open.html +19 -16
  254. package/templates/tower.html +54 -94
  255. package/templates/vendor/marked.min.js +6 -0
  256. package/templates/vendor/prism-bash.min.js +1 -0
  257. package/templates/vendor/prism-css.min.js +1 -0
  258. package/templates/vendor/prism-javascript.min.js +1 -0
  259. package/templates/vendor/prism-json.min.js +1 -0
  260. package/templates/vendor/prism-markdown.min.js +1 -0
  261. package/templates/vendor/prism-markup.min.js +1 -0
  262. package/templates/vendor/prism-python.min.js +1 -0
  263. package/templates/vendor/prism-tomorrow.min.css +1 -0
  264. package/templates/vendor/prism-typescript.min.js +1 -0
  265. package/templates/vendor/prism-yaml.min.js +1 -0
  266. package/templates/vendor/prism.min.js +1 -0
  267. package/templates/vendor/purify.min.js +3 -0
  268. package/dashboard/dist/assets/index-4n9zpWLY.css +0 -32
  269. package/dashboard/dist/assets/index-b38SaXk5.js +0 -136
  270. package/dashboard/dist/assets/index-b38SaXk5.js.map +0 -1
  271. package/dist/agent-farm/hq-connector.d.ts +0 -19
  272. package/dist/agent-farm/hq-connector.d.ts.map +0 -1
  273. package/dist/agent-farm/hq-connector.js +0 -351
  274. package/dist/agent-farm/hq-connector.js.map +0 -1
  275. package/dist/agent-farm/utils/deps.d.ts +0 -51
  276. package/dist/agent-farm/utils/deps.d.ts.map +0 -1
  277. package/dist/agent-farm/utils/deps.js +0 -162
  278. package/dist/agent-farm/utils/deps.js.map +0 -1
  279. package/dist/agent-farm/utils/gate-status.d.ts +0 -16
  280. package/dist/agent-farm/utils/gate-status.d.ts.map +0 -1
  281. package/dist/agent-farm/utils/gate-status.js +0 -79
  282. package/dist/agent-farm/utils/gate-status.js.map +0 -1
  283. package/dist/agent-farm/utils/gate-watcher.d.ts +0 -38
  284. package/dist/agent-farm/utils/gate-watcher.d.ts.map +0 -1
  285. package/dist/agent-farm/utils/gate-watcher.js +0 -122
  286. package/dist/agent-farm/utils/gate-watcher.js.map +0 -1
  287. package/dist/agent-farm/utils/session.d.ts +0 -32
  288. package/dist/agent-farm/utils/session.d.ts.map +0 -1
  289. package/dist/agent-farm/utils/session.js +0 -57
  290. package/dist/agent-farm/utils/session.js.map +0 -1
  291. package/dist/lib/projectlist-parser.d.ts +0 -70
  292. package/dist/lib/projectlist-parser.d.ts.map +0 -1
  293. package/dist/lib/projectlist-parser.js +0 -200
  294. package/dist/lib/projectlist-parser.js.map +0 -1
  295. package/skeleton/templates/projectlist-archive.md +0 -21
  296. package/skeleton/templates/projectlist.md +0 -147
  297. package/templates/dashboard/css/dialogs.css +0 -149
  298. package/templates/dashboard/css/files.css +0 -558
  299. package/templates/dashboard/css/layout.css +0 -133
  300. package/templates/dashboard/css/projects.css +0 -501
  301. package/templates/dashboard/css/statusbar.css +0 -23
  302. package/templates/dashboard/css/tabs.css +0 -314
  303. package/templates/dashboard/css/utilities.css +0 -50
  304. package/templates/dashboard/css/variables.css +0 -45
  305. package/templates/dashboard/index.html +0 -149
  306. package/templates/dashboard/js/dialogs.js +0 -368
  307. package/templates/dashboard/js/files.js +0 -448
  308. package/templates/dashboard/js/main.js +0 -476
  309. package/templates/dashboard/js/projects.js +0 -544
  310. package/templates/dashboard/js/state.js +0 -91
  311. package/templates/dashboard/js/tabs.js +0 -518
  312. package/templates/dashboard/js/utils.js +0 -191
@@ -1,448 +0,0 @@
1
- // File Tree Browser and Search (Spec 0055, 0058)
2
-
3
- // Auto-refresh interval (5 seconds)
4
- const FILES_POLL_INTERVAL = 5000;
5
- let filesLastHash = null;
6
- let filesPollTimer = null;
7
-
8
- // Start auto-polling for file changes
9
- function startFilesPolling() {
10
- if (filesPollTimer) return; // Already polling
11
- filesPollTimer = setInterval(checkFilesForChanges, FILES_POLL_INTERVAL);
12
- }
13
-
14
- // Stop auto-polling
15
- function stopFilesPolling() {
16
- if (filesPollTimer) {
17
- clearInterval(filesPollTimer);
18
- filesPollTimer = null;
19
- }
20
- }
21
-
22
- // Check if files have changed and refresh if needed
23
- async function checkFilesForChanges() {
24
- try {
25
- const response = await fetch(apiUrl(`api/files/hash?t=${Date.now()}`));
26
- if (!response.ok) return;
27
-
28
- const data = await response.json();
29
- if (filesLastHash === null) {
30
- filesLastHash = data.hash;
31
- } else if (data.hash !== filesLastHash) {
32
- filesLastHash = data.hash;
33
- await loadFilesTree();
34
- rerenderFilesBrowser();
35
- }
36
- } catch (err) {
37
- // Ignore errors - server may be restarting
38
- }
39
- }
40
-
41
- // Load the file tree from the API
42
- async function loadFilesTree() {
43
- try {
44
- // Add cache-busting param to ensure fresh data
45
- const response = await fetch(apiUrl(`api/files?t=${Date.now()}`));
46
- if (!response.ok) {
47
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
48
- }
49
- filesTreeData = await response.json();
50
- filesTreeError = null;
51
- filesTreeLoaded = true;
52
- filesTreeFlat = flattenFilesTree(filesTreeData);
53
- } catch (err) {
54
- console.error('Failed to load files tree:', err);
55
- filesTreeError = 'Could not load file tree: ' + err.message;
56
- filesTreeData = [];
57
- filesTreeFlat = [];
58
- }
59
- }
60
-
61
- // Load files tree if not already loaded
62
- async function loadFilesTreeIfNeeded() {
63
- if (!filesTreeLoaded) {
64
- await loadFilesTree();
65
- }
66
- }
67
-
68
- // Flatten the file tree into a searchable array
69
- function flattenFilesTree(nodes, result = []) {
70
- for (const node of nodes) {
71
- if (node.type === 'file') {
72
- result.push({ name: node.name, path: node.path });
73
- } else if (node.children) {
74
- flattenFilesTree(node.children, result);
75
- }
76
- }
77
- return result;
78
- }
79
-
80
- // Search files with relevance sorting
81
- function searchFiles(query) {
82
- if (!query) return [];
83
- const q = query.toLowerCase();
84
-
85
- const matches = filesTreeFlat.filter(f =>
86
- f.path.toLowerCase().includes(q)
87
- );
88
-
89
- matches.sort((a, b) => {
90
- const aName = a.name.toLowerCase();
91
- const bName = b.name.toLowerCase();
92
- const aPath = a.path.toLowerCase();
93
- const bPath = b.path.toLowerCase();
94
-
95
- if (aName === q && bName !== q) return -1;
96
- if (bName === q && aName !== q) return 1;
97
- if (aName.startsWith(q) && !bName.startsWith(q)) return -1;
98
- if (bName.startsWith(q) && !aName.startsWith(q)) return 1;
99
- if (aName.includes(q) && !bName.includes(q)) return -1;
100
- if (bName.includes(q) && !aName.includes(q)) return 1;
101
- return aPath.localeCompare(bPath);
102
- });
103
-
104
- return matches.slice(0, 15);
105
- }
106
-
107
- // Get file icon based on extension
108
- function getFileIcon(filename) {
109
- const ext = filename.split('.').pop().toLowerCase();
110
- const iconMap = {
111
- 'js': '📜', 'ts': '📜', 'jsx': '⚛️', 'tsx': '⚛️',
112
- 'json': '{}', 'md': '📝', 'html': '🌐', 'css': '🎨',
113
- 'py': '🐍', 'sh': '⚙️', 'bash': '⚙️', 'yml': '⚙️', 'yaml': '⚙️',
114
- 'png': '🖼️', 'jpg': '🖼️', 'jpeg': '🖼️', 'gif': '🖼️', 'svg': '🖼️',
115
- };
116
- return iconMap[ext] || '📄';
117
- }
118
-
119
- // Render tree nodes recursively
120
- function renderTreeNodes(nodes, depth) {
121
- if (!nodes || nodes.length === 0) return '';
122
-
123
- return nodes.map(node => {
124
- const indent = depth * 16;
125
- const isExpanded = filesTreeExpanded.has(node.path);
126
- const jsPath = escapeJsString(node.path);
127
-
128
- if (node.type === 'dir') {
129
- const icon = isExpanded ? '▼' : '▶';
130
- const childrenHtml = node.children && node.children.length > 0
131
- ? `<div class="tree-children ${isExpanded ? '' : 'collapsed'}" data-path="${escapeHtml(node.path)}">${renderTreeNodes(node.children, depth + 1)}</div>`
132
- : '';
133
-
134
- return `
135
- <div class="tree-item" data-type="dir" data-path="${escapeHtml(node.path)}" style="padding-left: ${indent + 8}px;" onclick="toggleFolder('${jsPath}')">
136
- <span class="tree-item-icon folder-toggle">${icon}</span>
137
- <span class="tree-item-name">${escapeHtml(node.name)}</span>
138
- </div>
139
- ${childrenHtml}
140
- `;
141
- } else {
142
- return `
143
- <div class="tree-item" data-type="file" data-path="${escapeHtml(node.path)}" style="padding-left: ${indent + 8}px;" onclick="openFileFromTree('${jsPath}')">
144
- <span class="tree-item-icon">${getFileIcon(node.name)}</span>
145
- <span class="tree-item-name">${escapeHtml(node.name)}</span>
146
- </div>
147
- `;
148
- }
149
- }).join('');
150
- }
151
-
152
- // Toggle folder expanded/collapsed state
153
- function toggleFolder(path) {
154
- if (filesTreeExpanded.has(path)) {
155
- filesTreeExpanded.delete(path);
156
- } else {
157
- filesTreeExpanded.add(path);
158
- }
159
- rerenderFilesBrowser();
160
- }
161
-
162
- // Re-render file browser in current context
163
- function rerenderFilesBrowser() {
164
- if (activeTabId === 'dashboard') {
165
- const filesContentEl = document.getElementById('dashboard-files-content');
166
- if (filesContentEl) {
167
- filesContentEl.innerHTML = filesSearchQuery
168
- ? renderFilesSearchResults()
169
- : renderDashboardFilesBrowserWithWrapper();
170
- }
171
- }
172
- }
173
-
174
- // Wrapper for file browser
175
- function renderDashboardFilesBrowserWithWrapper() {
176
- return `<div class="dashboard-files-list" id="dashboard-files-list">${renderDashboardFilesBrowser()}</div>`;
177
- }
178
-
179
- // Render compact file browser for dashboard
180
- function renderDashboardFilesBrowser() {
181
- if (filesTreeError) {
182
- return `<div class="dashboard-empty-state">${escapeHtml(filesTreeError)}</div>`;
183
- }
184
-
185
- if (!filesTreeLoaded || filesTreeData.length === 0) {
186
- return '<div class="dashboard-empty-state">Loading files...</div>';
187
- }
188
-
189
- return renderTreeNodes(filesTreeData, 0);
190
- }
191
-
192
- // Collapse all folders
193
- function collapseAllFolders() {
194
- filesTreeExpanded.clear();
195
- rerenderFilesBrowser();
196
- }
197
-
198
- // Expand all folders
199
- function expandAllFolders() {
200
- function collectPaths(nodes) {
201
- for (const node of nodes) {
202
- if (node.type === 'dir') {
203
- filesTreeExpanded.add(node.path);
204
- if (node.children) {
205
- collectPaths(node.children);
206
- }
207
- }
208
- }
209
- }
210
- collectPaths(filesTreeData);
211
- rerenderFilesBrowser();
212
- }
213
-
214
- // Refresh files tree
215
- async function refreshFilesTree() {
216
- await loadFilesTree();
217
- rerenderFilesBrowser();
218
- showToast('Files refreshed', 'success');
219
- }
220
-
221
- // Open file from tree click
222
- // Uses shared openFileTab from utils.js (Maintenance Run 0004)
223
- async function openFileFromTree(filePath) {
224
- await openFileTab(filePath, { showSwitchToast: false });
225
- }
226
-
227
- // ========================================
228
- // File Search Functions (Spec 0058)
229
- // ========================================
230
-
231
- // Debounced search input handler for Files column
232
- function onFilesSearchInput(value) {
233
- clearTimeout(filesSearchDebounceTimer);
234
- filesSearchDebounceTimer = setTimeout(() => {
235
- filesSearchQuery = value;
236
- filesSearchResults = searchFiles(value);
237
- filesSearchIndex = 0;
238
- rerenderFilesSearch();
239
- }, 100);
240
- }
241
-
242
- // Clear files search and restore tree view
243
- function clearFilesSearch() {
244
- filesSearchQuery = '';
245
- filesSearchResults = [];
246
- filesSearchIndex = 0;
247
- const input = document.getElementById('files-search-input');
248
- if (input) {
249
- input.value = '';
250
- }
251
- rerenderFilesSearch();
252
- }
253
-
254
- // Re-render the files search area
255
- function rerenderFilesSearch() {
256
- const filesContentEl = document.getElementById('dashboard-files-content');
257
- if (filesContentEl) {
258
- filesContentEl.innerHTML = filesSearchQuery
259
- ? renderFilesSearchResults()
260
- : renderDashboardFilesBrowserWithWrapper();
261
- }
262
- const clearBtn = document.querySelector('.files-search-clear');
263
- if (clearBtn) {
264
- clearBtn.classList.toggle('hidden', !filesSearchQuery);
265
- }
266
- }
267
-
268
- // Render search results for Files column
269
- function renderFilesSearchResults() {
270
- if (!filesSearchResults.length) {
271
- return '<div class="dashboard-empty-state">No files found</div>';
272
- }
273
-
274
- return `<div class="files-search-results">${filesSearchResults.map((file, index) =>
275
- renderSearchResult(file, index, index === filesSearchIndex, filesSearchQuery, 'files')
276
- ).join('')}</div>`;
277
- }
278
-
279
- // Highlight matching text in search results
280
- function highlightMatch(text, query) {
281
- if (!query) return escapeHtml(text);
282
- const q = query.toLowerCase();
283
- const t = text.toLowerCase();
284
- const idx = t.indexOf(q);
285
- if (idx === -1) return escapeHtml(text);
286
-
287
- return escapeHtml(text.substring(0, idx)) +
288
- '<span class="files-search-highlight">' + escapeHtml(text.substring(idx, idx + query.length)) + '</span>' +
289
- escapeHtml(text.substring(idx + query.length));
290
- }
291
-
292
- // Render a single search result
293
- function renderSearchResult(file, index, isSelected, query, context) {
294
- const classPrefix = context === 'palette' ? 'file-palette' : 'files-search';
295
- const jsPath = escapeJsString(file.path);
296
-
297
- return `
298
- <div class="${classPrefix}-result ${isSelected ? 'selected' : ''}"
299
- data-index="${index}"
300
- onclick="openFileFromSearch('${jsPath}', '${context}')">
301
- <div class="${classPrefix}-result-name">${highlightMatch(file.name, query)}</div>
302
- <div class="${classPrefix}-result-path">${highlightMatch(file.path, query)}</div>
303
- </div>
304
- `;
305
- }
306
-
307
- // Keyboard handler for Files search input
308
- function onFilesSearchKeydown(event) {
309
- if (!filesSearchResults.length) {
310
- if (event.key === 'Escape') {
311
- clearFilesSearch();
312
- event.target.blur();
313
- }
314
- return;
315
- }
316
-
317
- if (event.key === 'ArrowDown') {
318
- event.preventDefault();
319
- filesSearchIndex = Math.min(filesSearchIndex + 1, filesSearchResults.length - 1);
320
- rerenderFilesSearch();
321
- scrollSelectedIntoView('files');
322
- } else if (event.key === 'ArrowUp') {
323
- event.preventDefault();
324
- filesSearchIndex = Math.max(filesSearchIndex - 1, 0);
325
- rerenderFilesSearch();
326
- scrollSelectedIntoView('files');
327
- } else if (event.key === 'Enter') {
328
- event.preventDefault();
329
- if (filesSearchResults[filesSearchIndex]) {
330
- openFileFromSearch(filesSearchResults[filesSearchIndex].path, 'files');
331
- }
332
- } else if (event.key === 'Escape') {
333
- clearFilesSearch();
334
- event.target.blur();
335
- }
336
- }
337
-
338
- // Scroll selected result into view
339
- function scrollSelectedIntoView(context) {
340
- const selector = context === 'palette'
341
- ? '.file-palette-result.selected'
342
- : '.files-search-result.selected';
343
- const selected = document.querySelector(selector);
344
- if (selected) {
345
- selected.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
346
- }
347
- }
348
-
349
- // Open file from search result
350
- function openFileFromSearch(filePath, context) {
351
- const existingTab = tabs.find(t => t.type === 'file' && t.path === filePath);
352
- if (existingTab) {
353
- selectTab(existingTab.id);
354
- refreshFileTab(existingTab.id);
355
- } else {
356
- openFileFromTree(filePath);
357
- }
358
-
359
- if (context === 'palette') {
360
- closePalette();
361
- } else {
362
- clearFilesSearch();
363
- }
364
- }
365
-
366
- // ========================================
367
- // Cmd+P Palette Functions (Spec 0058)
368
- // ========================================
369
-
370
- // Open the file search palette
371
- function openPalette() {
372
- paletteOpen = true;
373
- paletteQuery = '';
374
- paletteResults = [];
375
- paletteIndex = 0;
376
- document.getElementById('file-palette').classList.remove('hidden');
377
- const input = document.getElementById('palette-input');
378
- input.value = '';
379
- input.focus();
380
- rerenderPaletteResults();
381
- }
382
-
383
- // Close the file search palette
384
- function closePalette() {
385
- paletteOpen = false;
386
- paletteQuery = '';
387
- paletteResults = [];
388
- paletteIndex = 0;
389
- document.getElementById('file-palette').classList.add('hidden');
390
- }
391
-
392
- // Debounced palette input handler
393
- function onPaletteInput(value) {
394
- clearTimeout(paletteDebounceTimer);
395
- paletteDebounceTimer = setTimeout(() => {
396
- paletteQuery = value;
397
- paletteResults = searchFiles(value);
398
- paletteIndex = 0;
399
- rerenderPaletteResults();
400
- }, 100);
401
- }
402
-
403
- // Re-render palette results
404
- function rerenderPaletteResults() {
405
- const resultsEl = document.getElementById('palette-results');
406
- if (!resultsEl) return;
407
-
408
- if (!paletteQuery) {
409
- resultsEl.innerHTML = '<div class="file-palette-empty">Type to search files...</div>';
410
- return;
411
- }
412
-
413
- if (!paletteResults.length) {
414
- resultsEl.innerHTML = '<div class="file-palette-empty">No files found</div>';
415
- return;
416
- }
417
-
418
- resultsEl.innerHTML = paletteResults.map((file, index) =>
419
- renderSearchResult(file, index, index === paletteIndex, paletteQuery, 'palette')
420
- ).join('');
421
- }
422
-
423
- // Keyboard handler for palette input
424
- function onPaletteKeydown(event) {
425
- if (event.key === 'Escape') {
426
- closePalette();
427
- return;
428
- }
429
-
430
- if (!paletteResults.length) return;
431
-
432
- if (event.key === 'ArrowDown') {
433
- event.preventDefault();
434
- paletteIndex = Math.min(paletteIndex + 1, paletteResults.length - 1);
435
- rerenderPaletteResults();
436
- scrollSelectedIntoView('palette');
437
- } else if (event.key === 'ArrowUp') {
438
- event.preventDefault();
439
- paletteIndex = Math.max(paletteIndex - 1, 0);
440
- rerenderPaletteResults();
441
- scrollSelectedIntoView('palette');
442
- } else if (event.key === 'Enter') {
443
- event.preventDefault();
444
- if (paletteResults[paletteIndex]) {
445
- openFileFromSearch(paletteResults[paletteIndex].path, 'palette');
446
- }
447
- }
448
- }