@starlove/orbit 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/Dockerfile +10 -8
  2. package/README.md +146 -164
  3. package/dist/full/csp.txt +1 -0
  4. package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-subset.woff2 +0 -0
  5. package/dist/full/fonts/JetBrains_Mono/README.txt +5 -0
  6. package/dist/full/fonts/Mona_Sans/MonaSans-subset.woff2 +0 -0
  7. package/{public/fonts/Open_Sans → dist/full/fonts/Mona_Sans}/OFL.txt +93 -93
  8. package/dist/full/fonts/Mona_Sans/README.txt +10 -0
  9. package/{public/fonts/JetBrains_Mono → dist/full/fonts/Newsreader}/OFL.txt +93 -93
  10. package/dist/full/fonts/Newsreader/README.txt +8 -0
  11. package/dist/full/fonts/Newsreader/newsreader.woff2 +0 -0
  12. package/dist/full/index.html +36 -653
  13. package/dist/full/js/app.BmuponPJ.js +32 -0
  14. package/dist/full/js/app.BmuponPJ.js.map +1 -0
  15. package/dist/full/js/chunk.1fJGQGbW.js +2 -0
  16. package/dist/full/js/chunk.1fJGQGbW.js.map +1 -0
  17. package/dist/full/js/chunk.5D7JO2zp.js +2 -0
  18. package/dist/full/js/chunk.5D7JO2zp.js.map +1 -0
  19. package/dist/full/js/chunk.BrNn_D79.js +2 -0
  20. package/dist/full/js/chunk.BrNn_D79.js.map +1 -0
  21. package/dist/full/js/chunk.CokJXIqM.js +2 -0
  22. package/dist/full/js/chunk.CokJXIqM.js.map +1 -0
  23. package/dist/full/js/chunk.D_Haqy6R.js +2 -0
  24. package/dist/full/js/chunk.D_Haqy6R.js.map +1 -0
  25. package/dist/full/js/chunk.RO0jsH6I.js +15 -0
  26. package/dist/full/js/chunk.RO0jsH6I.js.map +1 -0
  27. package/dist/full/js/chunk.dqWOEtBM.js +2 -0
  28. package/dist/full/js/chunk.dqWOEtBM.js.map +1 -0
  29. package/dist/full/js/warm.f260bbbc.js +15 -0
  30. package/dist/full/orbits-favicon.png +0 -0
  31. package/dist/full/orbits-logo-bg-wide.png +0 -0
  32. package/dist/full/orbits-logo-bg.png +0 -0
  33. package/dist/full/orbits-logo.png +0 -0
  34. package/dist/full/styles.2b154ffe.css +1 -0
  35. package/dist/full/vendor/starlove-ui/theme-init.js +66 -0
  36. package/dist/full/version.json +2 -2
  37. package/docs/AGENT_GUIDE.md +114 -0
  38. package/docs/UPDATING.md +249 -64
  39. package/lib/adapters/indexeddb/blobs.d.ts +3 -0
  40. package/lib/adapters/indexeddb/blobs.js +54 -0
  41. package/lib/adapters/indexeddb/database.d.ts +60 -0
  42. package/lib/adapters/indexeddb/database.js +126 -0
  43. package/lib/adapters/indexeddb/index.d.ts +5 -0
  44. package/lib/adapters/indexeddb/index.js +3 -0
  45. package/lib/adapters/indexeddb/locks.d.ts +14 -0
  46. package/lib/adapters/indexeddb/locks.js +40 -0
  47. package/lib/adapters/indexeddb/store.d.ts +40 -0
  48. package/lib/adapters/indexeddb/store.js +424 -0
  49. package/lib/adapters/indexeddb/tables.d.ts +43 -0
  50. package/lib/adapters/indexeddb/tables.js +127 -0
  51. package/lib/adapters/memory/blobs.d.ts +3 -0
  52. package/lib/adapters/memory/blobs.js +44 -0
  53. package/lib/adapters/memory/board.d.ts +41 -0
  54. package/lib/adapters/memory/board.js +521 -0
  55. package/lib/adapters/memory/index.d.ts +2 -0
  56. package/lib/adapters/memory/index.js +2 -0
  57. package/lib/adapters/memory/search.d.ts +6 -0
  58. package/lib/adapters/memory/search.js +30 -0
  59. package/lib/adapters/memory/store.d.ts +34 -0
  60. package/lib/adapters/memory/store.js +266 -0
  61. package/lib/adapters/sqlite/backups.d.ts +53 -0
  62. package/lib/adapters/sqlite/backups.js +232 -0
  63. package/lib/adapters/sqlite/blobs.d.ts +14 -0
  64. package/lib/adapters/sqlite/blobs.js +109 -0
  65. package/lib/adapters/sqlite/board.d.ts +77 -0
  66. package/lib/adapters/sqlite/board.js +328 -0
  67. package/lib/adapters/sqlite/database.d.ts +67 -0
  68. package/lib/adapters/sqlite/database.js +285 -0
  69. package/lib/adapters/sqlite/index.d.ts +3 -0
  70. package/lib/adapters/sqlite/index.js +2 -0
  71. package/lib/adapters/sqlite/lock.d.ts +11 -0
  72. package/lib/adapters/sqlite/lock.js +34 -0
  73. package/lib/adapters/sqlite/records.d.ts +54 -0
  74. package/lib/adapters/sqlite/records.js +546 -0
  75. package/lib/adapters/sqlite/schema.d.ts +54 -0
  76. package/lib/adapters/sqlite/schema.js +276 -0
  77. package/lib/adapters/sqlite/store.d.ts +39 -0
  78. package/lib/adapters/sqlite/store.js +385 -0
  79. package/lib/browser/in-page.d.ts +31 -0
  80. package/lib/browser/in-page.js +46 -0
  81. package/lib/browser/old-preview.d.ts +13 -0
  82. package/lib/browser/old-preview.js +80 -0
  83. package/lib/browser/preview-board.d.ts +8 -0
  84. package/lib/browser/preview-board.js +69 -0
  85. package/lib/cli/main.d.ts +7 -0
  86. package/lib/cli/main.js +343 -0
  87. package/lib/cli/orbit.d.ts +8 -0
  88. package/lib/cli/orbit.js +25 -0
  89. package/lib/client/http.d.ts +38 -0
  90. package/lib/client/http.js +334 -0
  91. package/lib/client/local.d.ts +26 -0
  92. package/lib/client/local.js +190 -0
  93. package/lib/client/object-url.d.ts +8 -0
  94. package/lib/client/object-url.js +21 -0
  95. package/lib/client/types.d.ts +268 -0
  96. package/lib/client/types.js +8 -0
  97. package/lib/commands/agent-tools.d.ts +31 -0
  98. package/lib/commands/agent-tools.js +100 -0
  99. package/lib/commands/index.d.ts +56 -0
  100. package/lib/commands/index.js +298 -0
  101. package/lib/commands/parse.d.ts +73 -0
  102. package/lib/commands/parse.js +231 -0
  103. package/lib/commands/present.d.ts +134 -0
  104. package/lib/commands/present.js +198 -0
  105. package/lib/commands/session.d.ts +85 -0
  106. package/lib/commands/session.js +138 -0
  107. package/lib/commands/verbs.d.ts +35 -0
  108. package/lib/commands/verbs.js +842 -0
  109. package/lib/core/actors.d.ts +18 -0
  110. package/lib/core/actors.js +45 -0
  111. package/lib/core/agent.d.ts +128 -0
  112. package/lib/core/agent.js +323 -0
  113. package/lib/core/boards.d.ts +113 -0
  114. package/lib/core/boards.js +288 -0
  115. package/lib/core/bootstrap.d.ts +47 -0
  116. package/lib/core/bootstrap.js +100 -0
  117. package/lib/core/bytes.d.ts +10 -0
  118. package/lib/core/bytes.js +52 -0
  119. package/lib/core/card-paths.d.ts +25 -0
  120. package/lib/core/card-paths.js +44 -0
  121. package/lib/core/context.d.ts +60 -0
  122. package/lib/core/context.js +42 -0
  123. package/lib/core/cross-board.d.ts +81 -0
  124. package/lib/core/cross-board.js +228 -0
  125. package/lib/core/describe.d.ts +21 -0
  126. package/lib/core/describe.js +81 -0
  127. package/lib/core/errors.d.ts +159 -0
  128. package/lib/core/errors.js +160 -0
  129. package/lib/core/files.d.ts +79 -0
  130. package/lib/core/files.js +262 -0
  131. package/lib/core/history.d.ts +20 -0
  132. package/lib/core/history.js +53 -0
  133. package/lib/core/image-types.d.ts +16 -0
  134. package/lib/core/image-types.js +36 -0
  135. package/lib/core/model.d.ts +263 -0
  136. package/lib/core/model.js +34 -0
  137. package/lib/core/nebula-link.d.ts +14 -0
  138. package/lib/core/nebula-link.js +39 -0
  139. package/lib/core/relations.d.ts +58 -0
  140. package/lib/core/relations.js +112 -0
  141. package/lib/core/search.d.ts +38 -0
  142. package/lib/core/search.js +92 -0
  143. package/lib/core/sessions.d.ts +44 -0
  144. package/lib/core/sessions.js +158 -0
  145. package/lib/core/snapshot-schema.d.ts +295 -0
  146. package/lib/core/snapshot-schema.js +82 -0
  147. package/lib/core/snapshots.d.ts +75 -0
  148. package/lib/core/snapshots.js +409 -0
  149. package/lib/core/states.d.ts +25 -0
  150. package/lib/core/states.js +126 -0
  151. package/lib/core/text.d.ts +40 -0
  152. package/lib/core/text.js +113 -0
  153. package/lib/core/tickets.d.ts +69 -0
  154. package/lib/core/tickets.js +311 -0
  155. package/lib/core/trello.d.ts +17 -0
  156. package/lib/core/trello.js +269 -0
  157. package/lib/core/verdicts.d.ts +28 -0
  158. package/lib/core/verdicts.js +92 -0
  159. package/lib/core/views.d.ts +95 -0
  160. package/lib/core/views.js +186 -0
  161. package/lib/http/app.d.ts +46 -0
  162. package/lib/http/app.js +491 -0
  163. package/lib/mcp-server.d.ts +10 -0
  164. package/lib/mcp-server.js +120 -0
  165. package/lib/node/assets.d.ts +7 -0
  166. package/lib/node/assets.js +68 -0
  167. package/lib/node/data-folder.d.ts +21 -0
  168. package/lib/node/data-folder.js +34 -0
  169. package/lib/node/env.d.ts +38 -0
  170. package/lib/node/env.js +49 -0
  171. package/lib/node/host-check.d.ts +24 -0
  172. package/lib/node/host-check.js +53 -0
  173. package/lib/node/host-services.d.ts +9 -0
  174. package/lib/node/host-services.js +150 -0
  175. package/lib/node/local.d.ts +22 -0
  176. package/lib/node/local.js +61 -0
  177. package/lib/node/migrate.d.ts +53 -0
  178. package/lib/node/migrate.js +635 -0
  179. package/lib/node/package.d.ts +7 -0
  180. package/lib/node/package.js +14 -0
  181. package/lib/node/repo-board.d.ts +49 -0
  182. package/lib/node/repo-board.js +245 -0
  183. package/lib/node/serve.d.ts +8 -0
  184. package/lib/node/serve.js +106 -0
  185. package/lib/orbit.d.ts +47 -0
  186. package/lib/orbit.js +44 -0
  187. package/lib/quiet-sqlite-warning.d.ts +1 -0
  188. package/lib/quiet-sqlite-warning.js +18 -0
  189. package/lib/store/blob-path.d.ts +6 -0
  190. package/lib/store/blob-path.js +12 -0
  191. package/lib/store/conformance.d.ts +52 -0
  192. package/lib/store/conformance.js +1449 -0
  193. package/lib/store/search-words.d.ts +10 -0
  194. package/lib/store/search-words.js +19 -0
  195. package/lib/store/types.d.ts +452 -0
  196. package/lib/store/types.js +34 -0
  197. package/llms.txt +63 -0
  198. package/package.json +109 -25
  199. package/src/cli/orbit.js +11 -658
  200. package/src/mcp-server.js +16 -876
  201. package/SKILL-ORBIT.md +0 -151
  202. package/build.mjs +0 -210
  203. package/dist/full/js/app.62905fcb.js +0 -952
  204. package/dist/full/js/app.62905fcb.js.map +0 -7
  205. package/dist/full/styles.4e60d824.css +0 -1
  206. package/docs/AGENT_PROTOCOL.md +0 -424
  207. package/docs/MCP_SETUP.md +0 -54
  208. package/docs/ORBIT_DISPATCH.md +0 -280
  209. package/docs/SS-Orbit-Dark.png +0 -0
  210. package/docs/SS-Orbit-Light.png +0 -0
  211. package/docs/mcp-client.example.json +0 -13
  212. package/docs/setup/orbit-init-wizard.md +0 -174
  213. package/public/apple-touch-icon.png +0 -0
  214. package/public/cursors/live_arrow.cur +0 -0
  215. package/public/cursors/live_link.cur +0 -0
  216. package/public/cursors/live_move.cur +0 -0
  217. package/public/cursors/live_select.cur +0 -0
  218. package/public/cursors/live_unavail.cur +0 -0
  219. package/public/favicon-32x32.png +0 -0
  220. package/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
  221. package/public/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
  222. package/public/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
  223. package/public/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
  224. package/public/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
  225. package/public/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
  226. package/public/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
  227. package/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
  228. package/public/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
  229. package/public/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
  230. package/public/fonts/Chakra_Petch/OFL.txt +0 -93
  231. package/public/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
  232. package/public/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
  233. package/public/fonts/Inter/OFL.txt +0 -93
  234. package/public/fonts/Inter/README.txt +0 -118
  235. package/public/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
  236. package/public/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
  237. package/public/fonts/JetBrains_Mono/README.txt +0 -79
  238. package/public/fonts/OpenRing-Regular.ttf +0 -0
  239. package/public/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
  240. package/public/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
  241. package/public/fonts/Open_Sans/README.txt +0 -100
  242. package/public/fonts/Orbitron/OFL.txt +0 -93
  243. package/public/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
  244. package/public/fonts/Orbitron/README.txt +0 -68
  245. package/public/fonts/Rajdhani/OFL.txt +0 -93
  246. package/public/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
  247. package/public/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
  248. package/public/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
  249. package/public/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
  250. package/public/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
  251. package/public/fonts/runescape-uf.ttf +0 -0
  252. package/public/index.html +0 -769
  253. package/public/js/actor-labels.js +0 -65
  254. package/public/js/api.js +0 -39
  255. package/public/js/app.js +0 -45
  256. package/public/js/artifact-drawer.js +0 -79
  257. package/public/js/board-export.js +0 -161
  258. package/public/js/board-menu.js +0 -374
  259. package/public/js/card-actions.js +0 -545
  260. package/public/js/config.js +0 -20
  261. package/public/js/create-card.js +0 -190
  262. package/public/js/dom.js +0 -19
  263. package/public/js/drawer.js +0 -273
  264. package/public/js/font-preference.js +0 -229
  265. package/public/js/format.js +0 -433
  266. package/public/js/help-menu.js +0 -31
  267. package/public/js/icons.js +0 -16
  268. package/public/js/kanban.js +0 -694
  269. package/public/js/local-backend.js +0 -1015
  270. package/public/js/main.js +0 -161
  271. package/public/js/modal.js +0 -33
  272. package/public/js/motion-preference.js +0 -64
  273. package/public/js/panel.js +0 -58
  274. package/public/js/router.js +0 -134
  275. package/public/js/search.js +0 -56
  276. package/public/js/settings-tabs.js +0 -7
  277. package/public/js/settings.js +0 -1634
  278. package/public/js/sse.js +0 -159
  279. package/public/js/starscape.js +0 -332
  280. package/public/js/state.js +0 -129
  281. package/public/js/text-editing.js +0 -128
  282. package/public/js/theme-preference.js +0 -95
  283. package/public/js/ticket-detail.js +0 -1516
  284. package/public/js/ticket-typeahead.js +0 -49
  285. package/public/js/toast.js +0 -89
  286. package/public/js/topbar-notes.js +0 -155
  287. package/public/js/transport.js +0 -22
  288. package/public/js/typeahead.js +0 -206
  289. package/public/js/unread.js +0 -121
  290. package/public/js/update-check.js +0 -58
  291. package/public/js/url-routes.js +0 -94
  292. package/public/orbits-favicon.png +0 -0
  293. package/public/orbits-logo-bg-wide.png +0 -0
  294. package/public/orbits-logo-bg.png +0 -0
  295. package/public/orbits-logo.png +0 -0
  296. package/public/styles.css +0 -7709
  297. package/src/core/agent.js +0 -387
  298. package/src/core/agents-md.js +0 -109
  299. package/src/core/artifacts.js +0 -149
  300. package/src/core/attachments.js +0 -238
  301. package/src/core/auth.js +0 -85
  302. package/src/core/backups.js +0 -142
  303. package/src/core/board.js +0 -148
  304. package/src/core/boards.js +0 -409
  305. package/src/core/bootstrap.js +0 -170
  306. package/src/core/css-bundle.js +0 -30
  307. package/src/core/db.js +0 -315
  308. package/src/core/delete-board.js +0 -163
  309. package/src/core/dispatch.js +0 -1007
  310. package/src/core/events.js +0 -314
  311. package/src/core/http.js +0 -115
  312. package/src/core/migrate.js +0 -198
  313. package/src/core/paths.js +0 -55
  314. package/src/core/provision-repo-board.js +0 -119
  315. package/src/core/queries.js +0 -246
  316. package/src/core/registry.js +0 -211
  317. package/src/core/relations.js +0 -163
  318. package/src/core/review-verdicts.js +0 -138
  319. package/src/core/router.js +0 -556
  320. package/src/core/search.js +0 -183
  321. package/src/core/seed.js +0 -234
  322. package/src/core/snapshots.js +0 -692
  323. package/src/core/states.js +0 -167
  324. package/src/core/system-picker.js +0 -109
  325. package/src/core/tickets.js +0 -400
  326. package/src/core/util.js +0 -106
  327. package/src/core/version-check.js +0 -154
  328. package/src/mcp/orbit-client.js +0 -287
  329. package/src/server.js +0 -115
@@ -1,183 +0,0 @@
1
- import { labelsForTicket } from "./queries.js";
2
- import { canAccessBoard } from "./auth.js";
3
- import { toFtsQuery } from "./util.js";
4
-
5
- /**
6
- * Search tickets on the resolved board only. The router/MCP layer is
7
- * responsible for resolving which board to search (slug in URL, body, or
8
- * session board); this function never crosses board boundaries or mutates
9
- * shared state.
10
- */
11
- export function searchTickets(args, ctx) {
12
- const { db, board, actor } = ctx;
13
- const q = String(args.q || "").trim();
14
- const limit = Math.min(Number(args.limit || 20), 50);
15
- const mode = normalizeMode(args);
16
- const maxCharsPerField = positiveInt(args.max_chars_per_field ?? args.maxCharsPerField, 0);
17
- const fields = parseFields(args.fields);
18
-
19
- if (!q) return { query: q, mode, results: [] };
20
- if (!canAccessBoard(actor, board)) return { query: q, mode, results: [] };
21
-
22
- const ticketNumber = ticketNumberQuery(q);
23
- const fts = toFtsQuery(q);
24
- let rows = [];
25
-
26
- if (ticketNumber !== null) {
27
- rows = db
28
- .prepare(
29
- `SELECT t.*, s.name AS state_name, s.role AS state_role, b.slug AS board_slug, -1 AS rank
30
- FROM tickets t
31
- JOIN states s ON s.id = t.state_id
32
- JOIN boards b ON b.id = t.board_id
33
- WHERE t.board_id = ? AND t.number = ? AND t.archived_at IS NULL
34
- LIMIT ?`
35
- )
36
- .all(board.id, ticketNumber, limit);
37
- }
38
-
39
- try {
40
- rows = rows.concat(
41
- db
42
- .prepare(
43
- `SELECT t.*, s.name AS state_name, s.role AS state_role, b.slug AS board_slug,
44
- bm25(ticket_fts) AS rank
45
- FROM ticket_fts
46
- JOIN tickets t ON t.id = ticket_fts.ticket_id
47
- JOIN states s ON s.id = t.state_id
48
- JOIN boards b ON b.id = t.board_id
49
- WHERE ticket_fts MATCH ? AND t.board_id = ? AND t.archived_at IS NULL
50
- ORDER BY rank
51
- LIMIT ?`
52
- )
53
- .all(fts, board.id, limit)
54
- );
55
- } catch {
56
- const like = `%${q}%`;
57
- const numberRank = ticketNumber !== null ? "CASE WHEN t.number = ? THEN -1 ELSE 0 END" : "0";
58
- const numberPredicate = ticketNumber !== null ? "OR t.number = ?" : "";
59
- const fallbackArgs = ticketNumber !== null ? [ticketNumber, board.id] : [board.id];
60
- fallbackArgs.push(like, like, like, like, like, like, like, like);
61
- if (ticketNumber !== null) fallbackArgs.push(ticketNumber);
62
- fallbackArgs.push(limit);
63
-
64
- rows = rows.concat(
65
- db
66
- .prepare(
67
- `SELECT DISTINCT t.*, s.name AS state_name, s.role AS state_role, b.slug AS board_slug, ${numberRank} AS rank
68
- FROM tickets t
69
- JOIN states s ON s.id = t.state_id
70
- JOIN boards b ON b.id = t.board_id
71
- LEFT JOIN comments c ON c.ticket_id = t.id
72
- WHERE t.board_id = ? AND t.archived_at IS NULL
73
- AND (t.title LIKE ? OR t.description LIKE ? OR t.ai_plan LIKE ?
74
- OR t.implementation_summary LIKE ? OR t.implementation_updates LIKE ?
75
- OR t.plan_artifact_path LIKE ? OR t.implementation_artifact_path LIKE ? OR c.body LIKE ?
76
- ${numberPredicate})
77
- ORDER BY t.updated_at DESC, t.id ASC
78
- LIMIT ?`
79
- )
80
- .all(...fallbackArgs)
81
- );
82
- }
83
-
84
- rows.sort((a, b) => {
85
- if (a.rank !== b.rank) return a.rank - b.rank;
86
- const byTime = String(b.updated_at).localeCompare(String(a.updated_at));
87
- if (byTime !== 0) return byTime;
88
- return String(a.id).localeCompare(String(b.id));
89
- });
90
-
91
- const seen = new Set();
92
- const deduped = [];
93
- for (const ticket of rows) {
94
- if (seen.has(ticket.id)) continue;
95
- seen.add(ticket.id);
96
- deduped.push(ticket);
97
- if (deduped.length >= limit) break;
98
- }
99
-
100
- const results = deduped.map((ticket) =>
101
- shapeSearchResult(ticket, labelsForTicket(db, ticket.id), { mode, fields, maxCharsPerField })
102
- );
103
-
104
- return { query: q, mode, results };
105
- }
106
-
107
- function normalizeMode(args) {
108
- if (args.include_full === true || args.includeFull === true) return "full";
109
- const mode = String(args.mode || "summary").trim().toLowerCase();
110
- return ["ids", "summary", "full"].includes(mode) ? mode : "summary";
111
- }
112
-
113
- function positiveInt(value, fallback) {
114
- const n = Number(value);
115
- return Number.isInteger(n) && n > 0 ? n : fallback;
116
- }
117
-
118
- function parseFields(fields) {
119
- if (Array.isArray(fields)) return new Set(fields.map(String));
120
- if (typeof fields === "string" && fields.trim()) {
121
- return new Set(fields.split(",").map((field) => field.trim()).filter(Boolean));
122
- }
123
- return null;
124
- }
125
-
126
- function cap(value, maxChars) {
127
- if (!maxChars || typeof value !== "string") return value;
128
- return value.length > maxChars ? value.slice(0, maxChars) : value;
129
- }
130
-
131
- function snippetFor(ticket, maxChars) {
132
- const text = ticket.description || ticket.ai_plan || ticket.implementation_summary || "";
133
- return cap(text, maxChars || 240);
134
- }
135
-
136
- function labelNames(labels) {
137
- return labels.map((label) => label.name);
138
- }
139
-
140
- function pickFields(row, fields) {
141
- if (!fields) return row;
142
- const picked = {};
143
- for (const field of fields) {
144
- if (Object.hasOwn(row, field)) picked[field] = row[field];
145
- }
146
- return picked;
147
- }
148
-
149
- function shapeSearchResult(ticket, labels, { mode, fields, maxCharsPerField }) {
150
- if (mode === "ids") {
151
- return pickFields({ ticket_id: ticket.id, id: ticket.id, number: ticket.number, rank: ticket.rank }, fields);
152
- }
153
- if (mode === "full") {
154
- const full = { ...ticket, labels };
155
- if (maxCharsPerField) {
156
- for (const key of ["description", "ai_plan", "implementation_summary", "implementation_updates"]) {
157
- full[key] = cap(full[key], maxCharsPerField);
158
- }
159
- }
160
- return pickFields(full, fields);
161
- }
162
- return pickFields({
163
- ticket_id: ticket.id,
164
- id: ticket.id,
165
- number: ticket.number,
166
- title: ticket.title,
167
- state_name: ticket.state_name,
168
- state_role: ticket.state_role,
169
- type: ticket.type,
170
- priority: ticket.priority,
171
- parent_ticket_id: ticket.parent_ticket_id,
172
- rank: ticket.rank,
173
- snippet: snippetFor(ticket, maxCharsPerField),
174
- labels: labelNames(labels)
175
- }, fields);
176
- }
177
-
178
- function ticketNumberQuery(q) {
179
- const match = String(q).trim().match(/^#?(\d+)$/);
180
- if (!match) return null;
181
- const number = Number(match[1]);
182
- return Number.isSafeInteger(number) ? number : null;
183
- }
package/src/core/seed.js DELETED
@@ -1,234 +0,0 @@
1
- import { execFileSync } from "node:child_process";
2
- import { existsSync, readFileSync } from "node:fs";
3
- import { basename, join } from "node:path";
4
- import { addComment } from "./queries.js";
5
- import { recordEvent } from "./events.js";
6
- import { id, now, normalizeTicketType, slugify, titleize } from "./util.js";
7
-
8
- /**
9
- * Seed a fresh per-board DB with the universal first-run profile. Caller
10
- * supplies the connection and the repo path the board lives in. Returns the
11
- * new board row, or null if the DB already had a board.
12
- */
13
- export function seedIfEmpty(db, repoPath, options = {}) {
14
- const existing = db.prepare("SELECT COUNT(*) AS count FROM boards").get().count;
15
- if (existing > 0) return null;
16
-
17
- const time = now();
18
- const boardId = id();
19
- const seed = buildBoardFromRepo(repoPath);
20
-
21
- db.exec("BEGIN;");
22
- try {
23
- db.prepare(
24
- `INSERT INTO boards
25
- (id, slug, name, repo_url, system_path, default_branch,
26
- project_notes, agent_instructions, ai_enabled, created_at, updated_at)
27
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
28
- ).run(
29
- boardId,
30
- seed.boardSlug,
31
- seed.boardName,
32
- seed.repoUrl,
33
- seed.systemPath,
34
- seed.defaultBranch,
35
- seed.projectNotes,
36
- seed.agentInstructions,
37
- options.enableAi === false ? 0 : 1,
38
- time,
39
- time
40
- );
41
-
42
- const states = options.enableAi === false ? [
43
- ["Backlog", null],
44
- ["Todo", null],
45
- ["In Progress", "in_progress"],
46
- ["Review", "review"],
47
- ["Done", "done"],
48
- ["Cancelled", null]
49
- ] : [
50
- ["Backlog", null],
51
- ["Todo", null],
52
- ["AI Ready", "ai_ready"],
53
- ["In Progress", "in_progress"],
54
- ["Review", "review"],
55
- ["Done", "done"],
56
- ["Cancelled", null]
57
- ];
58
- const stateIds = new Map();
59
- states.forEach(([name, role], position) => {
60
- const stateId = id();
61
- stateIds.set(name, stateId);
62
- db.prepare(
63
- `INSERT INTO states
64
- (id, board_id, name, position, is_default, role, created_at)
65
- VALUES (?, ?, ?, ?, ?, ?, ?)`
66
- ).run(stateId, boardId, name, position, name === "Todo" ? 1 : 0, role, time);
67
- });
68
-
69
- // User-defined labels only at seed time.
70
- const labelIds = new Map();
71
- [
72
- ["human-only", "#7c2d12"],
73
- ["needs-human-input", "#dc2626"],
74
- ["needs-decomposition", "#9333ea"],
75
- ["needs-followup", "#b45309"],
76
- ["tech-debt", "#64748b"],
77
- ["security", "#991b1b"],
78
- ["onboarding", "#0f766e"]
79
- ].forEach(([name, color]) => {
80
- const labelId = id();
81
- labelIds.set(name, labelId);
82
- db.prepare(
83
- "INSERT INTO labels (id, board_id, name, color, created_at) VALUES (?, ?, ?, ?, ?)"
84
- ).run(labelId, boardId, name, color, time);
85
- });
86
-
87
- if (options.includeExamples) {
88
- const epicTicket = insertSeedTicket(db, boardId, 1, {
89
- title: `Onboard ${seed.boardName} into this board`,
90
- description:
91
- "First-run onboarding epic. Use this to turn the generic seed into a useful repo-specific project context and work queue.",
92
- type: "epic",
93
- aiPlan:
94
- "1. Fill Settings → AI (Agent Instructions) and Settings → Notes (Notes For You).\n2. Capture initial decisions and lessons in the Journal.\n3. Create the first real epic or AI-ready implementation ticket.",
95
- stateId: stateIds.get("Todo"),
96
- priority: 4,
97
- labels: [labelIds.get("human-only"), labelIds.get("needs-decomposition"), labelIds.get("onboarding")]
98
- });
99
-
100
- const firstTicket = insertSeedTicket(db, boardId, 2, {
101
- title: "Fill agent context & personal notes",
102
- description:
103
- "Open Settings → AI (Agent Instructions) and Settings → Notes, and add real project context plus your own reminders.",
104
- type: "feature",
105
- parentTicketId: epicTicket,
106
- stateId: stateIds.get("Todo"),
107
- priority: 3,
108
- labels: [labelIds.get("human-only"), labelIds.get("onboarding")]
109
- });
110
-
111
- insertSeedTicket(db, boardId, 3, {
112
- title: "Create the first real implementation ticket",
113
- description:
114
- "Create a focused feature, task, or bug card with acceptance criteria, labels, and enough context for an agent or human to execute.",
115
- type: "feature",
116
- parentTicketId: epicTicket,
117
- stateId: stateIds.get("Backlog"),
118
- priority: 1,
119
- labels: [labelIds.get("human-only"), labelIds.get("onboarding")]
120
- });
121
-
122
- // #12 is a stable “try the agent on this card” handle for docs and `orbit init` next steps (MCP + claim-next).
123
- insertSeedTicket(db, boardId, 12, {
124
- title: "Try Orbit MCP on this ticket",
125
- description:
126
- "After `orbit init` and registering MCP, ask your agent from this repo to use the Orbit MCP tools on ticket 12 (claim context, update fields, move lanes). Read SKILL-ORBIT.md first.",
127
- type: "task",
128
- stateId: stateIds.get("Backlog"),
129
- priority: 2,
130
- labels: [labelIds.get("onboarding")]
131
- });
132
-
133
- addComment(db, epicTicket, "system", "note", "Universal first-run seed. Delete or complete these onboarding cards once this board reflects the repo.");
134
- addComment(db, firstTicket, "system", "note", "Settings → AI: agent_instructions (ticket context). Settings → Notes: project_notes (you only).");
135
- }
136
- recordEvent(db, boardId, "seed", null, "system", { board: seed.boardSlug });
137
- db.exec("COMMIT;");
138
- } catch (error) {
139
- db.exec("ROLLBACK;");
140
- throw error;
141
- }
142
-
143
- return db.prepare("SELECT * FROM boards WHERE id = ?").get(boardId);
144
- }
145
-
146
- function insertSeedTicket(db, boardId, number, ticket) {
147
- const ticketId = id();
148
- const time = now();
149
- db.prepare(
150
- `INSERT INTO tickets
151
- (id, board_id, number, title, description, type, parent_ticket_id, ai_plan,
152
- implementation_summary, implementation_updates, state_id, priority, created_by, created_at, updated_at)
153
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
154
- ).run(
155
- ticketId,
156
- boardId,
157
- number,
158
- ticket.title,
159
- ticket.description,
160
- normalizeTicketType(ticket.type || (ticket.parentTicketId ? "feature" : "task")),
161
- ticket.parentTicketId || null,
162
- ticket.aiPlan || "",
163
- ticket.implementationSummary || "",
164
- ticket.implementationUpdates || "",
165
- ticket.stateId,
166
- ticket.priority,
167
- "system",
168
- time,
169
- time
170
- );
171
-
172
- for (const labelId of ticket.labels || []) {
173
- db.prepare("INSERT OR IGNORE INTO ticket_labels (ticket_id, label_id) VALUES (?, ?)").run(ticketId, labelId);
174
- }
175
- return ticketId;
176
- }
177
-
178
- /** Sniff repo metadata for a new board (package.json, git, env). */
179
- export function buildBoardFromRepo(projectRoot) {
180
- const packageInfo = readPackageInfo(projectRoot);
181
- const directoryName = basename(projectRoot);
182
- const boardName =
183
- readSeedValue("board_name") || titleize(packageInfo.name || directoryName || "My Board");
184
- const boardSlug = slugify(
185
- readSeedValue("board_slug") || packageInfo.name || boardName || "my-board"
186
- );
187
- const repoUrl = readSeedValue("repo_url") || gitValue(["config", "--get", "remote.origin.url"], projectRoot) || "";
188
- const systemPath = readSeedValue("system_path") || projectRoot;
189
- const defaultBranch =
190
- readSeedValue("default_branch") ||
191
- gitValue(["branch", "--show-current"], projectRoot) ||
192
- gitValue(["symbolic-ref", "--short", "HEAD"], projectRoot) ||
193
- "main";
194
- const defaultProjectNotes =
195
- "Personal reminders (Settings → Notes: Notes For You). Point yourself at SKILL-ORBIT.md, runbooks, or nudges for your tools.";
196
- return {
197
- boardName,
198
- boardSlug,
199
- repoUrl,
200
- systemPath,
201
- defaultBranch,
202
- projectNotes: readSeedValue("project_notes") || defaultProjectNotes,
203
- agentInstructions: readSeedValue("agent_instructions") || ""
204
- };
205
- }
206
-
207
- function readPackageInfo(root) {
208
- const path = join(root, "package.json");
209
- if (!existsSync(path)) return {};
210
- try {
211
- return JSON.parse(readFileSync(path, "utf8"));
212
- } catch {
213
- return {};
214
- }
215
- }
216
-
217
- function readSeedValue(key) {
218
- const envValue = process.env[key.toUpperCase()];
219
- if (typeof envValue === "string" && envValue.trim()) return envValue.trim();
220
- return "";
221
- }
222
-
223
- function gitValue(args, cwd) {
224
- try {
225
- return execFileSync("git", args, {
226
- cwd,
227
- encoding: "utf8",
228
- stdio: ["ignore", "pipe", "ignore"],
229
- timeout: 2000
230
- }).trim();
231
- } catch {
232
- return "";
233
- }
234
- }