@sascha384/tic 1.34.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/backends/availability.js +4 -2
  3. package/dist/backends/availability.js.map +1 -1
  4. package/dist/backends/factory.d.ts +5 -3
  5. package/dist/backends/factory.js +28 -43
  6. package/dist/backends/factory.js.map +1 -1
  7. package/dist/backends/files/hash.d.ts +1 -0
  8. package/dist/backends/files/hash.js +5 -0
  9. package/dist/backends/files/hash.js.map +1 -0
  10. package/dist/backends/files/index.d.ts +48 -0
  11. package/dist/backends/files/index.js +174 -0
  12. package/dist/backends/files/index.js.map +1 -0
  13. package/dist/backends/files/sync.d.ts +13 -0
  14. package/dist/backends/files/sync.js +69 -0
  15. package/dist/backends/files/sync.js.map +1 -0
  16. package/dist/backends/jira/config.d.ts +1 -1
  17. package/dist/backends/jira/config.js +6 -9
  18. package/dist/backends/jira/config.js.map +1 -1
  19. package/dist/backends/types.d.ts +12 -0
  20. package/dist/backends/types.js +5 -1
  21. package/dist/backends/types.js.map +1 -1
  22. package/dist/cli/commands/config.js +27 -14
  23. package/dist/cli/commands/config.js.map +1 -1
  24. package/dist/cli/commands/init.js +10 -3
  25. package/dist/cli/commands/init.js.map +1 -1
  26. package/dist/cli/commands/mcp.d.ts +4 -4
  27. package/dist/cli/commands/mcp.js +16 -25
  28. package/dist/cli/commands/mcp.js.map +1 -1
  29. package/dist/cli/index.js +16 -19
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/commands.d.ts +2 -0
  32. package/dist/commands.js +33 -0
  33. package/dist/commands.js.map +1 -1
  34. package/dist/components/Header.js +9 -2
  35. package/dist/components/Header.js.map +1 -1
  36. package/dist/components/HelpScreen.js +3 -0
  37. package/dist/components/HelpScreen.js.map +1 -1
  38. package/dist/components/OverlayPanel.d.ts +2 -1
  39. package/dist/components/OverlayPanel.js +14 -1
  40. package/dist/components/OverlayPanel.js.map +1 -1
  41. package/dist/components/Settings.js +6 -11
  42. package/dist/components/Settings.js.map +1 -1
  43. package/dist/components/StatusScreen.js +29 -4
  44. package/dist/components/StatusScreen.js.map +1 -1
  45. package/dist/components/WorkItemForm.js +6 -9
  46. package/dist/components/WorkItemForm.js.map +1 -1
  47. package/dist/components/WorkItemList.js +353 -36
  48. package/dist/components/WorkItemList.js.map +1 -1
  49. package/dist/filters.d.ts +28 -0
  50. package/dist/filters.js +47 -0
  51. package/dist/filters.js.map +1 -0
  52. package/dist/implement.js +4 -56
  53. package/dist/implement.js.map +1 -1
  54. package/dist/index.js +20 -8
  55. package/dist/index.js.map +1 -1
  56. package/dist/storage/config.d.ts +61 -0
  57. package/dist/storage/config.js +309 -0
  58. package/dist/storage/config.js.map +1 -0
  59. package/dist/storage/db.d.ts +11 -0
  60. package/dist/storage/db.js +34 -0
  61. package/dist/storage/db.js.map +1 -0
  62. package/dist/storage/index.d.ts +73 -0
  63. package/dist/storage/index.js +966 -0
  64. package/dist/storage/index.js.map +1 -0
  65. package/dist/storage/mappers.d.ts +35 -0
  66. package/dist/storage/mappers.js +70 -0
  67. package/dist/storage/mappers.js.map +1 -0
  68. package/dist/storage/schema.d.ts +1844 -0
  69. package/dist/storage/schema.js +197 -0
  70. package/dist/storage/schema.js.map +1 -0
  71. package/dist/storage/syncQueue.d.ts +13 -0
  72. package/dist/storage/syncQueue.js +98 -0
  73. package/dist/storage/syncQueue.js.map +1 -0
  74. package/dist/storage/undo.d.ts +22 -0
  75. package/dist/storage/undo.js +129 -0
  76. package/dist/storage/undo.js.map +1 -0
  77. package/dist/stores/backendDataStore.d.ts +4 -1
  78. package/dist/stores/backendDataStore.js +61 -40
  79. package/dist/stores/backendDataStore.js.map +1 -1
  80. package/dist/stores/configStore.d.ts +3 -1
  81. package/dist/stores/configStore.js +25 -65
  82. package/dist/stores/configStore.js.map +1 -1
  83. package/dist/stores/filterStore.d.ts +13 -0
  84. package/dist/stores/filterStore.js +38 -0
  85. package/dist/stores/filterStore.js.map +1 -0
  86. package/dist/stores/listViewStore.d.ts +1 -0
  87. package/dist/stores/listViewStore.js +1 -0
  88. package/dist/stores/listViewStore.js.map +1 -1
  89. package/dist/stores/uiStore.d.ts +8 -0
  90. package/dist/stores/uiStore.js.map +1 -1
  91. package/dist/stores/undoStore.d.ts +4 -0
  92. package/dist/stores/undoStore.js +32 -0
  93. package/dist/stores/undoStore.js.map +1 -1
  94. package/dist/sync/SyncManager.d.ts +5 -4
  95. package/dist/sync/SyncManager.js +129 -36
  96. package/dist/sync/SyncManager.js.map +1 -1
  97. package/dist/sync/types.d.ts +25 -1
  98. package/package.json +5 -1
  99. package/dist/backends/local/config.d.ts +0 -23
  100. package/dist/backends/local/config.js +0 -42
  101. package/dist/backends/local/config.js.map +0 -1
  102. package/dist/backends/local/index.d.ts +0 -45
  103. package/dist/backends/local/index.js +0 -291
  104. package/dist/backends/local/index.js.map +0 -1
  105. package/dist/sync/queue.d.ts +0 -12
  106. package/dist/sync/queue.js +0 -56
  107. package/dist/sync/queue.js.map +0 -1
@@ -0,0 +1,309 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { eq } from 'drizzle-orm';
4
+ import { createDatabase } from './db.js';
5
+ import * as schema from './schema.js';
6
+ export const defaultConfig = {
7
+ backend: 'none',
8
+ types: ['epic', 'issue', 'task'],
9
+ statuses: ['backlog', 'todo', 'in-progress', 'review', 'done'],
10
+ current_iteration: 'default',
11
+ iterations: ['default'],
12
+ next_id: 1,
13
+ branchMode: 'worktree',
14
+ autoUpdate: true,
15
+ branchCommand: `claude "Brainstorm the implementation of issue #$TIC_ITEM_ID: $TIC_ITEM_TITLE. $TIC_ITEM_DESCRIPTION"`,
16
+ copyToClipboard: true,
17
+ };
18
+ /**
19
+ * Read just the backend type from the SQLite database synchronously.
20
+ * Used by CLI's `tryGetCapabilities()` which runs at startup before
21
+ * any async work. Returns 'none' if the DB doesn't exist yet.
22
+ */
23
+ export function readBackendTypeSync(root) {
24
+ const dbPath = path.join(root, '.tic', 'tic.db');
25
+ if (!fs.existsSync(dbPath))
26
+ return 'none';
27
+ const db = createDatabase(root);
28
+ try {
29
+ const row = db
30
+ .select({ backend: schema.projectConfig.backend })
31
+ .from(schema.projectConfig)
32
+ .where(eq(schema.projectConfig.id, 1))
33
+ .get();
34
+ const backend = row?.backend ?? 'none';
35
+ // 'drizzle' is the seed default — treat it as 'none' for capability lookup
36
+ return backend === 'drizzle' ? 'none' : backend;
37
+ }
38
+ finally {
39
+ db.close();
40
+ }
41
+ }
42
+ /**
43
+ * Read the full Config from the SQLite database.
44
+ */
45
+ export function readConfig(db) {
46
+ // 1. Read projectConfig singleton (id=1)
47
+ const pc = db
48
+ .select()
49
+ .from(schema.projectConfig)
50
+ .where(eq(schema.projectConfig.id, 1))
51
+ .get();
52
+ // 2. Read ordered arrays
53
+ const statusRows = db
54
+ .select()
55
+ .from(schema.statuses)
56
+ .orderBy(schema.statuses.sortOrder)
57
+ .all();
58
+ const typeRows = db
59
+ .select()
60
+ .from(schema.workItemTypes)
61
+ .orderBy(schema.workItemTypes.sortOrder)
62
+ .all();
63
+ const iterationRows = db
64
+ .select()
65
+ .from(schema.iterations)
66
+ .orderBy(schema.iterations.sortOrder)
67
+ .all();
68
+ // 3. Read jiraConfig singleton
69
+ const jc = db
70
+ .select()
71
+ .from(schema.jiraConfig)
72
+ .where(eq(schema.jiraConfig.id, 1))
73
+ .get();
74
+ // 4. Read saved views with filters and sort entries
75
+ const viewRows = db.select().from(schema.savedViews).all();
76
+ const filterRows = db.select().from(schema.savedViewFilters).all();
77
+ const sortRows = db
78
+ .select()
79
+ .from(schema.savedViewSortEntries)
80
+ .orderBy(schema.savedViewSortEntries.sortOrder)
81
+ .all();
82
+ // Build the config object
83
+ const config = {
84
+ backend: pc?.backend ?? 'drizzle',
85
+ statuses: statusRows.map((r) => r.name),
86
+ types: typeRows.map((r) => r.name),
87
+ current_iteration: pc?.currentIteration ?? '',
88
+ iterations: iterationRows.map((r) => r.name),
89
+ next_id: pc?.nextId ?? 1,
90
+ branchMode: pc?.branchMode ?? 'worktree',
91
+ autoUpdate: pc?.autoUpdate ?? true,
92
+ };
93
+ // Optional fields — only include when they have non-default values
94
+ if (pc?.defaultType && pc.defaultType !== '') {
95
+ config.defaultType = pc.defaultType;
96
+ }
97
+ if (pc?.showDetailPanel === true) {
98
+ config.showDetailPanel = true;
99
+ }
100
+ if (pc?.branchCommand && pc.branchCommand !== '') {
101
+ config.branchCommand = pc.branchCommand;
102
+ }
103
+ if (pc?.copyToClipboard !== undefined) {
104
+ config.copyToClipboard = pc.copyToClipboard;
105
+ }
106
+ if (pc?.defaultView && pc.defaultView !== '') {
107
+ config.defaultView = pc.defaultView;
108
+ }
109
+ // Jira — only include if site is non-empty
110
+ if (jc && jc.site !== '') {
111
+ const jira = {
112
+ site: jc.site,
113
+ project: jc.project,
114
+ };
115
+ if (jc.boardId !== '') {
116
+ jira.boardId = Number(jc.boardId);
117
+ }
118
+ config.jira = jira;
119
+ }
120
+ // Views — only include if there are any
121
+ if (viewRows.length > 0) {
122
+ // Group filters by view name and field
123
+ const filtersByView = new Map();
124
+ for (const f of filterRows) {
125
+ let viewFilters = filtersByView.get(f.viewName);
126
+ if (!viewFilters) {
127
+ viewFilters = new Map();
128
+ filtersByView.set(f.viewName, viewFilters);
129
+ }
130
+ let fieldValues = viewFilters.get(f.field);
131
+ if (!fieldValues) {
132
+ fieldValues = [];
133
+ viewFilters.set(f.field, fieldValues);
134
+ }
135
+ fieldValues.push(f.value);
136
+ }
137
+ // Group sort entries by view name
138
+ const sortByView = new Map();
139
+ for (const s of sortRows) {
140
+ let viewSort = sortByView.get(s.viewName);
141
+ if (!viewSort) {
142
+ viewSort = [];
143
+ sortByView.set(s.viewName, viewSort);
144
+ }
145
+ viewSort.push({ column: s.column, direction: s.direction });
146
+ }
147
+ config.views = viewRows.map((v) => {
148
+ const viewFilters = filtersByView.get(v.name);
149
+ const filters = {};
150
+ if (viewFilters) {
151
+ for (const [field, values] of viewFilters) {
152
+ filters[field] = values;
153
+ }
154
+ }
155
+ const result = {
156
+ name: v.name,
157
+ filters,
158
+ };
159
+ const viewSort = sortByView.get(v.name);
160
+ if (viewSort && viewSort.length > 0) {
161
+ result.sort = viewSort;
162
+ }
163
+ return result;
164
+ });
165
+ }
166
+ return config;
167
+ }
168
+ /**
169
+ * Insert (or replace) the full Config into the database tables using
170
+ * the given transaction handle. Shared by `writeConfig` and the legacy
171
+ * migration so the insertion logic is defined in exactly one place.
172
+ */
173
+ export function insertConfigTx(tx, config) {
174
+ // 1. Upsert projectConfig singleton
175
+ tx.insert(schema.projectConfig)
176
+ .values({
177
+ id: 1,
178
+ backend: config.backend,
179
+ currentIteration: config.current_iteration,
180
+ nextId: config.next_id,
181
+ branchMode: config.branchMode,
182
+ branchCommand: config.branchCommand ?? '',
183
+ copyToClipboard: config.copyToClipboard ?? true,
184
+ autoUpdate: config.autoUpdate,
185
+ defaultType: config.defaultType ?? '',
186
+ showDetailPanel: config.showDetailPanel ?? false,
187
+ defaultView: config.defaultView ?? '',
188
+ })
189
+ .onConflictDoUpdate({
190
+ target: schema.projectConfig.id,
191
+ set: {
192
+ backend: config.backend,
193
+ currentIteration: config.current_iteration,
194
+ nextId: config.next_id,
195
+ branchMode: config.branchMode,
196
+ branchCommand: config.branchCommand ?? '',
197
+ copyToClipboard: config.copyToClipboard ?? true,
198
+ autoUpdate: config.autoUpdate,
199
+ defaultType: config.defaultType ?? '',
200
+ showDetailPanel: config.showDetailPanel ?? false,
201
+ defaultView: config.defaultView ?? '',
202
+ },
203
+ })
204
+ .run();
205
+ // 2. Replace statuses
206
+ tx.delete(schema.statuses).run();
207
+ for (let i = 0; i < config.statuses.length; i++) {
208
+ tx.insert(schema.statuses)
209
+ .values({ name: config.statuses[i], sortOrder: i })
210
+ .run();
211
+ }
212
+ // 3. Replace types
213
+ tx.delete(schema.workItemTypes).run();
214
+ for (let i = 0; i < config.types.length; i++) {
215
+ tx.insert(schema.workItemTypes)
216
+ .values({ name: config.types[i], sortOrder: i })
217
+ .run();
218
+ }
219
+ // 4. Replace iterations
220
+ tx.delete(schema.iterations).run();
221
+ for (let i = 0; i < config.iterations.length; i++) {
222
+ tx.insert(schema.iterations)
223
+ .values({ name: config.iterations[i], sortOrder: i })
224
+ .run();
225
+ }
226
+ // 5. Upsert jiraConfig
227
+ if (config.jira) {
228
+ tx.insert(schema.jiraConfig)
229
+ .values({
230
+ id: 1,
231
+ site: config.jira.site,
232
+ project: config.jira.project,
233
+ boardId: config.jira.boardId !== undefined ? String(config.jira.boardId) : '',
234
+ })
235
+ .onConflictDoUpdate({
236
+ target: schema.jiraConfig.id,
237
+ set: {
238
+ site: config.jira.site,
239
+ project: config.jira.project,
240
+ boardId: config.jira.boardId !== undefined
241
+ ? String(config.jira.boardId)
242
+ : '',
243
+ },
244
+ })
245
+ .run();
246
+ }
247
+ else {
248
+ // Clear jira config by setting to empty values
249
+ tx.insert(schema.jiraConfig)
250
+ .values({ id: 1, site: '', project: '', boardId: '' })
251
+ .onConflictDoUpdate({
252
+ target: schema.jiraConfig.id,
253
+ set: { site: '', project: '', boardId: '' },
254
+ })
255
+ .run();
256
+ }
257
+ // 6. Replace saved views (cascade deletes filters and sort entries)
258
+ tx.delete(schema.savedViews).run();
259
+ if (config.views && config.views.length > 0) {
260
+ for (const view of config.views) {
261
+ tx.insert(schema.savedViews).values({ name: view.name }).run();
262
+ // Insert filters
263
+ const filters = view.filters;
264
+ if (filters) {
265
+ for (const [field, values] of Object.entries(filters)) {
266
+ if (values && values.length > 0) {
267
+ for (const value of values) {
268
+ tx.insert(schema.savedViewFilters)
269
+ .values({ viewName: view.name, field, value })
270
+ .run();
271
+ }
272
+ }
273
+ }
274
+ }
275
+ // Insert sort entries
276
+ if (view.sort && view.sort.length > 0) {
277
+ for (let i = 0; i < view.sort.length; i++) {
278
+ const s = view.sort[i];
279
+ tx.insert(schema.savedViewSortEntries)
280
+ .values({
281
+ viewName: view.name,
282
+ column: s.column,
283
+ direction: s.direction,
284
+ sortOrder: i,
285
+ })
286
+ .run();
287
+ }
288
+ }
289
+ }
290
+ }
291
+ }
292
+ /**
293
+ * Write the full Config to the SQLite database, replacing all existing data.
294
+ * Uses a transaction to keep tables consistent.
295
+ */
296
+ export function writeConfig(db, config) {
297
+ db.transaction((tx) => {
298
+ insertConfigTx(tx, config);
299
+ });
300
+ }
301
+ /**
302
+ * Read the current config, merge partial updates over it, and write back.
303
+ */
304
+ export function updateConfig(db, partial) {
305
+ const current = readConfig(db);
306
+ const merged = { ...current, ...partial };
307
+ writeConfig(db, merged);
308
+ }
309
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/storage/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import Database from 'better-sqlite3';
2
+ import { type BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
3
+ import * as schema from './schema.js';
4
+ export type TicDatabase = BetterSQLite3Database<typeof schema> & {
5
+ close(): void;
6
+ /** Access raw better-sqlite3 instance when needed */
7
+ raw: Database.Database;
8
+ };
9
+ /** Transaction handle passed to `db.transaction()` callbacks. */
10
+ export type TicTransaction = Parameters<Parameters<TicDatabase['transaction']>[0]>[0];
11
+ export declare function createDatabase(root: string): TicDatabase;
@@ -0,0 +1,34 @@
1
+ import Database from 'better-sqlite3';
2
+ import { drizzle, } from 'drizzle-orm/better-sqlite3';
3
+ import { migrate } from 'drizzle-orm/better-sqlite3/migrator';
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import * as schema from './schema.js';
7
+ export function createDatabase(root) {
8
+ const isMemory = root === ':memory:';
9
+ let dbPath;
10
+ if (isMemory) {
11
+ dbPath = ':memory:';
12
+ }
13
+ else {
14
+ const ticDir = path.join(root, '.tic');
15
+ fs.mkdirSync(ticDir, { recursive: true });
16
+ dbPath = path.join(ticDir, 'tic.db');
17
+ }
18
+ const sqlite = new Database(dbPath);
19
+ // Enable WAL mode for concurrent access (TUI + MCP + CLI)
20
+ if (!isMemory) {
21
+ sqlite.pragma('journal_mode = WAL');
22
+ }
23
+ // Enable foreign key constraints
24
+ sqlite.pragma('foreign_keys = ON');
25
+ const db = drizzle(sqlite, { schema });
26
+ // Apply migrations
27
+ const migrationsFolder = path.join(import.meta.dirname, '../../drizzle');
28
+ migrate(db, { migrationsFolder });
29
+ const ticDb = db;
30
+ ticDb.close = () => sqlite.close();
31
+ ticDb.raw = sqlite;
32
+ return ticDb;
33
+ }
34
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/storage/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EACL,OAAO,GAER,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAC;AAC9D,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAatC,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,QAAQ,GAAG,IAAI,KAAK,UAAU,CAAC;IACrC,IAAI,MAAc,CAAC;IAEnB,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,GAAG,UAAU,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpC,0DAA0D;IAC1D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACtC,CAAC;IAED,iCAAiC;IACjC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAEnC,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAEvC,mBAAmB;IACnB,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACzE,OAAO,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAElC,MAAM,KAAK,GAAG,EAA4B,CAAC;IAC3C,KAAK,CAAC,KAAK,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACnC,KAAK,CAAC,GAAG,GAAG,MAAM,CAAC;IAEnB,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,73 @@
1
+ import { BaseBackend } from '../backends/types.js';
2
+ import type { BackendCapabilities, SoftDeleteBackend } from '../backends/types.js';
3
+ import type { WorkItem, NewWorkItem, NewComment, Comment, Template } from '../types.js';
4
+ import { type TicDatabase } from './db.js';
5
+ export interface StorageOptions {
6
+ tempIds?: boolean;
7
+ }
8
+ export declare class Storage extends BaseBackend implements SoftDeleteBackend {
9
+ private db;
10
+ private root;
11
+ private tempIds;
12
+ private constructor();
13
+ /**
14
+ * Create a Storage instance, initializing the database and seeding defaults.
15
+ */
16
+ static create(root: string, options?: StorageOptions): Storage;
17
+ /**
18
+ * Create a Storage instance from an existing database instance (for testing).
19
+ */
20
+ static createFromDb(db: TicDatabase, options?: StorageOptions): Storage;
21
+ getDatabase(): TicDatabase;
22
+ getRoot(): string;
23
+ /**
24
+ * Seed default configuration, statuses, types, and iterations using INSERT OR IGNORE.
25
+ */
26
+ private seedDefaults;
27
+ /**
28
+ * If a legacy config.yml exists and the DB still has seed defaults,
29
+ * migrate the YAML config into the database and rename the file.
30
+ */
31
+ private migrateFromYaml;
32
+ /**
33
+ * Close the database connection. Call this when done with the backend.
34
+ */
35
+ destroy(): void;
36
+ getCapabilities(): BackendCapabilities;
37
+ getStatuses(): Promise<string[]>;
38
+ getIterations(): Promise<string[]>;
39
+ getWorkItemTypes(): Promise<string[]>;
40
+ getAssignees(): Promise<string[]>;
41
+ getLabels(): Promise<string[]>;
42
+ getCurrentIteration(): Promise<string>;
43
+ setCurrentIteration(name: string): Promise<void>;
44
+ listWorkItems(iteration?: string): Promise<WorkItem[]>;
45
+ getWorkItem(id: string): Promise<WorkItem>;
46
+ getChildren(id: string): Promise<WorkItem[]>;
47
+ getDependents(id: string): Promise<WorkItem[]>;
48
+ /**
49
+ * Helper: given a set of work item rows, fetch their labels/deps/comments and assemble.
50
+ */
51
+ private assembleWorkItems;
52
+ getItemUrl(id: string): string;
53
+ private validateRelationships;
54
+ createWorkItem(data: NewWorkItem): Promise<WorkItem>;
55
+ importWorkItem(item: WorkItem): Promise<WorkItem>;
56
+ updateWorkItem(id: string, data: Partial<WorkItem>): Promise<WorkItem>;
57
+ deleteWorkItem(id: string): Promise<void>;
58
+ softDeleteWorkItem(id: string): Promise<void>;
59
+ addComment(workItemId: string, comment: NewComment): Promise<Comment>;
60
+ restoreWorkItem(id: string): Promise<void>;
61
+ permanentlyDeleteWorkItem(id: string): Promise<void>;
62
+ cleanupTrash(): Promise<void>;
63
+ openItem(id: string): Promise<void>;
64
+ /**
65
+ * Slugify a template name (same logic as LocalBackend).
66
+ */
67
+ private slugifyName;
68
+ listTemplates(): Promise<Template[]>;
69
+ getTemplate(slug: string): Promise<Template>;
70
+ createTemplate(template: Template): Promise<Template>;
71
+ updateTemplate(oldSlug: string, template: Template): Promise<Template>;
72
+ deleteTemplate(slug: string): Promise<void>;
73
+ }