@starlove/orbit 1.0.2 → 1.0.4
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/README.md +6 -5
- package/dist/full/index.html +1 -1
- package/dist/full/js/{app.70be7d06.js → app.7e25f59b.js} +57 -57
- package/dist/full/js/app.7e25f59b.js.map +7 -0
- package/dist/full/version.json +2 -2
- package/docs/MCP_SETUP.md +1 -1
- package/package.json +1 -1
- package/public/js/create-card.js +2 -2
- package/public/js/kanban.js +2 -2
- package/public/js/settings.js +8 -7
- package/public/js/state.js +16 -0
- package/public/js/ticket-detail.js +2 -2
- package/src/cli/orbit.js +30 -58
- package/src/core/agents-md.js +88 -0
- package/src/core/boards.js +71 -14
- package/src/core/delete-board.js +49 -5
- package/src/core/provision-repo-board.js +8 -2
- package/src/core/seed.js +14 -6
- package/dist/full/js/app.70be7d06.js.map +0 -7
package/src/core/delete-board.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { existsSync, rmSync } from "node:fs";
|
|
1
|
+
import { existsSync, rmSync, unlinkSync } from "node:fs";
|
|
2
2
|
import { basename, dirname, join, relative } from "node:path";
|
|
3
|
+
import { removeOrbitAgentsSection } from "./agents-md.js";
|
|
3
4
|
import { requireBoardAccess } from "./auth.js";
|
|
4
5
|
import { backupBoardDatabase, backupRegistry, cancelAutomaticBoardBackup } from "./backups.js";
|
|
5
6
|
import { closeConnection } from "./db.js";
|
|
6
|
-
import { deleteBoard, openBoardDb } from "./registry.js";
|
|
7
|
+
import { deleteBoard, listBoards, openBoardDb } from "./registry.js";
|
|
7
8
|
import { httpError, normalizePath } from "./util.js";
|
|
8
9
|
|
|
9
10
|
function isInside(parent, child) {
|
|
@@ -26,6 +27,24 @@ function boardDbDeleteTargets(boardRow) {
|
|
|
26
27
|
return [dbPath, `${dbPath}-wal`, `${dbPath}-shm`, `${dbPath}-journal`];
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
function isLastBoardForRepo(boardRow) {
|
|
31
|
+
const repoRoot = normalizePath(boardRow.repo_path || "");
|
|
32
|
+
return !listBoards().some((row) => row.id !== boardRow.id && normalizePath(row.repo_path || "") === repoRoot);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function repoArtifactTargets(boardRow) {
|
|
36
|
+
const repoRoot = normalizePath(boardRow.repo_path || "");
|
|
37
|
+
const dbPath = normalizePath(boardRow.db_path || "");
|
|
38
|
+
const orbitRoot = normalizePath(join(repoRoot, ".orbit"));
|
|
39
|
+
if (!repoRoot || !dbPath || !isInside(orbitRoot, dbPath) || basename(dbPath) !== "board.db") {
|
|
40
|
+
throw httpError(409, "unsafe_board_db_path");
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
orbitRoot,
|
|
44
|
+
skillMd: join(repoRoot, "SKILL-ORBIT.md")
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
29
48
|
export function deleteRegisteredBoard(boardRow, body, actor) {
|
|
30
49
|
requireBoardAccess(actor, { slug: boardRow.slug });
|
|
31
50
|
|
|
@@ -33,14 +52,37 @@ export function deleteRegisteredBoard(boardRow, body, actor) {
|
|
|
33
52
|
if (confirmation !== boardRow.slug) throw httpError(400, "board_slug_confirmation_required");
|
|
34
53
|
|
|
35
54
|
const deleteFiles = body?.delete_files !== false;
|
|
36
|
-
const
|
|
55
|
+
const removeRepoArtifacts = deleteFiles && isLastBoardForRepo(boardRow);
|
|
56
|
+
const repoArtifacts = removeRepoArtifacts ? repoArtifactTargets(boardRow) : null;
|
|
57
|
+
const targets = deleteFiles
|
|
58
|
+
? removeRepoArtifacts
|
|
59
|
+
? [repoArtifacts.orbitRoot]
|
|
60
|
+
: boardDbDeleteTargets(boardRow)
|
|
61
|
+
: [];
|
|
62
|
+
const artifactResults = [];
|
|
37
63
|
cancelAutomaticBoardBackup(boardRow.id);
|
|
38
64
|
if (deleteFiles) backupBoardDatabase(boardRow, openBoardDb(boardRow), "pre-board-delete");
|
|
39
65
|
backupRegistry("pre-board-delete");
|
|
40
66
|
closeConnection(boardRow.db_path);
|
|
41
67
|
|
|
42
68
|
for (const target of targets) {
|
|
43
|
-
if (existsSync(target))
|
|
69
|
+
if (existsSync(target)) {
|
|
70
|
+
rmSync(target, { recursive: true, force: true });
|
|
71
|
+
artifactResults.push({ path: target, removed: true });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (repoArtifacts?.skillMd && existsSync(repoArtifacts.skillMd)) {
|
|
75
|
+
unlinkSync(repoArtifacts.skillMd);
|
|
76
|
+
artifactResults.push({ path: repoArtifacts.skillMd, removed: true });
|
|
77
|
+
}
|
|
78
|
+
if (removeRepoArtifacts) {
|
|
79
|
+
const agentsCleanup = removeOrbitAgentsSection(boardRow.repo_path);
|
|
80
|
+
artifactResults.push({
|
|
81
|
+
path: agentsCleanup.path,
|
|
82
|
+
removed: agentsCleanup.removed,
|
|
83
|
+
ok: agentsCleanup.ok,
|
|
84
|
+
reason: agentsCleanup.reason
|
|
85
|
+
});
|
|
44
86
|
}
|
|
45
87
|
|
|
46
88
|
deleteBoard(boardRow.id);
|
|
@@ -48,6 +90,8 @@ export function deleteRegisteredBoard(boardRow, body, actor) {
|
|
|
48
90
|
ok: true,
|
|
49
91
|
deleted_board_id: boardRow.id,
|
|
50
92
|
deleted_board_slug: boardRow.slug,
|
|
51
|
-
deleted_files: deleteFiles
|
|
93
|
+
deleted_files: deleteFiles,
|
|
94
|
+
deleted_repo_artifacts: removeRepoArtifacts,
|
|
95
|
+
artifacts: artifactResults
|
|
52
96
|
};
|
|
53
97
|
}
|
|
@@ -45,7 +45,10 @@ export function provisionRepoBoard(repoPathRaw, options = {}) {
|
|
|
45
45
|
|
|
46
46
|
const db = openConnection(dbPath);
|
|
47
47
|
createBoardSchema(db);
|
|
48
|
-
const seeded = seedIfEmpty(db, repoRoot, {
|
|
48
|
+
const seeded = seedIfEmpty(db, repoRoot, {
|
|
49
|
+
enableAi: options.enableAi,
|
|
50
|
+
includeExamples: options.includeExamples
|
|
51
|
+
});
|
|
49
52
|
if (!seeded) {
|
|
50
53
|
const boardMeta = readBoardMetaFromSqlite(db);
|
|
51
54
|
if (!boardMeta) {
|
|
@@ -60,7 +63,10 @@ export function provisionRepoBoard(repoPathRaw, options = {}) {
|
|
|
60
63
|
function provisionExistingDbFile(repoRoot, dbPath, options = {}) {
|
|
61
64
|
const db = openConnection(dbPath);
|
|
62
65
|
createBoardSchema(db);
|
|
63
|
-
const seeded = seedIfEmpty(db, repoRoot, {
|
|
66
|
+
const seeded = seedIfEmpty(db, repoRoot, {
|
|
67
|
+
enableAi: options.enableAi,
|
|
68
|
+
includeExamples: options.includeExamples
|
|
69
|
+
});
|
|
64
70
|
if (seeded) {
|
|
65
71
|
return insertAfterSeed(repoRoot, dbPath, db, seeded, "repaired");
|
|
66
72
|
}
|
package/src/core/seed.js
CHANGED
|
@@ -23,8 +23,8 @@ export function seedIfEmpty(db, repoPath, options = {}) {
|
|
|
23
23
|
db.prepare(
|
|
24
24
|
`INSERT INTO boards
|
|
25
25
|
(id, slug, name, repo_url, system_path, default_branch,
|
|
26
|
-
project_notes, agent_instructions, created_at, updated_at)
|
|
27
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
26
|
+
project_notes, agent_instructions, ai_enabled, created_at, updated_at)
|
|
27
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
28
28
|
).run(
|
|
29
29
|
boardId,
|
|
30
30
|
seed.boardSlug,
|
|
@@ -34,17 +34,26 @@ export function seedIfEmpty(db, repoPath, options = {}) {
|
|
|
34
34
|
seed.defaultBranch,
|
|
35
35
|
seed.projectNotes,
|
|
36
36
|
seed.agentInstructions,
|
|
37
|
+
options.enableAi === false ? 0 : 1,
|
|
37
38
|
time,
|
|
38
39
|
time
|
|
39
40
|
);
|
|
40
41
|
|
|
41
|
-
const states = [
|
|
42
|
+
const states = options.enableAi === false ? [
|
|
42
43
|
["Backlog", null],
|
|
43
44
|
["Todo", null],
|
|
44
45
|
["In Progress", "in_progress"],
|
|
45
46
|
["Review", "review"],
|
|
46
47
|
["Done", "done"],
|
|
47
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]
|
|
48
57
|
];
|
|
49
58
|
const stateIds = new Map();
|
|
50
59
|
states.forEach(([name, role], position) => {
|
|
@@ -91,7 +100,7 @@ export function seedIfEmpty(db, repoPath, options = {}) {
|
|
|
91
100
|
const firstTicket = insertSeedTicket(db, boardId, 2, {
|
|
92
101
|
title: "Fill agent context & personal notes",
|
|
93
102
|
description:
|
|
94
|
-
"Open Settings → AI (Agent Instructions) and Settings → Notes, and
|
|
103
|
+
"Open Settings → AI (Agent Instructions) and Settings → Notes, and add real project context plus your own reminders.",
|
|
95
104
|
type: "feature",
|
|
96
105
|
parentTicketId: epicTicket,
|
|
97
106
|
stateId: stateIds.get("Todo"),
|
|
@@ -184,7 +193,6 @@ export function buildBoardFromRepo(projectRoot) {
|
|
|
184
193
|
"main";
|
|
185
194
|
const defaultProjectNotes =
|
|
186
195
|
"Personal reminders (Settings → Notes: Notes For You). Point yourself at SKILL-ORBIT.md, runbooks, or nudges for your tools.";
|
|
187
|
-
const defaultAgentInstructions = `Describe why ${boardName} exists, who it serves, and what success looks like. Add features, stack, constraints, and anything agents should know — this project-level context is provided to agents when they work on tickets.`;
|
|
188
196
|
return {
|
|
189
197
|
boardName,
|
|
190
198
|
boardSlug,
|
|
@@ -192,7 +200,7 @@ export function buildBoardFromRepo(projectRoot) {
|
|
|
192
200
|
systemPath,
|
|
193
201
|
defaultBranch,
|
|
194
202
|
projectNotes: readSeedValue("project_notes") || defaultProjectNotes,
|
|
195
|
-
agentInstructions: readSeedValue("agent_instructions") ||
|
|
203
|
+
agentInstructions: readSeedValue("agent_instructions") || ""
|
|
196
204
|
};
|
|
197
205
|
}
|
|
198
206
|
|