@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
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
// Side-effect-free workspace provisioning for CLI and server startup.
|
|
2
|
-
// Do not import board.js from here (that module runs full startup at import time).
|
|
3
|
-
|
|
4
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
5
|
-
import { basename, dirname } from "node:path";
|
|
6
|
-
import { createBoardSchema, openConnection } from "./db.js";
|
|
7
|
-
import {
|
|
8
|
-
computeNewBoardDbPath,
|
|
9
|
-
getBoardByRepoPath,
|
|
10
|
-
insertBoard,
|
|
11
|
-
syncRegistryFromBoardDb
|
|
12
|
-
} from "./registry.js";
|
|
13
|
-
import { seedIfEmpty } from "./seed.js";
|
|
14
|
-
import { normalizePath, now, slugify } from "./util.js";
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Create or repair the **first** Orbit board for a repo root: `.orbit/board.db`,
|
|
18
|
-
* full seed when empty, and a matching registry row.
|
|
19
|
-
*
|
|
20
|
-
* Idempotent when a registry row already exists for `repo_path`.
|
|
21
|
-
*
|
|
22
|
-
* @param {string} repoPathRaw Absolute or normalized repo directory
|
|
23
|
-
* @returns {{ ok: true, status: "skipped"|"created"|"repaired", registryRow: object|null, message?: string }}
|
|
24
|
-
*/
|
|
25
|
-
export function provisionRepoBoard(repoPathRaw, options = {}) {
|
|
26
|
-
const repoRoot = normalizePath(repoPathRaw);
|
|
27
|
-
const existingReg = getBoardByRepoPath(repoRoot);
|
|
28
|
-
if (existingReg) {
|
|
29
|
-
return {
|
|
30
|
-
ok: true,
|
|
31
|
-
status: "skipped",
|
|
32
|
-
registryRow: existingReg,
|
|
33
|
-
message: "A board is already registered for this repo path."
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const slugHint = slugify(basename(repoRoot) || "board");
|
|
38
|
-
const dbPath = computeNewBoardDbPath(repoRoot, slugHint);
|
|
39
|
-
mkdirSync(dirname(dbPath), { recursive: true });
|
|
40
|
-
|
|
41
|
-
const hadExistingFile = existsSync(dbPath);
|
|
42
|
-
if (hadExistingFile) {
|
|
43
|
-
return provisionExistingDbFile(repoRoot, dbPath, options);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const db = openConnection(dbPath);
|
|
47
|
-
createBoardSchema(db);
|
|
48
|
-
const seeded = seedIfEmpty(db, repoRoot, {
|
|
49
|
-
enableAi: options.enableAi,
|
|
50
|
-
includeExamples: options.includeExamples
|
|
51
|
-
});
|
|
52
|
-
if (!seeded) {
|
|
53
|
-
const boardMeta = readBoardMetaFromSqlite(db);
|
|
54
|
-
if (!boardMeta) {
|
|
55
|
-
throw new Error("provisionRepoBoard: database file exists but contains no board row.");
|
|
56
|
-
}
|
|
57
|
-
return registerOrphanBoardDb(repoRoot, dbPath, db, boardMeta);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return insertAfterSeed(repoRoot, dbPath, db, seeded, "created");
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function provisionExistingDbFile(repoRoot, dbPath, options = {}) {
|
|
64
|
-
const db = openConnection(dbPath);
|
|
65
|
-
createBoardSchema(db);
|
|
66
|
-
const seeded = seedIfEmpty(db, repoRoot, {
|
|
67
|
-
enableAi: options.enableAi,
|
|
68
|
-
includeExamples: options.includeExamples
|
|
69
|
-
});
|
|
70
|
-
if (seeded) {
|
|
71
|
-
return insertAfterSeed(repoRoot, dbPath, db, seeded, "repaired");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const boardMeta = readBoardMetaFromSqlite(db);
|
|
75
|
-
if (!boardMeta) {
|
|
76
|
-
throw new Error(
|
|
77
|
-
"provisionRepoBoard: .orbit/board.db exists but has no board row — remove or repair the file manually."
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
return registerOrphanBoardDb(repoRoot, dbPath, db, boardMeta);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function readBoardMetaFromSqlite(db) {
|
|
84
|
-
return db.prepare("SELECT * FROM boards LIMIT 1").get() || null;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* @param {"created"|"repaired"} outcome
|
|
89
|
-
*/
|
|
90
|
-
function insertAfterSeed(repoRoot, dbPath, db, seeded, outcome) {
|
|
91
|
-
const t = now();
|
|
92
|
-
insertBoard({
|
|
93
|
-
id: seeded.id,
|
|
94
|
-
slug: seeded.slug,
|
|
95
|
-
name: seeded.name,
|
|
96
|
-
repo_path: repoRoot,
|
|
97
|
-
db_path: dbPath,
|
|
98
|
-
repo_url: seeded.repo_url || "",
|
|
99
|
-
default_branch: seeded.default_branch || "main",
|
|
100
|
-
last_active_at: t,
|
|
101
|
-
created_at: t,
|
|
102
|
-
updated_at: t
|
|
103
|
-
});
|
|
104
|
-
const fresh = getBoardByRepoPath(repoRoot);
|
|
105
|
-
if (fresh) syncRegistryFromBoardDb(fresh, db);
|
|
106
|
-
return { ok: true, status: outcome, registryRow: fresh, message: undefined };
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function registerOrphanBoardDb(repoRoot, dbPath, db, b) {
|
|
110
|
-
const boardRow = { id: b.id, repo_path: repoRoot, db_path: dbPath };
|
|
111
|
-
syncRegistryFromBoardDb(boardRow, db);
|
|
112
|
-
const fresh = getBoardByRepoPath(repoRoot);
|
|
113
|
-
return {
|
|
114
|
-
ok: true,
|
|
115
|
-
status: "repaired",
|
|
116
|
-
registryRow: fresh,
|
|
117
|
-
message: "Registered existing .orbit/board.db with the registry."
|
|
118
|
-
};
|
|
119
|
-
}
|
package/src/core/queries.js
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
// Read/write helpers that all take an explicit `db` connection. No hidden
|
|
2
|
-
// "active board" state — callers pass in the connection for the board they
|
|
3
|
-
// resolved at the request boundary.
|
|
4
|
-
|
|
5
|
-
import { httpError, id, now, requiredString } from "./util.js";
|
|
6
|
-
|
|
7
|
-
export function ticketByNumber(db, boardId, number) {
|
|
8
|
-
return db
|
|
9
|
-
.prepare(
|
|
10
|
-
`SELECT t.*, s.name AS state_name, s.role AS state_role,
|
|
11
|
-
b.slug AS board_slug, b.name AS board_name
|
|
12
|
-
FROM tickets t
|
|
13
|
-
JOIN states s ON s.id = t.state_id
|
|
14
|
-
JOIN boards b ON b.id = t.board_id
|
|
15
|
-
WHERE t.board_id = ? AND t.number = ?`
|
|
16
|
-
)
|
|
17
|
-
.get(boardId, number);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function ticketByTitle(db, boardId, title) {
|
|
21
|
-
return db
|
|
22
|
-
.prepare(
|
|
23
|
-
`SELECT t.*, s.name AS state_name, s.role AS state_role,
|
|
24
|
-
b.slug AS board_slug, b.name AS board_name
|
|
25
|
-
FROM tickets t
|
|
26
|
-
JOIN states s ON s.id = t.state_id
|
|
27
|
-
JOIN boards b ON b.id = t.board_id
|
|
28
|
-
WHERE t.board_id = ? AND lower(t.title) = lower(?)
|
|
29
|
-
ORDER BY t.archived_at IS NULL DESC, t.number DESC
|
|
30
|
-
LIMIT 1`
|
|
31
|
-
)
|
|
32
|
-
.get(boardId, title);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function ticketById(db, ticketId) {
|
|
36
|
-
return db
|
|
37
|
-
.prepare(
|
|
38
|
-
`SELECT t.*, s.name AS state_name, s.role AS state_role,
|
|
39
|
-
b.slug AS board_slug, b.name AS board_name
|
|
40
|
-
FROM tickets t
|
|
41
|
-
JOIN states s ON s.id = t.state_id
|
|
42
|
-
JOIN boards b ON b.id = t.board_id
|
|
43
|
-
WHERE t.id = ?`
|
|
44
|
-
)
|
|
45
|
-
.get(ticketId);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function boardById(db, boardId) {
|
|
49
|
-
return db.prepare("SELECT * FROM boards WHERE id = ?").get(boardId);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function stateByName(db, boardId, name) {
|
|
53
|
-
return db.prepare("SELECT * FROM states WHERE board_id = ? AND name = ?").get(boardId, name);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export function stateByRole(db, boardId, role) {
|
|
57
|
-
return db
|
|
58
|
-
.prepare("SELECT * FROM states WHERE board_id = ? AND role = ? ORDER BY position LIMIT 1")
|
|
59
|
-
.get(boardId, role);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function stateById(db, stateId) {
|
|
63
|
-
return db.prepare("SELECT * FROM states WHERE id = ?").get(stateId);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function defaultStateId(db, boardId) {
|
|
67
|
-
const state =
|
|
68
|
-
db.prepare("SELECT id FROM states WHERE board_id = ? AND is_default = 1").get(boardId) ||
|
|
69
|
-
db.prepare("SELECT id FROM states WHERE board_id = ? ORDER BY position LIMIT 1").get(boardId);
|
|
70
|
-
if (!state) throw httpError(400, "board_has_no_states");
|
|
71
|
-
return state.id;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function compactStatePositions(db, boardId) {
|
|
75
|
-
const states = db.prepare("SELECT id FROM states WHERE board_id = ? ORDER BY position").all(boardId);
|
|
76
|
-
states.forEach((state, position) => {
|
|
77
|
-
db.prepare("UPDATE states SET position = ? WHERE id = ?").run(position, state.id);
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function labelsForTicket(db, ticketId) {
|
|
82
|
-
return db
|
|
83
|
-
.prepare(
|
|
84
|
-
`SELECT l.*
|
|
85
|
-
FROM ticket_labels tl
|
|
86
|
-
JOIN labels l ON l.id = tl.label_id
|
|
87
|
-
WHERE tl.ticket_id = ?
|
|
88
|
-
ORDER BY l.name`
|
|
89
|
-
)
|
|
90
|
-
.all(ticketId);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function childTicketsFor(db, ticketId) {
|
|
94
|
-
return db
|
|
95
|
-
.prepare(
|
|
96
|
-
`SELECT t.*, s.name AS state_name, s.role AS state_role,
|
|
97
|
-
b.slug AS board_slug, b.name AS board_name
|
|
98
|
-
FROM tickets t
|
|
99
|
-
JOIN states s ON s.id = t.state_id
|
|
100
|
-
JOIN boards b ON b.id = t.board_id
|
|
101
|
-
WHERE t.parent_ticket_id = ? AND t.archived_at IS NULL
|
|
102
|
-
ORDER BY t.number ASC`
|
|
103
|
-
)
|
|
104
|
-
.all(ticketId);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export function archivedTicketsForBoard(db, boardId) {
|
|
108
|
-
return db
|
|
109
|
-
.prepare(
|
|
110
|
-
`SELECT t.*, s.name AS state_name, s.role AS state_role,
|
|
111
|
-
b.slug AS board_slug, b.name AS board_name
|
|
112
|
-
FROM tickets t
|
|
113
|
-
JOIN states s ON s.id = t.state_id
|
|
114
|
-
JOIN boards b ON b.id = t.board_id
|
|
115
|
-
WHERE t.board_id = ? AND t.archived_at IS NOT NULL
|
|
116
|
-
ORDER BY t.archived_at DESC`
|
|
117
|
-
)
|
|
118
|
-
.all(boardId);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function compactTicket(ticket) {
|
|
122
|
-
if (!ticket) return null;
|
|
123
|
-
return {
|
|
124
|
-
id: ticket.id,
|
|
125
|
-
board_id: ticket.board_id,
|
|
126
|
-
board_slug: ticket.board_slug,
|
|
127
|
-
number: ticket.number,
|
|
128
|
-
title: ticket.title,
|
|
129
|
-
type: ticket.type,
|
|
130
|
-
state_name: ticket.state_name,
|
|
131
|
-
state_role: ticket.state_role,
|
|
132
|
-
priority: ticket.priority
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function uniqueTickets(tickets) {
|
|
137
|
-
const seen = new Set();
|
|
138
|
-
const result = [];
|
|
139
|
-
for (const ticket of tickets) {
|
|
140
|
-
if (!ticket || seen.has(ticket.id)) continue;
|
|
141
|
-
seen.add(ticket.id);
|
|
142
|
-
result.push(ticket);
|
|
143
|
-
}
|
|
144
|
-
return result;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function relationRows(db, ticketId) {
|
|
148
|
-
const rows = db
|
|
149
|
-
.prepare(
|
|
150
|
-
`SELECT r.*,
|
|
151
|
-
source.title AS source_title,
|
|
152
|
-
source.number AS source_number,
|
|
153
|
-
source.board_id AS source_board_id,
|
|
154
|
-
target.title AS target_title,
|
|
155
|
-
target.number AS target_number,
|
|
156
|
-
target.board_id AS target_board_id
|
|
157
|
-
FROM relations r
|
|
158
|
-
JOIN tickets source ON source.id = r.source_ticket_id
|
|
159
|
-
JOIN tickets target ON target.id = r.target_ticket_id
|
|
160
|
-
WHERE (r.source_ticket_id = ? OR r.target_ticket_id = ?)
|
|
161
|
-
AND source.archived_at IS NULL AND target.archived_at IS NULL
|
|
162
|
-
ORDER BY r.created_at ASC`
|
|
163
|
-
)
|
|
164
|
-
.all(ticketId, ticketId);
|
|
165
|
-
|
|
166
|
-
return rows.map((row) => {
|
|
167
|
-
const isSource = row.source_ticket_id === ticketId;
|
|
168
|
-
const otherId = isSource ? row.target_ticket_id : row.source_ticket_id;
|
|
169
|
-
const other = ticketById(db, otherId);
|
|
170
|
-
return {
|
|
171
|
-
id: row.id,
|
|
172
|
-
type: row.type,
|
|
173
|
-
direction: isSource ? "outgoing" : "incoming",
|
|
174
|
-
other_ticket: other
|
|
175
|
-
};
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Returns the set of tickets currently blocking `ticketId`. The relation row
|
|
180
|
-
// IS the source of truth: a `blocked_by` row exists iff the target is still
|
|
181
|
-
// blocking. Cleanup happens at state-change time (tickets.js auto-deletes
|
|
182
|
-
// blocks/blocked_by rows when a ticket moves to a role='done' lane) or when
|
|
183
|
-
// the user removes the relation manually in the UI. So this resolver doesn't
|
|
184
|
-
// re-check lane state — it just returns the unarchived rows. Exception: epic
|
|
185
|
-
// targets expand to their children, since the epic itself isn't what gets
|
|
186
|
-
// "done"; each open child (state role != 'done', not archived) is a blocker
|
|
187
|
-
// and carries via_epic_id so callers can explain the dependency.
|
|
188
|
-
export function unresolvedBlockers(db, ticketId) {
|
|
189
|
-
const direct = db
|
|
190
|
-
.prepare(
|
|
191
|
-
`SELECT target.*, s.name AS state_name, s.role AS state_role
|
|
192
|
-
FROM relations r
|
|
193
|
-
JOIN tickets target ON target.id = r.target_ticket_id
|
|
194
|
-
JOIN states s ON s.id = target.state_id
|
|
195
|
-
WHERE r.source_ticket_id = ? AND r.type = 'blocked_by' AND target.archived_at IS NULL`
|
|
196
|
-
)
|
|
197
|
-
.all(ticketId);
|
|
198
|
-
|
|
199
|
-
const expandEpicChildren = db.prepare(
|
|
200
|
-
`SELECT t.*, s.name AS state_name, s.role AS state_role
|
|
201
|
-
FROM tickets t
|
|
202
|
-
JOIN states s ON s.id = t.state_id
|
|
203
|
-
WHERE t.parent_ticket_id = ? AND t.archived_at IS NULL AND (s.role IS NULL OR s.role != 'done')`
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
const seen = new Set();
|
|
207
|
-
const blockers = [];
|
|
208
|
-
for (const row of direct) {
|
|
209
|
-
if (row.type === "epic") {
|
|
210
|
-
const children = expandEpicChildren.all(row.id);
|
|
211
|
-
for (const child of children) {
|
|
212
|
-
if (seen.has(child.id)) continue;
|
|
213
|
-
seen.add(child.id);
|
|
214
|
-
blockers.push({ ...child, via_epic_id: row.id });
|
|
215
|
-
}
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
if (seen.has(row.id)) continue;
|
|
219
|
-
seen.add(row.id);
|
|
220
|
-
blockers.push(row);
|
|
221
|
-
}
|
|
222
|
-
return blockers;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export function ensureLabel(db, boardId, name, color = "#64748b") {
|
|
226
|
-
const cleanName = requiredString(name, "label").trim();
|
|
227
|
-
const existing = db.prepare("SELECT * FROM labels WHERE board_id = ? AND name = ?").get(boardId, cleanName);
|
|
228
|
-
if (existing) return existing;
|
|
229
|
-
const labelId = id();
|
|
230
|
-
db.prepare("INSERT INTO labels (id, board_id, name, color, created_at) VALUES (?, ?, ?, ?, ?)").run(
|
|
231
|
-
labelId,
|
|
232
|
-
boardId,
|
|
233
|
-
cleanName,
|
|
234
|
-
color,
|
|
235
|
-
now()
|
|
236
|
-
);
|
|
237
|
-
return db.prepare("SELECT * FROM labels WHERE id = ?").get(labelId);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export function addComment(db, ticketId, author, kind, body) {
|
|
241
|
-
const commentId = id();
|
|
242
|
-
db.prepare(
|
|
243
|
-
"INSERT INTO comments (id, ticket_id, author, kind, body, created_at) VALUES (?, ?, ?, ?, ?, ?)"
|
|
244
|
-
).run(commentId, ticketId, author, kind, body, now());
|
|
245
|
-
return db.prepare("SELECT * FROM comments WHERE id = ?").get(commentId);
|
|
246
|
-
}
|
package/src/core/registry.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
// Registry-level operations. No mutable global "active board" state lives
|
|
2
|
-
// here: every function either reads from the registry, opens a known
|
|
3
|
-
// per-board DB by path, or scans a bounded set of registry rows to locate
|
|
4
|
-
// the board that owns a given ticket / state / entry / relation. Callers
|
|
5
|
-
// receive `{ board, db }` and pass it down via `ctx`.
|
|
6
|
-
|
|
7
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
8
|
-
import { dirname, join } from "node:path";
|
|
9
|
-
import { createBoardSchema, getRegistry, openConnection } from "./db.js";
|
|
10
|
-
import { BOARDS_DIR } from "./paths.js";
|
|
11
|
-
import { now, slugify } from "./util.js";
|
|
12
|
-
|
|
13
|
-
export function listBoards() {
|
|
14
|
-
return getRegistry().prepare("SELECT * FROM boards ORDER BY name").all();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function getBoardByRegistryId(boardId) {
|
|
18
|
-
return getRegistry().prepare("SELECT * FROM boards WHERE id = ?").get(boardId);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function getBoardBySlug(slug) {
|
|
22
|
-
return getRegistry().prepare("SELECT * FROM boards WHERE slug = ?").get(slugify(slug));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function getBoardByRepoPath(repoPathNorm) {
|
|
26
|
-
return getRegistry()
|
|
27
|
-
.prepare(
|
|
28
|
-
`SELECT * FROM boards
|
|
29
|
-
WHERE repo_path = ?
|
|
30
|
-
ORDER BY (last_active_at IS NULL) ASC, last_active_at DESC, rowid DESC
|
|
31
|
-
LIMIT 1`
|
|
32
|
-
)
|
|
33
|
-
.get(repoPathNorm);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Most-recently-active registry row, or null. Used as a tie-breaker for the
|
|
37
|
-
* bootstrap-default case when no board is specified by the caller. */
|
|
38
|
-
export function pickDefaultBoard() {
|
|
39
|
-
return getRegistry()
|
|
40
|
-
.prepare(
|
|
41
|
-
`SELECT * FROM boards
|
|
42
|
-
ORDER BY (last_active_at IS NULL) ASC, last_active_at DESC, rowid DESC
|
|
43
|
-
LIMIT 1`
|
|
44
|
-
)
|
|
45
|
-
.get();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function deleteBoard(boardId) {
|
|
49
|
-
getRegistry().prepare("DELETE FROM boards WHERE id = ?").run(boardId);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function touchBoardActive(boardId) {
|
|
53
|
-
const t = now();
|
|
54
|
-
getRegistry()
|
|
55
|
-
.prepare("UPDATE boards SET last_active_at = ?, updated_at = ? WHERE id = ?")
|
|
56
|
-
.run(t, t, boardId);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function insertBoard(row) {
|
|
60
|
-
const t = row.created_at || now();
|
|
61
|
-
getRegistry()
|
|
62
|
-
.prepare(
|
|
63
|
-
`INSERT INTO boards (id, slug, name, repo_path, db_path, repo_url, default_branch, manage_helper_files, last_active_at, created_at, updated_at)
|
|
64
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
65
|
-
)
|
|
66
|
-
.run(
|
|
67
|
-
row.id,
|
|
68
|
-
row.slug,
|
|
69
|
-
row.name,
|
|
70
|
-
row.repo_path,
|
|
71
|
-
row.db_path,
|
|
72
|
-
row.repo_url || "",
|
|
73
|
-
row.default_branch || "main",
|
|
74
|
-
row.manage_helper_files === undefined ? 1 : row.manage_helper_files ? 1 : 0,
|
|
75
|
-
row.last_active_at || t,
|
|
76
|
-
t,
|
|
77
|
-
row.updated_at || t
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function updateBoardMeta(boardId, patch) {
|
|
82
|
-
const sets = [];
|
|
83
|
-
const vals = [];
|
|
84
|
-
for (const k of ["slug", "name", "repo_path", "db_path", "repo_url", "default_branch", "manage_helper_files"]) {
|
|
85
|
-
if (patch[k] !== undefined) {
|
|
86
|
-
sets.push(`${k} = ?`);
|
|
87
|
-
vals.push(patch[k]);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
if (!sets.length) return;
|
|
91
|
-
vals.push(now(), boardId);
|
|
92
|
-
getRegistry()
|
|
93
|
-
.prepare(`UPDATE boards SET ${sets.join(", ")}, updated_at = ? WHERE id = ?`)
|
|
94
|
-
.run(...vals);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Where a new board.db should live: always in the central DATA_DIR/boards/<slug>/ directory.
|
|
98
|
-
* Falls back to a numeric suffix if the canonical path already exists on disk (orphaned file). */
|
|
99
|
-
export function computeNewBoardDbPath(_repoPathNorm, slug) {
|
|
100
|
-
const preferred = join(BOARDS_DIR, slug, "board.db");
|
|
101
|
-
if (!existsSync(preferred)) return preferred;
|
|
102
|
-
for (let i = 2; i < 1000; i++) {
|
|
103
|
-
const alt = join(BOARDS_DIR, `${slug}-${i}`, "board.db");
|
|
104
|
-
if (!existsSync(alt)) return alt;
|
|
105
|
-
}
|
|
106
|
-
return preferred; // callers will handle any existing file
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Create the directory + file and apply the per-board schema. Returns the
|
|
110
|
-
* open connection. */
|
|
111
|
-
export function ensureBoardDbFileAndSchema(dbPath) {
|
|
112
|
-
mkdirSync(dirname(dbPath), { recursive: true });
|
|
113
|
-
const conn = openConnection(dbPath);
|
|
114
|
-
createBoardSchema(conn);
|
|
115
|
-
return conn;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/** Open the connection for a registry row. */
|
|
119
|
-
export function openBoardDb(boardRow) {
|
|
120
|
-
return openConnection(boardRow.db_path);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Whitelisted table names — these come from our own call sites, never user
|
|
124
|
-
// input, but interpolating into SQL is only safe because of this guard.
|
|
125
|
-
const ROW_OWNER_TABLES = new Set(["tickets", "states", "board_entries", "relations"]);
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Find which registry board's DB contains a row with `id` in `table`. Pure:
|
|
129
|
-
* opens one db per candidate to probe and returns `{ board, db }` (no global
|
|
130
|
-
* side effects). If `hintBoardId` is supplied it's checked first to avoid a
|
|
131
|
-
* full scan across every registered board.
|
|
132
|
-
*/
|
|
133
|
-
function findBoardForRow(table, rowId, hintBoardId = null) {
|
|
134
|
-
if (!ROW_OWNER_TABLES.has(table)) throw new Error(`unsupported owner table: ${table}`);
|
|
135
|
-
const probe = `SELECT 1 FROM ${table} WHERE id = ?`;
|
|
136
|
-
if (hintBoardId) {
|
|
137
|
-
const hint = getBoardByRegistryId(hintBoardId);
|
|
138
|
-
if (hint) {
|
|
139
|
-
const db = openBoardDb(hint);
|
|
140
|
-
if (db.prepare(probe).get(rowId)) return { board: hint, db };
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
for (const row of listBoards()) {
|
|
144
|
-
if (hintBoardId && row.id === hintBoardId) continue;
|
|
145
|
-
const db = openBoardDb(row);
|
|
146
|
-
if (db.prepare(probe).get(rowId)) return { board: row, db };
|
|
147
|
-
}
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export const findBoardForTicket = (ticketId, hintBoardId = null) =>
|
|
152
|
-
findBoardForRow("tickets", ticketId, hintBoardId);
|
|
153
|
-
export const findBoardForState = (stateId, hintBoardId = null) =>
|
|
154
|
-
findBoardForRow("states", stateId, hintBoardId);
|
|
155
|
-
export const findBoardForBoardEntry = (entryId, hintBoardId = null) =>
|
|
156
|
-
findBoardForRow("board_entries", entryId, hintBoardId);
|
|
157
|
-
export const findBoardForRelation = (relationId, hintBoardId = null) =>
|
|
158
|
-
findBoardForRow("relations", relationId, hintBoardId);
|
|
159
|
-
|
|
160
|
-
/** Sync a per-board DB's single boards-row into the registry. Idempotent. */
|
|
161
|
-
export function syncRegistryFromBoardDb(boardRow, db) {
|
|
162
|
-
const b = db.prepare("SELECT * FROM boards LIMIT 1").get();
|
|
163
|
-
if (!b) return;
|
|
164
|
-
|
|
165
|
-
const reg = getRegistry();
|
|
166
|
-
const t = now();
|
|
167
|
-
const existing = reg.prepare("SELECT id FROM boards WHERE id = ?").get(b.id);
|
|
168
|
-
if (existing) {
|
|
169
|
-
reg
|
|
170
|
-
.prepare(
|
|
171
|
-
`UPDATE boards SET slug = ?, name = ?, db_path = ?, repo_url = ?, default_branch = ?, updated_at = ?
|
|
172
|
-
WHERE id = ?`
|
|
173
|
-
)
|
|
174
|
-
.run(b.slug, b.name, boardRow.db_path, b.repo_url || "", b.default_branch || "main", t, b.id);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const existingPath = reg.prepare("SELECT id FROM boards WHERE db_path = ?").get(boardRow.db_path);
|
|
179
|
-
if (existingPath) {
|
|
180
|
-
reg
|
|
181
|
-
.prepare(
|
|
182
|
-
`UPDATE boards SET id = ?, slug = ?, name = ?, repo_path = ?, db_path = ?, repo_url = ?, default_branch = ?, updated_at = ?
|
|
183
|
-
WHERE id = ?`
|
|
184
|
-
)
|
|
185
|
-
.run(
|
|
186
|
-
b.id,
|
|
187
|
-
b.slug,
|
|
188
|
-
b.name,
|
|
189
|
-
boardRow.repo_path,
|
|
190
|
-
boardRow.db_path,
|
|
191
|
-
b.repo_url || "",
|
|
192
|
-
b.default_branch || "main",
|
|
193
|
-
t,
|
|
194
|
-
existingPath.id
|
|
195
|
-
);
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
insertBoard({
|
|
200
|
-
id: b.id,
|
|
201
|
-
slug: b.slug,
|
|
202
|
-
name: b.name,
|
|
203
|
-
repo_path: boardRow.repo_path,
|
|
204
|
-
db_path: boardRow.db_path,
|
|
205
|
-
repo_url: b.repo_url || "",
|
|
206
|
-
default_branch: b.default_branch || "main",
|
|
207
|
-
last_active_at: t,
|
|
208
|
-
created_at: t,
|
|
209
|
-
updated_at: t
|
|
210
|
-
});
|
|
211
|
-
}
|