@sudocode-ai/cli 0.1.0 → 0.1.2

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 (112) hide show
  1. package/dist/cli/feedback-commands.d.ts.map +1 -0
  2. package/dist/cli/feedback-commands.js +274 -0
  3. package/dist/cli/feedback-commands.js.map +1 -0
  4. package/dist/cli/init-commands.d.ts.map +1 -0
  5. package/dist/cli/init-commands.js +148 -0
  6. package/dist/cli/init-commands.js.map +1 -0
  7. package/dist/cli/issue-commands.d.ts.map +1 -0
  8. package/dist/cli/issue-commands.js +310 -0
  9. package/dist/cli/issue-commands.js.map +1 -0
  10. package/dist/cli/query-commands.d.ts.map +1 -0
  11. package/dist/cli/query-commands.js +61 -0
  12. package/dist/cli/query-commands.js.map +1 -0
  13. package/dist/cli/reference-commands.d.ts.map +1 -0
  14. package/dist/cli/reference-commands.js +136 -0
  15. package/dist/cli/reference-commands.js.map +1 -0
  16. package/dist/cli/relationship-commands.d.ts.map +1 -0
  17. package/dist/cli/relationship-commands.js +76 -0
  18. package/dist/cli/relationship-commands.js.map +1 -0
  19. package/dist/cli/server-commands.d.ts.map +1 -0
  20. package/dist/cli/server-commands.js +99 -0
  21. package/dist/cli/server-commands.js.map +1 -0
  22. package/dist/cli/spec-commands.d.ts.map +1 -0
  23. package/dist/cli/spec-commands.js +321 -0
  24. package/dist/cli/spec-commands.js.map +1 -0
  25. package/dist/cli/status-commands.d.ts.map +1 -0
  26. package/dist/cli/status-commands.js +131 -0
  27. package/dist/cli/status-commands.js.map +1 -0
  28. package/dist/cli/sync-commands.d.ts.map +1 -0
  29. package/dist/cli/sync-commands.js +416 -0
  30. package/dist/cli/sync-commands.js.map +1 -0
  31. package/dist/cli/update-commands.d.ts.map +1 -0
  32. package/dist/cli/update-commands.js +78 -0
  33. package/dist/cli/update-commands.js.map +1 -0
  34. package/dist/cli.d.ts.map +1 -0
  35. package/dist/cli.js +425 -195
  36. package/dist/cli.js.map +1 -0
  37. package/dist/db.d.ts.map +1 -0
  38. package/dist/db.js +54 -0
  39. package/dist/db.js.map +1 -0
  40. package/dist/export.d.ts.map +1 -0
  41. package/dist/export.js +195 -0
  42. package/dist/export.js.map +1 -0
  43. package/dist/filename-generator.d.ts.map +1 -0
  44. package/dist/filename-generator.js +93 -0
  45. package/dist/filename-generator.js.map +1 -0
  46. package/dist/id-generator.d.ts.map +1 -0
  47. package/dist/id-generator.js +123 -0
  48. package/dist/id-generator.js.map +1 -0
  49. package/dist/import.d.ts.map +1 -0
  50. package/dist/import.js +608 -0
  51. package/dist/import.js.map +1 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +13 -189
  54. package/dist/index.js.map +1 -0
  55. package/dist/jsonl.d.ts.map +1 -0
  56. package/dist/jsonl.js +333 -0
  57. package/dist/jsonl.js.map +1 -0
  58. package/dist/markdown.d.ts.map +1 -0
  59. package/dist/markdown.js +357 -0
  60. package/dist/markdown.js.map +1 -0
  61. package/dist/migrations.d.ts.map +1 -0
  62. package/dist/migrations.js +57 -0
  63. package/dist/migrations.js.map +1 -0
  64. package/dist/operations/events.d.ts.map +1 -0
  65. package/dist/operations/events.js +108 -0
  66. package/dist/operations/events.js.map +1 -0
  67. package/dist/operations/feedback-anchors.d.ts.map +1 -0
  68. package/dist/operations/feedback-anchors.js +444 -0
  69. package/dist/operations/feedback-anchors.js.map +1 -0
  70. package/dist/operations/feedback.d.ts.map +1 -0
  71. package/dist/operations/feedback.js +234 -0
  72. package/dist/operations/feedback.js.map +1 -0
  73. package/dist/operations/index.d.ts.map +1 -0
  74. package/dist/operations/index.js +10 -0
  75. package/dist/operations/index.js.map +1 -0
  76. package/dist/operations/issues.d.ts.map +1 -0
  77. package/dist/operations/issues.js +411 -0
  78. package/dist/operations/issues.js.map +1 -0
  79. package/dist/operations/references.d.ts.map +1 -0
  80. package/dist/operations/references.js +117 -0
  81. package/dist/operations/references.js.map +1 -0
  82. package/dist/operations/relationships.d.ts.map +1 -0
  83. package/dist/operations/relationships.js +236 -0
  84. package/dist/operations/relationships.js.map +1 -0
  85. package/dist/operations/specs.d.ts.map +1 -0
  86. package/dist/operations/specs.js +290 -0
  87. package/dist/operations/specs.js.map +1 -0
  88. package/dist/operations/tags.d.ts.map +1 -0
  89. package/dist/operations/tags.js +127 -0
  90. package/dist/operations/tags.js.map +1 -0
  91. package/dist/operations/transactions.d.ts.map +1 -0
  92. package/dist/operations/transactions.js +111 -0
  93. package/dist/operations/transactions.js.map +1 -0
  94. package/dist/sync.d.ts.map +1 -0
  95. package/dist/sync.js +442 -0
  96. package/dist/sync.js.map +1 -0
  97. package/dist/test-schema.d.ts.map +1 -0
  98. package/dist/test-schema.js +46 -0
  99. package/dist/test-schema.js.map +1 -0
  100. package/dist/types.d.ts.map +1 -0
  101. package/dist/types.js +7 -0
  102. package/dist/types.js.map +1 -0
  103. package/dist/update-checker.d.ts.map +1 -0
  104. package/dist/update-checker.js +151 -0
  105. package/dist/update-checker.js.map +1 -0
  106. package/dist/version.d.ts.map +1 -0
  107. package/dist/version.js +23 -0
  108. package/dist/version.js.map +1 -0
  109. package/dist/watcher.d.ts.map +1 -0
  110. package/dist/watcher.js +438 -0
  111. package/dist/watcher.js.map +1 -0
  112. package/package.json +4 -7
@@ -0,0 +1,234 @@
1
+ /**
2
+ * CRUD operations for Issue Feedback
3
+ */
4
+ /**
5
+ * Convert raw database row to IssueFeedback with proper types
6
+ * SQLite stores booleans as integers (0/1), so we need to convert
7
+ */
8
+ function convertDbRowToFeedback(row) {
9
+ return {
10
+ ...row,
11
+ dismissed: row.dismissed === 1,
12
+ };
13
+ }
14
+ /**
15
+ * Generate next feedback ID (FB-001, FB-002, etc.)
16
+ */
17
+ export function generateFeedbackId(db) {
18
+ const stmt = db.prepare(`
19
+ SELECT id FROM issue_feedback ORDER BY id DESC LIMIT 1
20
+ `);
21
+ const lastFeedback = stmt.get();
22
+ if (!lastFeedback) {
23
+ return "FB-001";
24
+ }
25
+ const match = lastFeedback.id.match(/^FB-(\d+)$/);
26
+ if (!match) {
27
+ return "FB-001";
28
+ }
29
+ const nextNum = parseInt(match[1], 10) + 1;
30
+ return `FB-${String(nextNum).padStart(3, "0")}`;
31
+ }
32
+ /**
33
+ * Create a new feedback entry
34
+ */
35
+ export function createFeedback(db, input) {
36
+ const id = input.id || generateFeedbackId(db);
37
+ const anchorJson = input.anchor ? JSON.stringify(input.anchor) : null;
38
+ const agent = input.agent || "user";
39
+ // Get issue_uuid and spec_uuid
40
+ const issue = db.prepare(`SELECT uuid FROM issues WHERE id = ?`).get(input.issue_id);
41
+ if (!issue) {
42
+ throw new Error(`Issue not found: ${input.issue_id}`);
43
+ }
44
+ const spec = db.prepare(`SELECT uuid FROM specs WHERE id = ?`).get(input.spec_id);
45
+ if (!spec) {
46
+ throw new Error(`Spec not found: ${input.spec_id}`);
47
+ }
48
+ const stmt = db.prepare(`
49
+ INSERT INTO issue_feedback (
50
+ id, issue_id, issue_uuid, spec_id, spec_uuid, feedback_type, content, agent, anchor, dismissed
51
+ ) VALUES (
52
+ @id, @issue_id, @issue_uuid, @spec_id, @spec_uuid, @feedback_type, @content, @agent, @anchor, @dismissed
53
+ )
54
+ `);
55
+ try {
56
+ stmt.run({
57
+ id,
58
+ issue_id: input.issue_id,
59
+ issue_uuid: issue.uuid,
60
+ spec_id: input.spec_id,
61
+ spec_uuid: spec.uuid,
62
+ feedback_type: input.feedback_type,
63
+ content: input.content,
64
+ agent: agent,
65
+ anchor: anchorJson,
66
+ dismissed: input.dismissed !== undefined ? (input.dismissed ? 1 : 0) : 0,
67
+ });
68
+ const feedback = getFeedback(db, id);
69
+ if (!feedback) {
70
+ throw new Error(`Failed to create feedback ${id}`);
71
+ }
72
+ return feedback;
73
+ }
74
+ catch (error) {
75
+ if (error.code && error.code.startsWith("SQLITE_CONSTRAINT")) {
76
+ throw new Error(`Constraint violation: ${error.message}`);
77
+ }
78
+ throw error;
79
+ }
80
+ }
81
+ /**
82
+ * Get a feedback entry by ID
83
+ */
84
+ export function getFeedback(db, id) {
85
+ const stmt = db.prepare(`
86
+ SELECT * FROM issue_feedback WHERE id = ?
87
+ `);
88
+ const row = stmt.get(id);
89
+ return row ? convertDbRowToFeedback(row) : null;
90
+ }
91
+ /**
92
+ * Update a feedback entry
93
+ */
94
+ export function updateFeedback(db, id, input) {
95
+ const existing = getFeedback(db, id);
96
+ if (!existing) {
97
+ throw new Error(`Feedback not found: ${id}`);
98
+ }
99
+ const updates = [];
100
+ const params = { id };
101
+ if (input.content !== undefined) {
102
+ updates.push("content = @content");
103
+ params.content = input.content;
104
+ }
105
+ if (input.dismissed !== undefined) {
106
+ updates.push("dismissed = @dismissed");
107
+ params.dismissed = input.dismissed ? 1 : 0;
108
+ }
109
+ if (input.anchor !== undefined) {
110
+ updates.push("anchor = @anchor");
111
+ params.anchor = JSON.stringify(input.anchor);
112
+ }
113
+ updates.push("updated_at = CURRENT_TIMESTAMP");
114
+ if (updates.length === 1) {
115
+ // Only updated_at changed, return existing
116
+ return existing;
117
+ }
118
+ const stmt = db.prepare(`
119
+ UPDATE issue_feedback SET ${updates.join(", ")} WHERE id = @id
120
+ `);
121
+ try {
122
+ stmt.run(params);
123
+ const updated = getFeedback(db, id);
124
+ if (!updated) {
125
+ throw new Error(`Failed to update feedback ${id}`);
126
+ }
127
+ return updated;
128
+ }
129
+ catch (error) {
130
+ if (error.code && error.code.startsWith("SQLITE_CONSTRAINT")) {
131
+ throw new Error(`Constraint violation: ${error.message}`);
132
+ }
133
+ throw error;
134
+ }
135
+ }
136
+ /**
137
+ * Delete a feedback entry
138
+ */
139
+ export function deleteFeedback(db, id) {
140
+ const stmt = db.prepare(`DELETE FROM issue_feedback WHERE id = ?`);
141
+ const result = stmt.run(id);
142
+ return result.changes > 0;
143
+ }
144
+ /**
145
+ * Dismiss feedback (convenience method)
146
+ */
147
+ export function dismissFeedback(db, id) {
148
+ return updateFeedback(db, id, { dismissed: true });
149
+ }
150
+ /**
151
+ * List feedback entries with optional filters
152
+ */
153
+ export function listFeedback(db, options = {}) {
154
+ const conditions = [];
155
+ const params = {};
156
+ if (options.issue_id !== undefined) {
157
+ conditions.push("issue_id = @issue_id");
158
+ params.issue_id = options.issue_id;
159
+ }
160
+ if (options.spec_id !== undefined) {
161
+ conditions.push("spec_id = @spec_id");
162
+ params.spec_id = options.spec_id;
163
+ }
164
+ if (options.feedback_type !== undefined) {
165
+ conditions.push("feedback_type = @feedback_type");
166
+ params.feedback_type = options.feedback_type;
167
+ }
168
+ if (options.dismissed !== undefined) {
169
+ conditions.push("dismissed = @dismissed");
170
+ params.dismissed = options.dismissed ? 1 : 0;
171
+ }
172
+ let query = "SELECT * FROM issue_feedback";
173
+ if (conditions.length > 0) {
174
+ query += " WHERE " + conditions.join(" AND ");
175
+ }
176
+ query += " ORDER BY created_at DESC";
177
+ if (options.limit !== undefined) {
178
+ query += " LIMIT @limit";
179
+ params.limit = options.limit;
180
+ }
181
+ if (options.offset !== undefined) {
182
+ query += " OFFSET @offset";
183
+ params.offset = options.offset;
184
+ }
185
+ const stmt = db.prepare(query);
186
+ const rows = stmt.all(params);
187
+ return rows.map(convertDbRowToFeedback);
188
+ }
189
+ /**
190
+ * Get all feedback for a specific issue
191
+ */
192
+ export function getFeedbackForIssue(db, issue_id) {
193
+ return listFeedback(db, { issue_id });
194
+ }
195
+ /**
196
+ * Get all feedback for a specific spec
197
+ */
198
+ export function getFeedbackForSpec(db, spec_id) {
199
+ return listFeedback(db, { spec_id });
200
+ }
201
+ /**
202
+ * Get active feedback for a spec (not dismissed)
203
+ */
204
+ export function getActiveFeedbackForSpec(db, spec_id) {
205
+ return listFeedback(db, { spec_id, dismissed: false });
206
+ }
207
+ /**
208
+ * Count feedback by dismissed status
209
+ */
210
+ export function countFeedbackByDismissed(db, spec_id) {
211
+ let query = "SELECT dismissed, COUNT(*) as count FROM issue_feedback";
212
+ const params = {};
213
+ if (spec_id) {
214
+ query += " WHERE spec_id = @spec_id";
215
+ params.spec_id = spec_id;
216
+ }
217
+ query += " GROUP BY dismissed";
218
+ const stmt = db.prepare(query);
219
+ const rows = stmt.all(params);
220
+ const counts = {
221
+ active: 0,
222
+ dismissed: 0,
223
+ };
224
+ for (const row of rows) {
225
+ if (row.dismissed === 0) {
226
+ counts.active = row.count;
227
+ }
228
+ else {
229
+ counts.dismissed = row.count;
230
+ }
231
+ }
232
+ return counts;
233
+ }
234
+ //# sourceMappingURL=feedback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback.js","sourceRoot":"","sources":["../../src/operations/feedback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/operations/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Main entry point for all database operations
3
+ */
4
+ export * from './specs.js';
5
+ export * from './issues.js';
6
+ export * from './relationships.js';
7
+ export * from './tags.js';
8
+ export * from './events.js';
9
+ export * from './references.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/operations/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/operations/issues.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,411 @@
1
+ /**
2
+ * CRUD operations for Issues
3
+ */
4
+ import { generateUUID } from "../id-generator.js";
5
+ import { getIncomingRelationships } from "./relationships.js";
6
+ /**
7
+ * Create a new issue
8
+ */
9
+ export function createIssue(db, input) {
10
+ // Validate parent_id exists if provided and get parent_uuid
11
+ let parent_uuid = null;
12
+ if (input.parent_id) {
13
+ const parent = getIssue(db, input.parent_id);
14
+ if (!parent) {
15
+ throw new Error(`Parent issue not found: ${input.parent_id}`);
16
+ }
17
+ parent_uuid = parent.uuid;
18
+ }
19
+ const uuid = input.uuid || generateUUID();
20
+ // Build INSERT statement with optional timestamp fields
21
+ const columns = [
22
+ "id",
23
+ "uuid",
24
+ "title",
25
+ "content",
26
+ "status",
27
+ "priority",
28
+ "assignee",
29
+ "parent_id",
30
+ "parent_uuid",
31
+ "archived",
32
+ ];
33
+ const values = [
34
+ "@id",
35
+ "@uuid",
36
+ "@title",
37
+ "@content",
38
+ "@status",
39
+ "@priority",
40
+ "@assignee",
41
+ "@parent_id",
42
+ "@parent_uuid",
43
+ "@archived",
44
+ ];
45
+ if (input.created_at) {
46
+ columns.push("created_at");
47
+ values.push("@created_at");
48
+ }
49
+ if (input.updated_at) {
50
+ columns.push("updated_at");
51
+ values.push("@updated_at");
52
+ }
53
+ if (input.closed_at !== undefined) {
54
+ columns.push("closed_at");
55
+ values.push("@closed_at");
56
+ }
57
+ if (input.archived_at !== undefined) {
58
+ columns.push("archived_at");
59
+ values.push("@archived_at");
60
+ }
61
+ const stmt = db.prepare(`
62
+ INSERT INTO issues (
63
+ ${columns.join(", ")}
64
+ ) VALUES (
65
+ ${values.join(", ")}
66
+ )
67
+ ON CONFLICT(id) DO UPDATE SET
68
+ uuid = excluded.uuid,
69
+ title = excluded.title,
70
+ content = excluded.content,
71
+ status = excluded.status,
72
+ priority = excluded.priority,
73
+ assignee = excluded.assignee,
74
+ parent_id = excluded.parent_id,
75
+ parent_uuid = excluded.parent_uuid,
76
+ archived = excluded.archived,
77
+ archived_at = excluded.archived_at,
78
+ ${input.created_at ? "created_at = excluded.created_at," : ""}
79
+ ${input.updated_at ? "updated_at = excluded.updated_at" : "updated_at = CURRENT_TIMESTAMP"}
80
+ `);
81
+ try {
82
+ const params = {
83
+ id: input.id,
84
+ uuid: uuid,
85
+ title: input.title,
86
+ content: input.content || "",
87
+ status: input.status || "open",
88
+ priority: input.priority ?? 2,
89
+ assignee: input.assignee ?? null,
90
+ parent_id: input.parent_id ?? null,
91
+ parent_uuid: parent_uuid,
92
+ archived: input.archived ? 1 : 0,
93
+ };
94
+ // Add optional timestamp parameters
95
+ if (input.created_at) {
96
+ params.created_at = input.created_at;
97
+ }
98
+ if (input.updated_at) {
99
+ params.updated_at = input.updated_at;
100
+ }
101
+ if (input.closed_at !== undefined) {
102
+ params.closed_at = input.closed_at;
103
+ }
104
+ if (input.archived_at !== undefined) {
105
+ params.archived_at = input.archived_at;
106
+ }
107
+ stmt.run(params);
108
+ const issue = getIssue(db, input.id);
109
+ if (!issue) {
110
+ throw new Error(`Failed to create issue ${input.id}`);
111
+ }
112
+ return issue;
113
+ }
114
+ catch (error) {
115
+ if (error.code && error.code.startsWith("SQLITE_CONSTRAINT")) {
116
+ throw new Error(`Constraint violation: ${error.message}`);
117
+ }
118
+ throw error;
119
+ }
120
+ }
121
+ /**
122
+ * Get an issue by ID
123
+ */
124
+ export function getIssue(db, id) {
125
+ const stmt = db.prepare(`
126
+ SELECT * FROM issues WHERE id = ?
127
+ `);
128
+ return stmt.get(id) ?? null;
129
+ }
130
+ /**
131
+ * Update an issue
132
+ */
133
+ export function updateIssue(db, id, input) {
134
+ const existing = getIssue(db, id);
135
+ if (!existing) {
136
+ throw new Error(`Issue not found: ${id}`);
137
+ }
138
+ // Validate parent_id exists if provided
139
+ if (input.parent_id) {
140
+ const parent = getIssue(db, input.parent_id);
141
+ if (!parent) {
142
+ throw new Error(`Parent issue not found: ${input.parent_id}`);
143
+ }
144
+ }
145
+ const updates = [];
146
+ const params = { id };
147
+ if (input.title !== undefined && input.title !== existing.title) {
148
+ updates.push("title = @title");
149
+ params.title = input.title;
150
+ }
151
+ if (input.content !== undefined && input.content !== existing.content) {
152
+ updates.push("content = @content");
153
+ params.content = input.content;
154
+ }
155
+ if (input.status !== undefined && input.status !== existing.status) {
156
+ updates.push("status = @status");
157
+ params.status = input.status;
158
+ // Handle closed_at based on status changes
159
+ // Use input.closed_at if provided, otherwise auto-set based on status
160
+ if (input.closed_at !== undefined) {
161
+ // Explicit closed_at provided - use it
162
+ updates.push("closed_at = @closed_at");
163
+ params.closed_at = input.closed_at;
164
+ }
165
+ else if (input.status === "closed" && existing.status !== "closed") {
166
+ // Status changing to 'closed' - set timestamp
167
+ updates.push("closed_at = CURRENT_TIMESTAMP");
168
+ }
169
+ else if (input.status !== "closed" && existing.status === "closed") {
170
+ // Reopening - clear timestamp
171
+ updates.push("closed_at = NULL");
172
+ }
173
+ }
174
+ else if (input.closed_at !== undefined &&
175
+ input.closed_at !== existing.closed_at) {
176
+ // closed_at provided without status change
177
+ updates.push("closed_at = @closed_at");
178
+ params.closed_at = input.closed_at;
179
+ }
180
+ if (input.priority !== undefined && input.priority !== existing.priority) {
181
+ updates.push("priority = @priority");
182
+ params.priority = input.priority;
183
+ }
184
+ if (input.assignee !== undefined && input.assignee !== existing.assignee) {
185
+ updates.push("assignee = @assignee");
186
+ params.assignee = input.assignee;
187
+ }
188
+ if (input.parent_id !== undefined && input.parent_id !== existing.parent_id) {
189
+ updates.push("parent_id = @parent_id");
190
+ params.parent_id = input.parent_id;
191
+ }
192
+ if (input.archived !== undefined &&
193
+ (input.archived ? 1 : 0) !== existing.archived) {
194
+ updates.push("archived = @archived");
195
+ params.archived = input.archived ? 1 : 0;
196
+ // Handle archived_at based on archived changes
197
+ // Use input.archived_at if provided, otherwise auto-set based on archived
198
+ if (input.archived_at !== undefined) {
199
+ // Explicit archived_at provided - use it
200
+ updates.push("archived_at = @archived_at");
201
+ params.archived_at = input.archived_at;
202
+ }
203
+ else if (input.archived && !existing.archived) {
204
+ // Archiving - set timestamp
205
+ updates.push("archived_at = CURRENT_TIMESTAMP");
206
+ }
207
+ else if (!input.archived && existing.archived) {
208
+ // Unarchiving - clear timestamp
209
+ updates.push("archived_at = NULL");
210
+ }
211
+ }
212
+ else if (input.archived_at !== undefined &&
213
+ input.archived_at !== existing.archived_at) {
214
+ // archived_at provided without archived change
215
+ updates.push("archived_at = @archived_at");
216
+ params.archived_at = input.archived_at;
217
+ }
218
+ // Handle updated_at - use provided value or set to current timestamp
219
+ if (input.updated_at !== undefined) {
220
+ updates.push("updated_at = @updated_at");
221
+ params.updated_at = input.updated_at;
222
+ }
223
+ else if (updates.length > 0) {
224
+ // Only update timestamp if there are actual changes
225
+ updates.push("updated_at = CURRENT_TIMESTAMP");
226
+ }
227
+ if (updates.length === 0) {
228
+ return existing;
229
+ }
230
+ const stmt = db.prepare(`
231
+ UPDATE issues SET ${updates.join(", ")} WHERE id = @id
232
+ `);
233
+ try {
234
+ stmt.run(params);
235
+ const updated = getIssue(db, id);
236
+ if (!updated) {
237
+ throw new Error(`Failed to update issue ${id}`);
238
+ }
239
+ // If status changed to 'closed', update any dependent blocked issues
240
+ if (input.status === "closed" && existing.status !== "closed") {
241
+ updateDependentBlockedIssues(db, id);
242
+ }
243
+ return updated;
244
+ }
245
+ catch (error) {
246
+ if (error.code && error.code.startsWith("SQLITE_CONSTRAINT")) {
247
+ throw new Error(`Constraint violation: ${error.message}`);
248
+ }
249
+ throw error;
250
+ }
251
+ }
252
+ /**
253
+ * Update status of issues that were blocked by the given issue
254
+ * Called when a blocker issue is closed
255
+ */
256
+ function updateDependentBlockedIssues(db, closedIssueId) {
257
+ // Find all issues that are blocked by this issue
258
+ // (issues that have a 'blocks' relationship pointing to this issue)
259
+ const dependentRelationships = getIncomingRelationships(db, closedIssueId, "issue", "blocks");
260
+ for (const rel of dependentRelationships) {
261
+ const blockedIssueId = rel.from_id;
262
+ const blockedIssue = getIssue(db, blockedIssueId);
263
+ // Only update if the issue is currently marked as 'blocked'
264
+ if (!blockedIssue || blockedIssue.status !== "blocked") {
265
+ continue;
266
+ }
267
+ // Check if this issue has any other open/in_progress/blocked blockers
268
+ const hasOtherBlockers = hasOpenBlockers(db, blockedIssueId, closedIssueId);
269
+ // If no other blockers, update status from 'blocked' to 'open'
270
+ if (!hasOtherBlockers) {
271
+ const updateStmt = db.prepare(`
272
+ UPDATE issues
273
+ SET status = 'open', updated_at = CURRENT_TIMESTAMP
274
+ WHERE id = ?
275
+ `);
276
+ updateStmt.run(blockedIssueId);
277
+ }
278
+ }
279
+ }
280
+ /**
281
+ * Check if an issue has any open blockers (excluding the specified blocker)
282
+ */
283
+ function hasOpenBlockers(db, issueId, excludeBlockerId) {
284
+ const stmt = db.prepare(`
285
+ SELECT COUNT(*) as count
286
+ FROM relationships r
287
+ JOIN issues blocker ON r.to_id = blocker.id AND r.to_type = 'issue'
288
+ WHERE r.from_id = ?
289
+ AND r.from_type = 'issue'
290
+ AND r.relationship_type = 'blocks'
291
+ AND blocker.status IN ('open', 'in_progress', 'blocked')
292
+ ${excludeBlockerId ? "AND blocker.id != ?" : ""}
293
+ `);
294
+ const params = excludeBlockerId ? [issueId, excludeBlockerId] : [issueId];
295
+ const result = stmt.get(...params);
296
+ return result.count > 0;
297
+ }
298
+ /**
299
+ * Delete an issue
300
+ */
301
+ export function deleteIssue(db, id) {
302
+ const stmt = db.prepare(`DELETE FROM issues WHERE id = ?`);
303
+ const result = stmt.run(id);
304
+ return result.changes > 0;
305
+ }
306
+ /**
307
+ * Close an issue (convenience method)
308
+ */
309
+ export function closeIssue(db, id) {
310
+ return updateIssue(db, id, { status: "closed" });
311
+ }
312
+ /**
313
+ * Reopen an issue (convenience method)
314
+ */
315
+ export function reopenIssue(db, id) {
316
+ return updateIssue(db, id, { status: "open" });
317
+ }
318
+ /**
319
+ * List issues with optional filters
320
+ */
321
+ export function listIssues(db, options = {}) {
322
+ const conditions = [];
323
+ const params = {};
324
+ if (options.status !== undefined) {
325
+ conditions.push("status = @status");
326
+ params.status = options.status;
327
+ }
328
+ if (options.priority !== undefined) {
329
+ conditions.push("priority = @priority");
330
+ params.priority = options.priority;
331
+ }
332
+ if (options.assignee !== undefined) {
333
+ conditions.push("assignee = @assignee");
334
+ params.assignee = options.assignee;
335
+ }
336
+ if (options.parent_id !== undefined) {
337
+ conditions.push("parent_id = @parent_id");
338
+ params.parent_id = options.parent_id;
339
+ }
340
+ if (options.archived !== undefined) {
341
+ conditions.push("archived = @archived");
342
+ params.archived = options.archived ? 1 : 0;
343
+ }
344
+ let query = "SELECT * FROM issues";
345
+ if (conditions.length > 0) {
346
+ query += " WHERE " + conditions.join(" AND ");
347
+ }
348
+ query += " ORDER BY priority DESC, created_at DESC";
349
+ if (options.limit !== undefined) {
350
+ query += " LIMIT @limit";
351
+ params.limit = options.limit;
352
+ }
353
+ if (options.offset !== undefined) {
354
+ query += " OFFSET @offset";
355
+ params.offset = options.offset;
356
+ }
357
+ const stmt = db.prepare(query);
358
+ return stmt.all(params);
359
+ }
360
+ /**
361
+ * Get ready issues (no blockers)
362
+ */
363
+ export function getReadyIssues(db) {
364
+ const stmt = db.prepare("SELECT * FROM ready_issues ORDER BY priority DESC, created_at DESC");
365
+ return stmt.all();
366
+ }
367
+ /**
368
+ * Get blocked issues
369
+ */
370
+ export function getBlockedIssues(db) {
371
+ const stmt = db.prepare("SELECT * FROM blocked_issues ORDER BY priority DESC, created_at DESC");
372
+ return stmt.all();
373
+ }
374
+ /**
375
+ * Search issues by title or content
376
+ */
377
+ export function searchIssues(db, query, options = {}) {
378
+ const conditions = ["(title LIKE @query OR content LIKE @query)"];
379
+ const params = { query: `%${query}%` };
380
+ if (options.status !== undefined) {
381
+ conditions.push("status = @status");
382
+ params.status = options.status;
383
+ }
384
+ if (options.priority !== undefined) {
385
+ conditions.push("priority = @priority");
386
+ params.priority = options.priority;
387
+ }
388
+ if (options.assignee !== undefined) {
389
+ conditions.push("assignee = @assignee");
390
+ params.assignee = options.assignee;
391
+ }
392
+ if (options.parent_id !== undefined) {
393
+ conditions.push("parent_id = @parent_id");
394
+ params.parent_id = options.parent_id;
395
+ }
396
+ if (options.archived !== undefined) {
397
+ conditions.push("archived = @archived");
398
+ params.archived = options.archived ? 1 : 0;
399
+ }
400
+ let sql = `SELECT * FROM issues WHERE ${conditions.join(" AND ")} ORDER BY priority DESC, created_at DESC`;
401
+ if (options.limit !== undefined) {
402
+ sql += " LIMIT @limit";
403
+ params.limit = options.limit;
404
+ }
405
+ else {
406
+ sql += " LIMIT 50";
407
+ }
408
+ const stmt = db.prepare(sql);
409
+ return stmt.all(params);
410
+ }
411
+ //# sourceMappingURL=issues.js.map