kanbo-cli 0.1.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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +79 -0
  3. package/dist/better-sqlite3-fU3G4xnX.cjs +2254 -0
  4. package/dist/better-sqlite3-fU3G4xnX.cjs.map +1 -0
  5. package/dist/cli.cjs +42949 -0
  6. package/dist/cli.cjs.map +1 -0
  7. package/dist/dist-Cd6wg8pp.cjs +942 -0
  8. package/dist/dist-Cd6wg8pp.cjs.map +1 -0
  9. package/dist/drizzle-postgres/0000_board.sql +135 -0
  10. package/dist/drizzle-postgres/0001_history_order.sql +2 -0
  11. package/dist/drizzle-postgres/0002_issue_pull_requests.sql +16 -0
  12. package/dist/drizzle-postgres/0003_milestone_start_date.sql +1 -0
  13. package/dist/drizzle-postgres/0004_status_entry_rules.sql +1 -0
  14. package/dist/drizzle-postgres/0005_run_external_session_ref.sql +1 -0
  15. package/dist/drizzle-postgres/README.md +61 -0
  16. package/dist/drizzle-postgres/meta/0000_snapshot.json +1078 -0
  17. package/dist/drizzle-postgres/meta/0001_snapshot.json +1090 -0
  18. package/dist/drizzle-postgres/meta/0002_snapshot.json +1239 -0
  19. package/dist/drizzle-postgres/meta/0003_snapshot.json +1245 -0
  20. package/dist/drizzle-postgres/meta/0004_snapshot.json +1251 -0
  21. package/dist/drizzle-postgres/meta/0005_snapshot.json +1257 -0
  22. package/dist/drizzle-postgres/meta/_journal.json +48 -0
  23. package/dist/drizzle-sqlite/0000_board.sql +133 -0
  24. package/dist/drizzle-sqlite/0001_issue_pull_requests.sql +15 -0
  25. package/dist/drizzle-sqlite/0002_milestone_start_date.sql +1 -0
  26. package/dist/drizzle-sqlite/0003_status_entry_rules.sql +1 -0
  27. package/dist/drizzle-sqlite/0004_run_external_session_ref.sql +1 -0
  28. package/dist/drizzle-sqlite/README.md +67 -0
  29. package/dist/drizzle-sqlite/meta/0000_snapshot.json +946 -0
  30. package/dist/drizzle-sqlite/meta/0001_snapshot.json +1054 -0
  31. package/dist/drizzle-sqlite/meta/0002_snapshot.json +1061 -0
  32. package/dist/drizzle-sqlite/meta/0003_snapshot.json +1068 -0
  33. package/dist/drizzle-sqlite/meta/0004_snapshot.json +1075 -0
  34. package/dist/drizzle-sqlite/meta/_journal.json +41 -0
  35. package/dist/lib/board-store-B16YarvX.d.mts +281 -0
  36. package/dist/lib/board-store-BHHo_ZlR.d.cts +281 -0
  37. package/dist/lib/index.cjs +340 -0
  38. package/dist/lib/index.cjs.map +1 -0
  39. package/dist/lib/index.d.cts +1608 -0
  40. package/dist/lib/index.d.mts +1608 -0
  41. package/dist/lib/index.mjs +284 -0
  42. package/dist/lib/index.mjs.map +1 -0
  43. package/dist/lib/manifest-C0EcwwgO.mjs +7866 -0
  44. package/dist/lib/manifest-C0EcwwgO.mjs.map +1 -0
  45. package/dist/lib/manifest-CpZOcB_6.cjs +8272 -0
  46. package/dist/lib/manifest-CpZOcB_6.cjs.map +1 -0
  47. package/dist/lib/mcp/index.cjs +184 -0
  48. package/dist/lib/mcp/index.cjs.map +1 -0
  49. package/dist/lib/mcp/index.d.cts +346 -0
  50. package/dist/lib/mcp/index.d.mts +346 -0
  51. package/dist/lib/mcp/index.mjs +173 -0
  52. package/dist/lib/mcp/index.mjs.map +1 -0
  53. package/dist/lib/migrate-BhYi9cXw.mjs +656 -0
  54. package/dist/lib/migrate-BhYi9cXw.mjs.map +1 -0
  55. package/dist/lib/migrate-DnMjTCvu.cjs +709 -0
  56. package/dist/lib/migrate-DnMjTCvu.cjs.map +1 -0
  57. package/dist/lib/migrations-path-CZxVOgeD.cjs +109 -0
  58. package/dist/lib/migrations-path-CZxVOgeD.cjs.map +1 -0
  59. package/dist/lib/migrations-path-Ciwan537.mjs +80 -0
  60. package/dist/lib/migrations-path-Ciwan537.mjs.map +1 -0
  61. package/dist/lib/postgres/index.cjs +56 -0
  62. package/dist/lib/postgres/index.cjs.map +1 -0
  63. package/dist/lib/postgres/index.d.cts +3403 -0
  64. package/dist/lib/postgres/index.d.mts +3403 -0
  65. package/dist/lib/postgres/index.mjs +35 -0
  66. package/dist/lib/postgres/index.mjs.map +1 -0
  67. package/dist/lib/roles.sql-B9rt-x4o.cjs +1033 -0
  68. package/dist/lib/roles.sql-B9rt-x4o.cjs.map +1 -0
  69. package/dist/lib/roles.sql-CvyCGt38.mjs +920 -0
  70. package/dist/lib/roles.sql-CvyCGt38.mjs.map +1 -0
  71. package/dist/lib/schema-epoch-ZyumVL_A.d.cts +16 -0
  72. package/dist/lib/schema-epoch-ZyumVL_A.d.mts +16 -0
  73. package/dist/lib/schema-fsHqNAip.d.cts +3612 -0
  74. package/dist/lib/schema-fsHqNAip.d.mts +3612 -0
  75. package/dist/lib/sqlite/index.cjs +23 -0
  76. package/dist/lib/sqlite/index.d.cts +175 -0
  77. package/dist/lib/sqlite/index.d.mts +175 -0
  78. package/dist/lib/sqlite/index.mjs +4 -0
  79. package/dist/lib/sqlite/schema.cjs +266 -0
  80. package/dist/lib/sqlite/schema.cjs.map +1 -0
  81. package/dist/lib/sqlite/schema.d.cts +2 -0
  82. package/dist/lib/sqlite/schema.d.mts +2 -0
  83. package/dist/lib/sqlite/schema.mjs +256 -0
  84. package/dist/lib/sqlite/schema.mjs.map +1 -0
  85. package/dist/lib/tool-names-9cmCn0gP.d.cts +112 -0
  86. package/dist/lib/tool-names-Dxg1UTUl.d.mts +112 -0
  87. package/dist/page/board.css +477 -0
  88. package/dist/page/board.js +2 -0
  89. package/drizzle-postgres/0000_board.sql +135 -0
  90. package/drizzle-postgres/0001_history_order.sql +2 -0
  91. package/drizzle-postgres/0002_issue_pull_requests.sql +16 -0
  92. package/drizzle-postgres/0003_milestone_start_date.sql +1 -0
  93. package/drizzle-postgres/0004_status_entry_rules.sql +1 -0
  94. package/drizzle-postgres/0005_run_external_session_ref.sql +1 -0
  95. package/drizzle-postgres/README.md +61 -0
  96. package/drizzle-postgres/meta/0000_snapshot.json +1078 -0
  97. package/drizzle-postgres/meta/0001_snapshot.json +1090 -0
  98. package/drizzle-postgres/meta/0002_snapshot.json +1239 -0
  99. package/drizzle-postgres/meta/0003_snapshot.json +1245 -0
  100. package/drizzle-postgres/meta/0004_snapshot.json +1251 -0
  101. package/drizzle-postgres/meta/0005_snapshot.json +1257 -0
  102. package/drizzle-postgres/meta/_journal.json +48 -0
  103. package/drizzle-sqlite/0000_board.sql +133 -0
  104. package/drizzle-sqlite/0001_issue_pull_requests.sql +15 -0
  105. package/drizzle-sqlite/0002_milestone_start_date.sql +1 -0
  106. package/drizzle-sqlite/0003_status_entry_rules.sql +1 -0
  107. package/drizzle-sqlite/0004_run_external_session_ref.sql +1 -0
  108. package/drizzle-sqlite/README.md +67 -0
  109. package/drizzle-sqlite/meta/0000_snapshot.json +946 -0
  110. package/drizzle-sqlite/meta/0001_snapshot.json +1054 -0
  111. package/drizzle-sqlite/meta/0002_snapshot.json +1061 -0
  112. package/drizzle-sqlite/meta/0003_snapshot.json +1068 -0
  113. package/drizzle-sqlite/meta/0004_snapshot.json +1075 -0
  114. package/drizzle-sqlite/meta/_journal.json +41 -0
  115. package/package.json +147 -0
@@ -0,0 +1,41 @@
1
+ {
2
+ "version": "7",
3
+ "dialect": "sqlite",
4
+ "entries": [
5
+ {
6
+ "idx": 0,
7
+ "version": "6",
8
+ "when": 1790170176198,
9
+ "tag": "0000_board",
10
+ "breakpoints": true
11
+ },
12
+ {
13
+ "idx": 1,
14
+ "version": "6",
15
+ "when": 1790227027024,
16
+ "tag": "0001_issue_pull_requests",
17
+ "breakpoints": true
18
+ },
19
+ {
20
+ "idx": 2,
21
+ "version": "6",
22
+ "when": 1790244864688,
23
+ "tag": "0002_milestone_start_date",
24
+ "breakpoints": true
25
+ },
26
+ {
27
+ "idx": 3,
28
+ "version": "6",
29
+ "when": 1790255381416,
30
+ "tag": "0003_status_entry_rules",
31
+ "breakpoints": true
32
+ },
33
+ {
34
+ "idx": 4,
35
+ "version": "6",
36
+ "when": 1790266700022,
37
+ "tag": "0004_run_external_session_ref",
38
+ "breakpoints": true
39
+ }
40
+ ]
41
+ }
@@ -0,0 +1,281 @@
1
+ import { _ as issueStatuses, a as IssuePullRequest, c as IssueStatus, d as issueComments, f as issueFieldChanges, g as issueRuns, h as issueRelations, i as IssueMilestone, l as KanbanMeta, m as issuePullRequests, n as IssueComment, o as IssueRelation, p as issueMilestones, r as IssueFieldChange, s as IssueRun, t as Issue, v as issues } from "./schema-fsHqNAip.mjs";
2
+ //#region src/board-store.d.ts
3
+ /** Workflow statuses of a workspace. */
4
+ interface IssueStatusStore {
5
+ /** Statuses of one workspace, in board order. */
6
+ listByWorkspace: (workspaceId: string) => Promise<IssueStatus[]>;
7
+ /** Every status, grouped by workspace, in board order within each workspace. */
8
+ listAllInBoardOrder: () => Promise<IssueStatus[]>;
9
+ /** Every status, in no particular order. */
10
+ listAll: () => Promise<IssueStatus[]>;
11
+ findById: (statusId: string) => Promise<IssueStatus | null>;
12
+ /** The status, only when it belongs to the given workspace. */
13
+ findInWorkspace: (workspaceId: string, statusId: string) => Promise<IssueStatus | null>;
14
+ countByWorkspace: (workspaceId: string) => Promise<number>;
15
+ create: (values: typeof issueStatuses.$inferInsert) => Promise<IssueStatus>;
16
+ update: (statusId: string, patch: Partial<typeof issueStatuses.$inferInsert>) => Promise<void>;
17
+ delete: (statusId: string) => Promise<void>;
18
+ }
19
+ /** Milestones of a workspace. */
20
+ interface IssueMilestoneStore {
21
+ /** Milestones, newest first. `null` spans every workspace. */
22
+ listNewestFirst: (workspaceId: string | null) => Promise<IssueMilestone[]>;
23
+ /** Milestones of one workspace, in no particular order. */
24
+ listByWorkspace: (workspaceId: string) => Promise<IssueMilestone[]>;
25
+ /** Every milestone, in no particular order. */
26
+ listAll: () => Promise<IssueMilestone[]>;
27
+ findById: (milestoneId: string) => Promise<IssueMilestone | null>;
28
+ /** The milestone, only when it belongs to the given workspace. */
29
+ findInWorkspace: (workspaceId: string, milestoneId: string) => Promise<IssueMilestone | null>;
30
+ create: (values: typeof issueMilestones.$inferInsert) => Promise<IssueMilestone>;
31
+ update: (milestoneId: string, patch: Partial<typeof issueMilestones.$inferInsert>) => Promise<void>;
32
+ delete: (milestoneId: string) => Promise<void>;
33
+ }
34
+ /** Issue rows themselves. */
35
+ interface IssueRowStore {
36
+ /** Issues in board order (`order`, then newest first). `null` spans every workspace. */
37
+ listInBoardOrder: (workspaceId: string | null) => Promise<Issue[]>;
38
+ /** Every issue, newest first. */
39
+ listNewestFirst: () => Promise<Issue[]>;
40
+ /** Every issue, in no particular order. */
41
+ listAll: () => Promise<Issue[]>;
42
+ /** Issues of one workspace, in no particular order. */
43
+ listByWorkspace: (workspaceId: string) => Promise<Issue[]>;
44
+ /** Issues with the given ids, in no particular order. Missing ids are simply absent. */
45
+ listByIds: (issueIds: string[]) => Promise<Issue[]>;
46
+ findById: (issueId: string) => Promise<Issue | null>;
47
+ /** The issue, only when it belongs to the given workspace. */
48
+ findInWorkspace: (workspaceId: string, issueId: string) => Promise<Issue | null>;
49
+ /** The issue carrying that number inside the workspace — the uniqueness constraint behind key generation. */
50
+ findByNumber: (workspaceId: string, number: number) => Promise<Issue | null>;
51
+ /** Highest issue number in the workspace, `0` when it holds no issues. */
52
+ maxNumber: (workspaceId: string) => Promise<number>;
53
+ /** Highest board position in the workspace, `0` when it holds no issues. */
54
+ maxOrder: (workspaceId: string) => Promise<number>;
55
+ create: (values: typeof issues.$inferInsert) => Promise<Issue>;
56
+ update: (issueId: string, patch: Partial<typeof issues.$inferInsert>) => Promise<void>;
57
+ /** Apply one patch to many issues; resolves to the number of rows written. */
58
+ updateMany: (issueIds: string[], patch: Partial<typeof issues.$inferInsert>) => Promise<number>;
59
+ /** Detach every issue that points at the deleted milestone. */
60
+ clearMilestoneReferences: (milestoneId: string, updatedAt: number) => Promise<void>;
61
+ /** Detach every child of the deleted parent issue. */
62
+ clearParentReferences: (parentIssueId: string, updatedAt: number) => Promise<void>;
63
+ /**
64
+ * Undelegate every card that names the deleted agent or provider target, and
65
+ * say how many were written.
66
+ *
67
+ * Both columns are soft references — an agent and a provider target are
68
+ * a host app's rows, and a board is carried by files that have no such tables
69
+ * (ruling 5-1) — so nothing in the database undoes a delegation when the row
70
+ * behind it goes. This is what the host calls instead, on every board it can
71
+ * reach. A card keeps its delegate *kind* nowhere else, so both columns are
72
+ * cleared together when either one matches.
73
+ */
74
+ clearDelegateReferences: (delegate: {
75
+ agentId: string;
76
+ } | {
77
+ providerTargetId: string;
78
+ }, updatedAt: number) => Promise<number>;
79
+ delete: (issueId: string) => Promise<void>;
80
+ }
81
+ /** Comments on an issue. */
82
+ interface IssueCommentStore {
83
+ /** Comments of one issue, oldest first. */
84
+ listByIssue: (issueId: string) => Promise<IssueComment[]>;
85
+ findById: (commentId: string) => Promise<IssueComment | null>;
86
+ /**
87
+ * The comment on that issue carrying `dedupeKey`, or `null` — one read of the
88
+ * unique `(issue_id, dedupe_key)` index. How a caller asks whether a card has
89
+ * already said something without reading every comment it holds.
90
+ */
91
+ findByDedupeKey: (issueId: string, dedupeKey: string) => Promise<IssueComment | null>;
92
+ /**
93
+ * The comments on that issue whose dedupe key starts with `prefix`, oldest
94
+ * first — how a caller finds the newest of a family of keys (a verdict per
95
+ * commit, say) without reading every comment the card holds. The prefix is
96
+ * matched literally: no character in it is a wildcard.
97
+ */
98
+ listByDedupeKeyPrefix: (issueId: string, prefix: string) => Promise<IssueComment[]>;
99
+ create: (values: typeof issueComments.$inferInsert) => Promise<IssueComment>;
100
+ /**
101
+ * Write the comment only if its issue does not carry `dedupeKey` yet, and
102
+ * return whichever row holds the key afterwards — the one just written or the
103
+ * one that was already there. The unique index on `(issue_id, dedupe_key)` is
104
+ * what makes this safe against a concurrent writer, so there is no
105
+ * read-then-write window to lose.
106
+ */
107
+ createOnce: (values: typeof issueComments.$inferInsert & {
108
+ dedupeKey: string;
109
+ }) => Promise<IssueComment>;
110
+ delete: (commentId: string) => Promise<void>;
111
+ }
112
+ /** One launch of a card, from the moment it starts until it ends. */
113
+ interface IssueRunStore {
114
+ /** Runs of one issue, oldest first. */
115
+ listByIssue: (issueId: string) => Promise<IssueRun[]>;
116
+ /** Runs of one issue that are still `running`, oldest first. */
117
+ listRunning: (issueId: string) => Promise<IssueRun[]>;
118
+ /**
119
+ * Every run still `running` that a chat session was driving, of any issue,
120
+ * oldest first.
121
+ *
122
+ * This is the board's answer to "what does the app that launched these still
123
+ * believe it is running", and the one run listing that spans the whole store: a host coming
124
+ * back up has no card in mind, it has a process that died under it. A run with
125
+ * no session behind it is left out — it belongs to a host the board knows
126
+ * nothing about, and is still going for all the board can tell.
127
+ */
128
+ listRunningWithSession: () => Promise<IssueRun[]>;
129
+ findById: (runId: string) => Promise<IssueRun | null>;
130
+ /** The newest run driving that chat session, across every issue. */
131
+ findByChatSessionId: (chatSessionId: string) => Promise<IssueRun | null>;
132
+ /** How many runs the issue has ever had — the attempt number of the next one, minus one. */
133
+ countByIssue: (issueId: string) => Promise<number>;
134
+ create: (values: typeof issueRuns.$inferInsert) => Promise<IssueRun>;
135
+ update: (runId: string, patch: Partial<typeof issueRuns.$inferInsert>) => Promise<void>;
136
+ /**
137
+ * The run facts a card list needs, for every card in scope, in one statement:
138
+ * how many runs it has had and which one is running now. Cards with no runs at
139
+ * all are simply absent from the result.
140
+ */
141
+ project: (scope: BoardRunProjectionScope) => Promise<BoardRunProjection[]>;
142
+ }
143
+ /** Which cards a projection covers: a whole workspace, or a named list. */
144
+ type BoardRunProjectionScope = {
145
+ workspaceId: string;
146
+ } | {
147
+ issueIds: string[];
148
+ };
149
+ /** The run of a card that is going on right now. */
150
+ interface BoardActiveRun {
151
+ id: string;
152
+ agentId: string | null;
153
+ agentName: string;
154
+ state: IssueRun['state'];
155
+ branch: string | null;
156
+ executionMode: IssueRun['executionMode'];
157
+ chatSessionId: string | null;
158
+ startedAt: number;
159
+ }
160
+ /** What the run table answers about one card. */
161
+ interface BoardRunProjection {
162
+ issueId: string;
163
+ /** Every run the card has ever had; the next launch is attempt `attemptCount + 1`. */
164
+ attemptCount: number;
165
+ /** The `running` run, or `null` when the newest run of the card has already ended. */
166
+ activeRun: BoardActiveRun | null;
167
+ }
168
+ /**
169
+ * The counters the board keeps for its readers, one row per key: `board`, bumped
170
+ * once per write transaction that changed something, and `schema_epoch`, the
171
+ * schema generation the file was written with.
172
+ */
173
+ interface KanbanMetaStore {
174
+ read: (key: string) => Promise<KanbanMeta | null>;
175
+ /** Raise the key's revision by one, creating the row at `1` when it is missing. */
176
+ bumpRevision: (key: string, updatedAt: number) => Promise<void>;
177
+ }
178
+ /** Edges between issues. */
179
+ interface IssueRelationStore {
180
+ /** Every edge touching the issue, in either direction. */
181
+ listByIssue: (issueId: string) => Promise<IssueRelation[]>;
182
+ findById: (relationId: string) => Promise<IssueRelation | null>;
183
+ /**
184
+ * The edge the unique `(source, target, type)` constraint would collide with.
185
+ * `relates_to` is undirected, so the reversed pair matches too.
186
+ */
187
+ findMatching: (edge: Pick<typeof issueRelations.$inferInsert, 'sourceIssueId' | 'targetIssueId' | 'type'>) => Promise<IssueRelation | null>;
188
+ create: (values: typeof issueRelations.$inferInsert) => Promise<IssueRelation>;
189
+ delete: (relationId: string) => Promise<void>;
190
+ /** Drop every edge touching the issue, in either direction. */
191
+ deleteByIssue: (issueId: string) => Promise<void>;
192
+ }
193
+ /**
194
+ * Context refs attached to an issue. They live in a column today, so the store —
195
+ * not the caller — owns how they are stored.
196
+ */
197
+ interface IssueContextRefStore {
198
+ /** Replace the whole ref list of one issue with the serialized value the caller built. */
199
+ replace: (issueId: string, contextRefs: Issue['contextRefs'], updatedAt: number) => Promise<void>;
200
+ }
201
+ /** Append-only audit of issue field edits. */
202
+ interface IssueFieldChangeStore {
203
+ /** Field changes of one issue, oldest first. */
204
+ listByIssue: (issueId: string) => Promise<IssueFieldChange[]>;
205
+ /** Field changes of one issue touching one field, oldest first. */
206
+ listByIssueField: (issueId: string, field: string) => Promise<IssueFieldChange[]>;
207
+ create: (values: typeof issueFieldChanges.$inferInsert) => Promise<void>;
208
+ }
209
+ /** A pull request a card names, with the workspace of that card — one row of `listLinked`. */
210
+ type BoardLinkedPullRequest = IssuePullRequest & {
211
+ workspaceId: string;
212
+ };
213
+ /** The pull requests cards name (ruling 4-1). The link only: what the pull request *is* stays GitHub's. */
214
+ interface IssuePullRequestStore {
215
+ /** Links of one card, in the order they were made. */
216
+ listByIssue: (issueId: string) => Promise<IssuePullRequest[]>;
217
+ /**
218
+ * Every link on the board, each with its card's workspace, in the order they
219
+ * were made — what a watcher reading GitHub for the whole board walks.
220
+ */
221
+ listLinked: () => Promise<BoardLinkedPullRequest[]>;
222
+ /**
223
+ * Name the pull request on the card, once. When the card already names that
224
+ * `(owner, repo, number)` the standing row comes back and nothing is written —
225
+ * the unique index settles a concurrent writer the same way.
226
+ */
227
+ link: (values: typeof issuePullRequests.$inferInsert) => Promise<IssuePullRequest>;
228
+ /** Drop one link of the card; the row that was removed, or `null` when the card named no such link. */
229
+ unlink: (issueId: string, linkId: string) => Promise<IssuePullRequest | null>;
230
+ }
231
+ /**
232
+ * How the outer transaction takes its write lock. `deferred` — the SQLite
233
+ * default — waits for the first write; `immediate` takes the lock up front, so
234
+ * two writers racing for the same board fail fast instead of half-way through.
235
+ * A transaction nested in another one takes no lock of its own, so the mode only
236
+ * reaches the outermost one.
237
+ *
238
+ * It is a board *file*'s lock, and a store whose engine has none ignores the
239
+ * mode entirely: Postgres locks rows as they are written, and the two races the
240
+ * board actually has are settled without a lock of their own — two writers
241
+ * numbering a card collide on the unique index over `(workspace_id, number)`,
242
+ * and two writers bumping the change counter meet in the `on conflict do
243
+ * update` on `kanban_meta`.
244
+ */
245
+ type BoardTransactionMode = 'deferred' | 'immediate';
246
+ /**
247
+ * Storage boundary of the board.
248
+ *
249
+ * The store moves rows in and out of the board tables (`issues`,
250
+ * `issue_statuses`, `issue_milestones`, `issue_comments`, `issue_runs`,
251
+ * `issue_relations`, `issue_field_changes`, `issue_pull_requests`, `kanban_meta`
252
+ * and context refs),
253
+ * holds their integrity constraints,
254
+ * and owns transactions across them. It carries no domain validation: a missing
255
+ * row comes back as `null`, an empty result as `[]`.
256
+ *
257
+ * Rows other owners write — workspaces, agents, provider targets — are not part
258
+ * of it. A host that needs them composes its own lookup group beside this one.
259
+ */
260
+ interface BoardStore {
261
+ statuses: IssueStatusStore;
262
+ milestones: IssueMilestoneStore;
263
+ issues: IssueRowStore;
264
+ comments: IssueCommentStore;
265
+ runs: IssueRunStore;
266
+ relations: IssueRelationStore;
267
+ contextRefs: IssueContextRefStore;
268
+ fieldChanges: IssueFieldChangeStore;
269
+ pullRequests: IssuePullRequestStore;
270
+ meta: KanbanMetaStore;
271
+ /**
272
+ * Run `fn` against a transactional view of the same store. Everything written
273
+ * through `tx` commits together, or none of it does.
274
+ */
275
+ transaction: <T>(fn: (tx: BoardStore) => Promise<T>, options?: {
276
+ mode?: BoardTransactionMode;
277
+ }) => Promise<T>;
278
+ }
279
+ //#endregion
280
+ export { BoardStore as a, IssueContextRefStore as c, IssuePullRequestStore as d, IssueRelationStore as f, KanbanMetaStore as g, IssueStatusStore as h, BoardRunProjectionScope as i, IssueFieldChangeStore as l, IssueRunStore as m, BoardLinkedPullRequest as n, BoardTransactionMode as o, IssueRowStore as p, BoardRunProjection as r, IssueCommentStore as s, BoardActiveRun as t, IssueMilestoneStore as u };
281
+ //# sourceMappingURL=board-store-B16YarvX.d.mts.map
@@ -0,0 +1,281 @@
1
+ import { _ as issueStatuses, a as IssuePullRequest, c as IssueStatus, d as issueComments, f as issueFieldChanges, g as issueRuns, h as issueRelations, i as IssueMilestone, l as KanbanMeta, m as issuePullRequests, n as IssueComment, o as IssueRelation, p as issueMilestones, r as IssueFieldChange, s as IssueRun, t as Issue, v as issues } from "./schema-fsHqNAip.cjs";
2
+ //#region src/board-store.d.ts
3
+ /** Workflow statuses of a workspace. */
4
+ interface IssueStatusStore {
5
+ /** Statuses of one workspace, in board order. */
6
+ listByWorkspace: (workspaceId: string) => Promise<IssueStatus[]>;
7
+ /** Every status, grouped by workspace, in board order within each workspace. */
8
+ listAllInBoardOrder: () => Promise<IssueStatus[]>;
9
+ /** Every status, in no particular order. */
10
+ listAll: () => Promise<IssueStatus[]>;
11
+ findById: (statusId: string) => Promise<IssueStatus | null>;
12
+ /** The status, only when it belongs to the given workspace. */
13
+ findInWorkspace: (workspaceId: string, statusId: string) => Promise<IssueStatus | null>;
14
+ countByWorkspace: (workspaceId: string) => Promise<number>;
15
+ create: (values: typeof issueStatuses.$inferInsert) => Promise<IssueStatus>;
16
+ update: (statusId: string, patch: Partial<typeof issueStatuses.$inferInsert>) => Promise<void>;
17
+ delete: (statusId: string) => Promise<void>;
18
+ }
19
+ /** Milestones of a workspace. */
20
+ interface IssueMilestoneStore {
21
+ /** Milestones, newest first. `null` spans every workspace. */
22
+ listNewestFirst: (workspaceId: string | null) => Promise<IssueMilestone[]>;
23
+ /** Milestones of one workspace, in no particular order. */
24
+ listByWorkspace: (workspaceId: string) => Promise<IssueMilestone[]>;
25
+ /** Every milestone, in no particular order. */
26
+ listAll: () => Promise<IssueMilestone[]>;
27
+ findById: (milestoneId: string) => Promise<IssueMilestone | null>;
28
+ /** The milestone, only when it belongs to the given workspace. */
29
+ findInWorkspace: (workspaceId: string, milestoneId: string) => Promise<IssueMilestone | null>;
30
+ create: (values: typeof issueMilestones.$inferInsert) => Promise<IssueMilestone>;
31
+ update: (milestoneId: string, patch: Partial<typeof issueMilestones.$inferInsert>) => Promise<void>;
32
+ delete: (milestoneId: string) => Promise<void>;
33
+ }
34
+ /** Issue rows themselves. */
35
+ interface IssueRowStore {
36
+ /** Issues in board order (`order`, then newest first). `null` spans every workspace. */
37
+ listInBoardOrder: (workspaceId: string | null) => Promise<Issue[]>;
38
+ /** Every issue, newest first. */
39
+ listNewestFirst: () => Promise<Issue[]>;
40
+ /** Every issue, in no particular order. */
41
+ listAll: () => Promise<Issue[]>;
42
+ /** Issues of one workspace, in no particular order. */
43
+ listByWorkspace: (workspaceId: string) => Promise<Issue[]>;
44
+ /** Issues with the given ids, in no particular order. Missing ids are simply absent. */
45
+ listByIds: (issueIds: string[]) => Promise<Issue[]>;
46
+ findById: (issueId: string) => Promise<Issue | null>;
47
+ /** The issue, only when it belongs to the given workspace. */
48
+ findInWorkspace: (workspaceId: string, issueId: string) => Promise<Issue | null>;
49
+ /** The issue carrying that number inside the workspace — the uniqueness constraint behind key generation. */
50
+ findByNumber: (workspaceId: string, number: number) => Promise<Issue | null>;
51
+ /** Highest issue number in the workspace, `0` when it holds no issues. */
52
+ maxNumber: (workspaceId: string) => Promise<number>;
53
+ /** Highest board position in the workspace, `0` when it holds no issues. */
54
+ maxOrder: (workspaceId: string) => Promise<number>;
55
+ create: (values: typeof issues.$inferInsert) => Promise<Issue>;
56
+ update: (issueId: string, patch: Partial<typeof issues.$inferInsert>) => Promise<void>;
57
+ /** Apply one patch to many issues; resolves to the number of rows written. */
58
+ updateMany: (issueIds: string[], patch: Partial<typeof issues.$inferInsert>) => Promise<number>;
59
+ /** Detach every issue that points at the deleted milestone. */
60
+ clearMilestoneReferences: (milestoneId: string, updatedAt: number) => Promise<void>;
61
+ /** Detach every child of the deleted parent issue. */
62
+ clearParentReferences: (parentIssueId: string, updatedAt: number) => Promise<void>;
63
+ /**
64
+ * Undelegate every card that names the deleted agent or provider target, and
65
+ * say how many were written.
66
+ *
67
+ * Both columns are soft references — an agent and a provider target are
68
+ * a host app's rows, and a board is carried by files that have no such tables
69
+ * (ruling 5-1) — so nothing in the database undoes a delegation when the row
70
+ * behind it goes. This is what the host calls instead, on every board it can
71
+ * reach. A card keeps its delegate *kind* nowhere else, so both columns are
72
+ * cleared together when either one matches.
73
+ */
74
+ clearDelegateReferences: (delegate: {
75
+ agentId: string;
76
+ } | {
77
+ providerTargetId: string;
78
+ }, updatedAt: number) => Promise<number>;
79
+ delete: (issueId: string) => Promise<void>;
80
+ }
81
+ /** Comments on an issue. */
82
+ interface IssueCommentStore {
83
+ /** Comments of one issue, oldest first. */
84
+ listByIssue: (issueId: string) => Promise<IssueComment[]>;
85
+ findById: (commentId: string) => Promise<IssueComment | null>;
86
+ /**
87
+ * The comment on that issue carrying `dedupeKey`, or `null` — one read of the
88
+ * unique `(issue_id, dedupe_key)` index. How a caller asks whether a card has
89
+ * already said something without reading every comment it holds.
90
+ */
91
+ findByDedupeKey: (issueId: string, dedupeKey: string) => Promise<IssueComment | null>;
92
+ /**
93
+ * The comments on that issue whose dedupe key starts with `prefix`, oldest
94
+ * first — how a caller finds the newest of a family of keys (a verdict per
95
+ * commit, say) without reading every comment the card holds. The prefix is
96
+ * matched literally: no character in it is a wildcard.
97
+ */
98
+ listByDedupeKeyPrefix: (issueId: string, prefix: string) => Promise<IssueComment[]>;
99
+ create: (values: typeof issueComments.$inferInsert) => Promise<IssueComment>;
100
+ /**
101
+ * Write the comment only if its issue does not carry `dedupeKey` yet, and
102
+ * return whichever row holds the key afterwards — the one just written or the
103
+ * one that was already there. The unique index on `(issue_id, dedupe_key)` is
104
+ * what makes this safe against a concurrent writer, so there is no
105
+ * read-then-write window to lose.
106
+ */
107
+ createOnce: (values: typeof issueComments.$inferInsert & {
108
+ dedupeKey: string;
109
+ }) => Promise<IssueComment>;
110
+ delete: (commentId: string) => Promise<void>;
111
+ }
112
+ /** One launch of a card, from the moment it starts until it ends. */
113
+ interface IssueRunStore {
114
+ /** Runs of one issue, oldest first. */
115
+ listByIssue: (issueId: string) => Promise<IssueRun[]>;
116
+ /** Runs of one issue that are still `running`, oldest first. */
117
+ listRunning: (issueId: string) => Promise<IssueRun[]>;
118
+ /**
119
+ * Every run still `running` that a chat session was driving, of any issue,
120
+ * oldest first.
121
+ *
122
+ * This is the board's answer to "what does the app that launched these still
123
+ * believe it is running", and the one run listing that spans the whole store: a host coming
124
+ * back up has no card in mind, it has a process that died under it. A run with
125
+ * no session behind it is left out — it belongs to a host the board knows
126
+ * nothing about, and is still going for all the board can tell.
127
+ */
128
+ listRunningWithSession: () => Promise<IssueRun[]>;
129
+ findById: (runId: string) => Promise<IssueRun | null>;
130
+ /** The newest run driving that chat session, across every issue. */
131
+ findByChatSessionId: (chatSessionId: string) => Promise<IssueRun | null>;
132
+ /** How many runs the issue has ever had — the attempt number of the next one, minus one. */
133
+ countByIssue: (issueId: string) => Promise<number>;
134
+ create: (values: typeof issueRuns.$inferInsert) => Promise<IssueRun>;
135
+ update: (runId: string, patch: Partial<typeof issueRuns.$inferInsert>) => Promise<void>;
136
+ /**
137
+ * The run facts a card list needs, for every card in scope, in one statement:
138
+ * how many runs it has had and which one is running now. Cards with no runs at
139
+ * all are simply absent from the result.
140
+ */
141
+ project: (scope: BoardRunProjectionScope) => Promise<BoardRunProjection[]>;
142
+ }
143
+ /** Which cards a projection covers: a whole workspace, or a named list. */
144
+ type BoardRunProjectionScope = {
145
+ workspaceId: string;
146
+ } | {
147
+ issueIds: string[];
148
+ };
149
+ /** The run of a card that is going on right now. */
150
+ interface BoardActiveRun {
151
+ id: string;
152
+ agentId: string | null;
153
+ agentName: string;
154
+ state: IssueRun['state'];
155
+ branch: string | null;
156
+ executionMode: IssueRun['executionMode'];
157
+ chatSessionId: string | null;
158
+ startedAt: number;
159
+ }
160
+ /** What the run table answers about one card. */
161
+ interface BoardRunProjection {
162
+ issueId: string;
163
+ /** Every run the card has ever had; the next launch is attempt `attemptCount + 1`. */
164
+ attemptCount: number;
165
+ /** The `running` run, or `null` when the newest run of the card has already ended. */
166
+ activeRun: BoardActiveRun | null;
167
+ }
168
+ /**
169
+ * The counters the board keeps for its readers, one row per key: `board`, bumped
170
+ * once per write transaction that changed something, and `schema_epoch`, the
171
+ * schema generation the file was written with.
172
+ */
173
+ interface KanbanMetaStore {
174
+ read: (key: string) => Promise<KanbanMeta | null>;
175
+ /** Raise the key's revision by one, creating the row at `1` when it is missing. */
176
+ bumpRevision: (key: string, updatedAt: number) => Promise<void>;
177
+ }
178
+ /** Edges between issues. */
179
+ interface IssueRelationStore {
180
+ /** Every edge touching the issue, in either direction. */
181
+ listByIssue: (issueId: string) => Promise<IssueRelation[]>;
182
+ findById: (relationId: string) => Promise<IssueRelation | null>;
183
+ /**
184
+ * The edge the unique `(source, target, type)` constraint would collide with.
185
+ * `relates_to` is undirected, so the reversed pair matches too.
186
+ */
187
+ findMatching: (edge: Pick<typeof issueRelations.$inferInsert, 'sourceIssueId' | 'targetIssueId' | 'type'>) => Promise<IssueRelation | null>;
188
+ create: (values: typeof issueRelations.$inferInsert) => Promise<IssueRelation>;
189
+ delete: (relationId: string) => Promise<void>;
190
+ /** Drop every edge touching the issue, in either direction. */
191
+ deleteByIssue: (issueId: string) => Promise<void>;
192
+ }
193
+ /**
194
+ * Context refs attached to an issue. They live in a column today, so the store —
195
+ * not the caller — owns how they are stored.
196
+ */
197
+ interface IssueContextRefStore {
198
+ /** Replace the whole ref list of one issue with the serialized value the caller built. */
199
+ replace: (issueId: string, contextRefs: Issue['contextRefs'], updatedAt: number) => Promise<void>;
200
+ }
201
+ /** Append-only audit of issue field edits. */
202
+ interface IssueFieldChangeStore {
203
+ /** Field changes of one issue, oldest first. */
204
+ listByIssue: (issueId: string) => Promise<IssueFieldChange[]>;
205
+ /** Field changes of one issue touching one field, oldest first. */
206
+ listByIssueField: (issueId: string, field: string) => Promise<IssueFieldChange[]>;
207
+ create: (values: typeof issueFieldChanges.$inferInsert) => Promise<void>;
208
+ }
209
+ /** A pull request a card names, with the workspace of that card — one row of `listLinked`. */
210
+ type BoardLinkedPullRequest = IssuePullRequest & {
211
+ workspaceId: string;
212
+ };
213
+ /** The pull requests cards name (ruling 4-1). The link only: what the pull request *is* stays GitHub's. */
214
+ interface IssuePullRequestStore {
215
+ /** Links of one card, in the order they were made. */
216
+ listByIssue: (issueId: string) => Promise<IssuePullRequest[]>;
217
+ /**
218
+ * Every link on the board, each with its card's workspace, in the order they
219
+ * were made — what a watcher reading GitHub for the whole board walks.
220
+ */
221
+ listLinked: () => Promise<BoardLinkedPullRequest[]>;
222
+ /**
223
+ * Name the pull request on the card, once. When the card already names that
224
+ * `(owner, repo, number)` the standing row comes back and nothing is written —
225
+ * the unique index settles a concurrent writer the same way.
226
+ */
227
+ link: (values: typeof issuePullRequests.$inferInsert) => Promise<IssuePullRequest>;
228
+ /** Drop one link of the card; the row that was removed, or `null` when the card named no such link. */
229
+ unlink: (issueId: string, linkId: string) => Promise<IssuePullRequest | null>;
230
+ }
231
+ /**
232
+ * How the outer transaction takes its write lock. `deferred` — the SQLite
233
+ * default — waits for the first write; `immediate` takes the lock up front, so
234
+ * two writers racing for the same board fail fast instead of half-way through.
235
+ * A transaction nested in another one takes no lock of its own, so the mode only
236
+ * reaches the outermost one.
237
+ *
238
+ * It is a board *file*'s lock, and a store whose engine has none ignores the
239
+ * mode entirely: Postgres locks rows as they are written, and the two races the
240
+ * board actually has are settled without a lock of their own — two writers
241
+ * numbering a card collide on the unique index over `(workspace_id, number)`,
242
+ * and two writers bumping the change counter meet in the `on conflict do
243
+ * update` on `kanban_meta`.
244
+ */
245
+ type BoardTransactionMode = 'deferred' | 'immediate';
246
+ /**
247
+ * Storage boundary of the board.
248
+ *
249
+ * The store moves rows in and out of the board tables (`issues`,
250
+ * `issue_statuses`, `issue_milestones`, `issue_comments`, `issue_runs`,
251
+ * `issue_relations`, `issue_field_changes`, `issue_pull_requests`, `kanban_meta`
252
+ * and context refs),
253
+ * holds their integrity constraints,
254
+ * and owns transactions across them. It carries no domain validation: a missing
255
+ * row comes back as `null`, an empty result as `[]`.
256
+ *
257
+ * Rows other owners write — workspaces, agents, provider targets — are not part
258
+ * of it. A host that needs them composes its own lookup group beside this one.
259
+ */
260
+ interface BoardStore {
261
+ statuses: IssueStatusStore;
262
+ milestones: IssueMilestoneStore;
263
+ issues: IssueRowStore;
264
+ comments: IssueCommentStore;
265
+ runs: IssueRunStore;
266
+ relations: IssueRelationStore;
267
+ contextRefs: IssueContextRefStore;
268
+ fieldChanges: IssueFieldChangeStore;
269
+ pullRequests: IssuePullRequestStore;
270
+ meta: KanbanMetaStore;
271
+ /**
272
+ * Run `fn` against a transactional view of the same store. Everything written
273
+ * through `tx` commits together, or none of it does.
274
+ */
275
+ transaction: <T>(fn: (tx: BoardStore) => Promise<T>, options?: {
276
+ mode?: BoardTransactionMode;
277
+ }) => Promise<T>;
278
+ }
279
+ //#endregion
280
+ export { BoardStore as a, IssueContextRefStore as c, IssuePullRequestStore as d, IssueRelationStore as f, KanbanMetaStore as g, IssueStatusStore as h, BoardRunProjectionScope as i, IssueFieldChangeStore as l, IssueRunStore as m, BoardLinkedPullRequest as n, BoardTransactionMode as o, IssueRowStore as p, BoardRunProjection as r, IssueCommentStore as s, BoardActiveRun as t, IssueMilestoneStore as u };
281
+ //# sourceMappingURL=board-store-BHHo_ZlR.d.cts.map