@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.
- package/Dockerfile +10 -8
- package/README.md +146 -164
- package/dist/full/csp.txt +1 -0
- package/dist/full/fonts/JetBrains_Mono/JetBrainsMono-subset.woff2 +0 -0
- package/dist/full/fonts/JetBrains_Mono/README.txt +5 -0
- package/dist/full/fonts/Mona_Sans/MonaSans-subset.woff2 +0 -0
- package/{public/fonts/Open_Sans → dist/full/fonts/Mona_Sans}/OFL.txt +93 -93
- package/dist/full/fonts/Mona_Sans/README.txt +10 -0
- package/{public/fonts/JetBrains_Mono → dist/full/fonts/Newsreader}/OFL.txt +93 -93
- package/dist/full/fonts/Newsreader/README.txt +8 -0
- package/dist/full/fonts/Newsreader/newsreader.woff2 +0 -0
- package/dist/full/index.html +36 -653
- package/dist/full/js/app.BmuponPJ.js +32 -0
- package/dist/full/js/app.BmuponPJ.js.map +1 -0
- package/dist/full/js/chunk.1fJGQGbW.js +2 -0
- package/dist/full/js/chunk.1fJGQGbW.js.map +1 -0
- package/dist/full/js/chunk.5D7JO2zp.js +2 -0
- package/dist/full/js/chunk.5D7JO2zp.js.map +1 -0
- package/dist/full/js/chunk.BrNn_D79.js +2 -0
- package/dist/full/js/chunk.BrNn_D79.js.map +1 -0
- package/dist/full/js/chunk.CokJXIqM.js +2 -0
- package/dist/full/js/chunk.CokJXIqM.js.map +1 -0
- package/dist/full/js/chunk.D_Haqy6R.js +2 -0
- package/dist/full/js/chunk.D_Haqy6R.js.map +1 -0
- package/dist/full/js/chunk.RO0jsH6I.js +15 -0
- package/dist/full/js/chunk.RO0jsH6I.js.map +1 -0
- package/dist/full/js/chunk.dqWOEtBM.js +2 -0
- package/dist/full/js/chunk.dqWOEtBM.js.map +1 -0
- package/dist/full/js/warm.f260bbbc.js +15 -0
- package/dist/full/orbits-favicon.png +0 -0
- package/dist/full/orbits-logo-bg-wide.png +0 -0
- package/dist/full/orbits-logo-bg.png +0 -0
- package/dist/full/orbits-logo.png +0 -0
- package/dist/full/styles.2b154ffe.css +1 -0
- package/dist/full/vendor/starlove-ui/theme-init.js +66 -0
- package/dist/full/version.json +2 -2
- package/docs/AGENT_GUIDE.md +114 -0
- package/docs/UPDATING.md +249 -64
- package/lib/adapters/indexeddb/blobs.d.ts +3 -0
- package/lib/adapters/indexeddb/blobs.js +54 -0
- package/lib/adapters/indexeddb/database.d.ts +60 -0
- package/lib/adapters/indexeddb/database.js +126 -0
- package/lib/adapters/indexeddb/index.d.ts +5 -0
- package/lib/adapters/indexeddb/index.js +3 -0
- package/lib/adapters/indexeddb/locks.d.ts +14 -0
- package/lib/adapters/indexeddb/locks.js +40 -0
- package/lib/adapters/indexeddb/store.d.ts +40 -0
- package/lib/adapters/indexeddb/store.js +424 -0
- package/lib/adapters/indexeddb/tables.d.ts +43 -0
- package/lib/adapters/indexeddb/tables.js +127 -0
- package/lib/adapters/memory/blobs.d.ts +3 -0
- package/lib/adapters/memory/blobs.js +44 -0
- package/lib/adapters/memory/board.d.ts +41 -0
- package/lib/adapters/memory/board.js +521 -0
- package/lib/adapters/memory/index.d.ts +2 -0
- package/lib/adapters/memory/index.js +2 -0
- package/lib/adapters/memory/search.d.ts +6 -0
- package/lib/adapters/memory/search.js +30 -0
- package/lib/adapters/memory/store.d.ts +34 -0
- package/lib/adapters/memory/store.js +266 -0
- package/lib/adapters/sqlite/backups.d.ts +53 -0
- package/lib/adapters/sqlite/backups.js +232 -0
- package/lib/adapters/sqlite/blobs.d.ts +14 -0
- package/lib/adapters/sqlite/blobs.js +109 -0
- package/lib/adapters/sqlite/board.d.ts +77 -0
- package/lib/adapters/sqlite/board.js +328 -0
- package/lib/adapters/sqlite/database.d.ts +67 -0
- package/lib/adapters/sqlite/database.js +285 -0
- package/lib/adapters/sqlite/index.d.ts +3 -0
- package/lib/adapters/sqlite/index.js +2 -0
- package/lib/adapters/sqlite/lock.d.ts +11 -0
- package/lib/adapters/sqlite/lock.js +34 -0
- package/lib/adapters/sqlite/records.d.ts +54 -0
- package/lib/adapters/sqlite/records.js +546 -0
- package/lib/adapters/sqlite/schema.d.ts +54 -0
- package/lib/adapters/sqlite/schema.js +276 -0
- package/lib/adapters/sqlite/store.d.ts +39 -0
- package/lib/adapters/sqlite/store.js +385 -0
- package/lib/browser/in-page.d.ts +31 -0
- package/lib/browser/in-page.js +46 -0
- package/lib/browser/old-preview.d.ts +13 -0
- package/lib/browser/old-preview.js +80 -0
- package/lib/browser/preview-board.d.ts +8 -0
- package/lib/browser/preview-board.js +69 -0
- package/lib/cli/main.d.ts +7 -0
- package/lib/cli/main.js +343 -0
- package/lib/cli/orbit.d.ts +8 -0
- package/lib/cli/orbit.js +25 -0
- package/lib/client/http.d.ts +38 -0
- package/lib/client/http.js +334 -0
- package/lib/client/local.d.ts +26 -0
- package/lib/client/local.js +190 -0
- package/lib/client/object-url.d.ts +8 -0
- package/lib/client/object-url.js +21 -0
- package/lib/client/types.d.ts +268 -0
- package/lib/client/types.js +8 -0
- package/lib/commands/agent-tools.d.ts +31 -0
- package/lib/commands/agent-tools.js +100 -0
- package/lib/commands/index.d.ts +56 -0
- package/lib/commands/index.js +298 -0
- package/lib/commands/parse.d.ts +73 -0
- package/lib/commands/parse.js +231 -0
- package/lib/commands/present.d.ts +134 -0
- package/lib/commands/present.js +198 -0
- package/lib/commands/session.d.ts +85 -0
- package/lib/commands/session.js +138 -0
- package/lib/commands/verbs.d.ts +35 -0
- package/lib/commands/verbs.js +842 -0
- package/lib/core/actors.d.ts +18 -0
- package/lib/core/actors.js +45 -0
- package/lib/core/agent.d.ts +128 -0
- package/lib/core/agent.js +323 -0
- package/lib/core/boards.d.ts +113 -0
- package/lib/core/boards.js +288 -0
- package/lib/core/bootstrap.d.ts +47 -0
- package/lib/core/bootstrap.js +100 -0
- package/lib/core/bytes.d.ts +10 -0
- package/lib/core/bytes.js +52 -0
- package/lib/core/card-paths.d.ts +25 -0
- package/lib/core/card-paths.js +44 -0
- package/lib/core/context.d.ts +60 -0
- package/lib/core/context.js +42 -0
- package/lib/core/cross-board.d.ts +81 -0
- package/lib/core/cross-board.js +228 -0
- package/lib/core/describe.d.ts +21 -0
- package/lib/core/describe.js +81 -0
- package/lib/core/errors.d.ts +159 -0
- package/lib/core/errors.js +160 -0
- package/lib/core/files.d.ts +79 -0
- package/lib/core/files.js +262 -0
- package/lib/core/history.d.ts +20 -0
- package/lib/core/history.js +53 -0
- package/lib/core/image-types.d.ts +16 -0
- package/lib/core/image-types.js +36 -0
- package/lib/core/model.d.ts +263 -0
- package/lib/core/model.js +34 -0
- package/lib/core/nebula-link.d.ts +14 -0
- package/lib/core/nebula-link.js +39 -0
- package/lib/core/relations.d.ts +58 -0
- package/lib/core/relations.js +112 -0
- package/lib/core/search.d.ts +38 -0
- package/lib/core/search.js +92 -0
- package/lib/core/sessions.d.ts +44 -0
- package/lib/core/sessions.js +158 -0
- package/lib/core/snapshot-schema.d.ts +295 -0
- package/lib/core/snapshot-schema.js +82 -0
- package/lib/core/snapshots.d.ts +75 -0
- package/lib/core/snapshots.js +409 -0
- package/lib/core/states.d.ts +25 -0
- package/lib/core/states.js +126 -0
- package/lib/core/text.d.ts +40 -0
- package/lib/core/text.js +113 -0
- package/lib/core/tickets.d.ts +69 -0
- package/lib/core/tickets.js +311 -0
- package/lib/core/trello.d.ts +17 -0
- package/lib/core/trello.js +269 -0
- package/lib/core/verdicts.d.ts +28 -0
- package/lib/core/verdicts.js +92 -0
- package/lib/core/views.d.ts +95 -0
- package/lib/core/views.js +186 -0
- package/lib/http/app.d.ts +46 -0
- package/lib/http/app.js +491 -0
- package/lib/mcp-server.d.ts +10 -0
- package/lib/mcp-server.js +120 -0
- package/lib/node/assets.d.ts +7 -0
- package/lib/node/assets.js +68 -0
- package/lib/node/data-folder.d.ts +21 -0
- package/lib/node/data-folder.js +34 -0
- package/lib/node/env.d.ts +38 -0
- package/lib/node/env.js +49 -0
- package/lib/node/host-check.d.ts +24 -0
- package/lib/node/host-check.js +53 -0
- package/lib/node/host-services.d.ts +9 -0
- package/lib/node/host-services.js +150 -0
- package/lib/node/local.d.ts +22 -0
- package/lib/node/local.js +61 -0
- package/lib/node/migrate.d.ts +53 -0
- package/lib/node/migrate.js +635 -0
- package/lib/node/package.d.ts +7 -0
- package/lib/node/package.js +14 -0
- package/lib/node/repo-board.d.ts +49 -0
- package/lib/node/repo-board.js +245 -0
- package/lib/node/serve.d.ts +8 -0
- package/lib/node/serve.js +106 -0
- package/lib/orbit.d.ts +47 -0
- package/lib/orbit.js +44 -0
- package/lib/quiet-sqlite-warning.d.ts +1 -0
- package/lib/quiet-sqlite-warning.js +18 -0
- package/lib/store/blob-path.d.ts +6 -0
- package/lib/store/blob-path.js +12 -0
- package/lib/store/conformance.d.ts +52 -0
- package/lib/store/conformance.js +1449 -0
- package/lib/store/search-words.d.ts +10 -0
- package/lib/store/search-words.js +19 -0
- package/lib/store/types.d.ts +452 -0
- package/lib/store/types.js +34 -0
- package/llms.txt +63 -0
- package/package.json +109 -25
- package/src/cli/orbit.js +11 -658
- package/src/mcp-server.js +16 -876
- package/SKILL-ORBIT.md +0 -151
- package/build.mjs +0 -210
- package/dist/full/js/app.62905fcb.js +0 -952
- package/dist/full/js/app.62905fcb.js.map +0 -7
- package/dist/full/styles.4e60d824.css +0 -1
- package/docs/AGENT_PROTOCOL.md +0 -424
- package/docs/MCP_SETUP.md +0 -54
- package/docs/ORBIT_DISPATCH.md +0 -280
- package/docs/SS-Orbit-Dark.png +0 -0
- package/docs/SS-Orbit-Light.png +0 -0
- package/docs/mcp-client.example.json +0 -13
- package/docs/setup/orbit-init-wizard.md +0 -174
- package/public/apple-touch-icon.png +0 -0
- package/public/cursors/live_arrow.cur +0 -0
- package/public/cursors/live_link.cur +0 -0
- package/public/cursors/live_move.cur +0 -0
- package/public/cursors/live_select.cur +0 -0
- package/public/cursors/live_unavail.cur +0 -0
- package/public/favicon-32x32.png +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Bold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-BoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Italic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Light.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-LightItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Medium.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-MediumItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-Regular.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBold.ttf +0 -0
- package/public/fonts/Chakra_Petch/ChakraPetch-SemiBoldItalic.ttf +0 -0
- package/public/fonts/Chakra_Petch/OFL.txt +0 -93
- package/public/fonts/Inter/Inter-Italic-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/Inter-VariableFont_opsz,wght.ttf +0 -0
- package/public/fonts/Inter/OFL.txt +0 -93
- package/public/fonts/Inter/README.txt +0 -118
- package/public/fonts/JetBrains_Mono/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/JetBrainsMono-VariableFont_wght.ttf +0 -0
- package/public/fonts/JetBrains_Mono/README.txt +0 -79
- package/public/fonts/OpenRing-Regular.ttf +0 -0
- package/public/fonts/Open_Sans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- package/public/fonts/Open_Sans/README.txt +0 -100
- package/public/fonts/Orbitron/OFL.txt +0 -93
- package/public/fonts/Orbitron/Orbitron-VariableFont_wght.ttf +0 -0
- package/public/fonts/Orbitron/README.txt +0 -68
- package/public/fonts/Rajdhani/OFL.txt +0 -93
- package/public/fonts/Rajdhani/Rajdhani-Bold.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Light.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Medium.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-Regular.ttf +0 -0
- package/public/fonts/Rajdhani/Rajdhani-SemiBold.ttf +0 -0
- package/public/fonts/runescape-uf.ttf +0 -0
- package/public/index.html +0 -769
- package/public/js/actor-labels.js +0 -65
- package/public/js/api.js +0 -39
- package/public/js/app.js +0 -45
- package/public/js/artifact-drawer.js +0 -79
- package/public/js/board-export.js +0 -161
- package/public/js/board-menu.js +0 -374
- package/public/js/card-actions.js +0 -545
- package/public/js/config.js +0 -20
- package/public/js/create-card.js +0 -190
- package/public/js/dom.js +0 -19
- package/public/js/drawer.js +0 -273
- package/public/js/font-preference.js +0 -229
- package/public/js/format.js +0 -433
- package/public/js/help-menu.js +0 -31
- package/public/js/icons.js +0 -16
- package/public/js/kanban.js +0 -694
- package/public/js/local-backend.js +0 -1015
- package/public/js/main.js +0 -161
- package/public/js/modal.js +0 -33
- package/public/js/motion-preference.js +0 -64
- package/public/js/panel.js +0 -58
- package/public/js/router.js +0 -134
- package/public/js/search.js +0 -56
- package/public/js/settings-tabs.js +0 -7
- package/public/js/settings.js +0 -1634
- package/public/js/sse.js +0 -159
- package/public/js/starscape.js +0 -332
- package/public/js/state.js +0 -129
- package/public/js/text-editing.js +0 -128
- package/public/js/theme-preference.js +0 -95
- package/public/js/ticket-detail.js +0 -1516
- package/public/js/ticket-typeahead.js +0 -49
- package/public/js/toast.js +0 -89
- package/public/js/topbar-notes.js +0 -155
- package/public/js/transport.js +0 -22
- package/public/js/typeahead.js +0 -206
- package/public/js/unread.js +0 -121
- package/public/js/update-check.js +0 -58
- package/public/js/url-routes.js +0 -94
- package/public/orbits-favicon.png +0 -0
- package/public/orbits-logo-bg-wide.png +0 -0
- package/public/orbits-logo-bg.png +0 -0
- package/public/orbits-logo.png +0 -0
- package/public/styles.css +0 -7709
- package/src/core/agent.js +0 -387
- package/src/core/agents-md.js +0 -109
- package/src/core/artifacts.js +0 -149
- package/src/core/attachments.js +0 -238
- package/src/core/auth.js +0 -85
- package/src/core/backups.js +0 -142
- package/src/core/board.js +0 -148
- package/src/core/boards.js +0 -409
- package/src/core/bootstrap.js +0 -170
- package/src/core/css-bundle.js +0 -30
- package/src/core/db.js +0 -315
- package/src/core/delete-board.js +0 -163
- package/src/core/dispatch.js +0 -1007
- package/src/core/events.js +0 -314
- package/src/core/http.js +0 -115
- package/src/core/migrate.js +0 -198
- package/src/core/paths.js +0 -55
- package/src/core/provision-repo-board.js +0 -119
- package/src/core/queries.js +0 -246
- package/src/core/registry.js +0 -211
- package/src/core/relations.js +0 -163
- package/src/core/review-verdicts.js +0 -138
- package/src/core/router.js +0 -556
- package/src/core/search.js +0 -183
- package/src/core/seed.js +0 -234
- package/src/core/snapshots.js +0 -692
- package/src/core/states.js +0 -167
- package/src/core/system-picker.js +0 -109
- package/src/core/tickets.js +0 -400
- package/src/core/util.js +0 -106
- package/src/core/version-check.js +0 -154
- package/src/mcp/orbit-client.js +0 -287
- package/src/server.js +0 -115
package/src/core/search.js
DELETED
|
@@ -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
|
-
}
|