@compilr-dev/cli 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -0
- package/dist/agent.d.ts +62 -0
- package/dist/agent.js +317 -0
- package/dist/agents/registry.d.ts +66 -0
- package/dist/agents/registry.js +238 -0
- package/dist/agents/types.d.ts +40 -0
- package/dist/agents/types.js +94 -0
- package/dist/commands/custom-registry.d.ts +69 -0
- package/dist/commands/custom-registry.js +246 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/types.d.ts +31 -0
- package/dist/commands/types.js +26 -0
- package/dist/commands.d.ts +63 -0
- package/dist/commands.js +324 -0
- package/dist/db/index.d.ts +42 -0
- package/dist/db/index.js +146 -0
- package/dist/db/repositories/document-repository.d.ts +63 -0
- package/dist/db/repositories/document-repository.js +184 -0
- package/dist/db/repositories/index.d.ts +9 -0
- package/dist/db/repositories/index.js +6 -0
- package/dist/db/repositories/project-repository.d.ts +132 -0
- package/dist/db/repositories/project-repository.js +337 -0
- package/dist/db/repositories/work-item-repository.d.ts +115 -0
- package/dist/db/repositories/work-item-repository.js +389 -0
- package/dist/db/schema.d.ts +83 -0
- package/dist/db/schema.js +143 -0
- package/dist/debug.d.ts +8 -0
- package/dist/debug.js +48 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +348 -0
- package/dist/index.old.d.ts +7 -0
- package/dist/index.old.js +1014 -0
- package/dist/repl.d.ts +121 -0
- package/dist/repl.js +1878 -0
- package/dist/settings/index.d.ts +80 -0
- package/dist/settings/index.js +195 -0
- package/dist/shared-handlers.d.ts +63 -0
- package/dist/shared-handlers.js +57 -0
- package/dist/slash-autocomplete.d.ts +41 -0
- package/dist/slash-autocomplete.js +638 -0
- package/dist/state.d.ts +75 -0
- package/dist/state.js +130 -0
- package/dist/tabbed-menu.d.ts +11 -0
- package/dist/tabbed-menu.js +328 -0
- package/dist/templates/backlog-md.d.ts +7 -0
- package/dist/templates/backlog-md.js +94 -0
- package/dist/templates/claude-md.d.ts +7 -0
- package/dist/templates/claude-md.js +189 -0
- package/dist/templates/coding-standards.d.ts +7 -0
- package/dist/templates/coding-standards.js +299 -0
- package/dist/templates/compilr-md.d.ts +7 -0
- package/dist/templates/compilr-md.js +189 -0
- package/dist/templates/config-json.d.ts +38 -0
- package/dist/templates/config-json.js +39 -0
- package/dist/templates/gitignore.d.ts +7 -0
- package/dist/templates/gitignore.js +85 -0
- package/dist/templates/index.d.ts +19 -0
- package/dist/templates/index.js +302 -0
- package/dist/templates/package-json.d.ts +7 -0
- package/dist/templates/package-json.js +111 -0
- package/dist/templates/readme-md.d.ts +7 -0
- package/dist/templates/readme-md.js +161 -0
- package/dist/templates/tsconfig.d.ts +7 -0
- package/dist/templates/tsconfig.js +61 -0
- package/dist/templates/types.d.ts +33 -0
- package/dist/templates/types.js +24 -0
- package/dist/test-autocomplete.d.ts +7 -0
- package/dist/test-autocomplete.js +85 -0
- package/dist/test-tabbed-menu.d.ts +7 -0
- package/dist/test-tabbed-menu.js +25 -0
- package/dist/themes/colors.d.ts +49 -0
- package/dist/themes/colors.js +135 -0
- package/dist/themes/index.d.ts +23 -0
- package/dist/themes/index.js +24 -0
- package/dist/themes/registry.d.ts +60 -0
- package/dist/themes/registry.js +195 -0
- package/dist/themes/types.d.ts +82 -0
- package/dist/themes/types.js +7 -0
- package/dist/tool-selector.d.ts +71 -0
- package/dist/tool-selector.js +184 -0
- package/dist/tools/ask-user-simple.d.ts +19 -0
- package/dist/tools/ask-user-simple.js +86 -0
- package/dist/tools/ask-user.d.ts +32 -0
- package/dist/tools/ask-user.js +113 -0
- package/dist/tools/backlog.d.ts +53 -0
- package/dist/tools/backlog.js +709 -0
- package/dist/tools.d.ts +15 -0
- package/dist/tools.js +121 -0
- package/dist/ui/agents-overlay.d.ts +12 -0
- package/dist/ui/agents-overlay.js +501 -0
- package/dist/ui/arch-type-overlay.d.ts +20 -0
- package/dist/ui/arch-type-overlay.js +229 -0
- package/dist/ui/ask-user-overlay.d.ts +26 -0
- package/dist/ui/ask-user-overlay.js +647 -0
- package/dist/ui/ask-user-simple-overlay.d.ts +25 -0
- package/dist/ui/ask-user-simple-overlay.js +242 -0
- package/dist/ui/backlog-overlay.d.ts +17 -0
- package/dist/ui/backlog-overlay.js +786 -0
- package/dist/ui/commands-overlay.d.ts +11 -0
- package/dist/ui/commands-overlay.js +410 -0
- package/dist/ui/config-overlay.d.ts +34 -0
- package/dist/ui/config-overlay.js +977 -0
- package/dist/ui/conversation.d.ts +82 -0
- package/dist/ui/conversation.js +508 -0
- package/dist/ui/diff.d.ts +38 -0
- package/dist/ui/diff.js +182 -0
- package/dist/ui/ephemeral.d.ts +111 -0
- package/dist/ui/ephemeral.js +413 -0
- package/dist/ui/file-autocomplete.d.ts +45 -0
- package/dist/ui/file-autocomplete.js +237 -0
- package/dist/ui/footer.d.ts +153 -0
- package/dist/ui/footer.js +422 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/init-overlay.d.ts +24 -0
- package/dist/ui/init-overlay.js +525 -0
- package/dist/ui/input-prompt-v2.d.ts +179 -0
- package/dist/ui/input-prompt-v2.js +991 -0
- package/dist/ui/input-prompt.d.ts +97 -0
- package/dist/ui/input-prompt.js +800 -0
- package/dist/ui/iteration-limit-overlay.d.ts +21 -0
- package/dist/ui/iteration-limit-overlay.js +150 -0
- package/dist/ui/keys-overlay.d.ts +14 -0
- package/dist/ui/keys-overlay.js +181 -0
- package/dist/ui/model-warning-overlay.d.ts +30 -0
- package/dist/ui/model-warning-overlay.js +171 -0
- package/dist/ui/overlay-controller.d.ts +25 -0
- package/dist/ui/overlay-controller.js +35 -0
- package/dist/ui/overlays.d.ts +47 -0
- package/dist/ui/overlays.js +627 -0
- package/dist/ui/permission-overlay.d.ts +16 -0
- package/dist/ui/permission-overlay.js +494 -0
- package/dist/ui/terminal.d.ts +117 -0
- package/dist/ui/terminal.js +237 -0
- package/dist/ui/todo-zone.d.ts +112 -0
- package/dist/ui/todo-zone.js +353 -0
- package/dist/ui/tools-overlay.d.ts +26 -0
- package/dist/ui/tools-overlay.js +278 -0
- package/dist/ui/tutorial-overlay.d.ts +10 -0
- package/dist/ui/tutorial-overlay.js +936 -0
- package/dist/ui/types.d.ts +103 -0
- package/dist/ui/types.js +33 -0
- package/dist/utils/credentials.d.ts +55 -0
- package/dist/utils/credentials.js +268 -0
- package/dist/utils/model-tiers.d.ts +37 -0
- package/dist/utils/model-tiers.js +118 -0
- package/dist/utils/project-memory.d.ts +47 -0
- package/dist/utils/project-memory.js +117 -0
- package/dist/utils/project-status.d.ts +56 -0
- package/dist/utils/project-status.js +237 -0
- package/package.json +66 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Repository
|
|
3
|
+
*
|
|
4
|
+
* Handles all database operations for projects.
|
|
5
|
+
*/
|
|
6
|
+
import { getDb } from '../index.js';
|
|
7
|
+
/**
|
|
8
|
+
* Convert database record to Project object
|
|
9
|
+
*/
|
|
10
|
+
function recordToProject(record) {
|
|
11
|
+
return {
|
|
12
|
+
id: record.id,
|
|
13
|
+
name: record.name,
|
|
14
|
+
displayName: record.display_name,
|
|
15
|
+
description: record.description,
|
|
16
|
+
type: record.type,
|
|
17
|
+
status: record.status,
|
|
18
|
+
path: record.path,
|
|
19
|
+
docsPath: record.docs_path,
|
|
20
|
+
repoPattern: record.repo_pattern,
|
|
21
|
+
language: record.language,
|
|
22
|
+
framework: record.framework,
|
|
23
|
+
packageManager: record.package_manager,
|
|
24
|
+
runtimeVersion: record.runtime_version,
|
|
25
|
+
commands: record.commands ? JSON.parse(record.commands) : null,
|
|
26
|
+
gitRemote: record.git_remote,
|
|
27
|
+
gitBranch: record.git_branch,
|
|
28
|
+
workflowMode: record.workflow_mode,
|
|
29
|
+
lifecycleState: record.lifecycle_state,
|
|
30
|
+
currentItemId: record.current_item_id,
|
|
31
|
+
lastContext: record.last_context ? JSON.parse(record.last_context) : null,
|
|
32
|
+
metadata: record.metadata ? JSON.parse(record.metadata) : null,
|
|
33
|
+
createdAt: new Date(record.created_at),
|
|
34
|
+
updatedAt: new Date(record.updated_at),
|
|
35
|
+
lastActivityAt: record.last_activity_at
|
|
36
|
+
? new Date(record.last_activity_at)
|
|
37
|
+
: null,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export const projectRepository = {
|
|
41
|
+
/**
|
|
42
|
+
* Create a new project
|
|
43
|
+
*/
|
|
44
|
+
create(input) {
|
|
45
|
+
const db = getDb();
|
|
46
|
+
const now = new Date().toISOString();
|
|
47
|
+
const result = db
|
|
48
|
+
.prepare(`
|
|
49
|
+
INSERT INTO projects (
|
|
50
|
+
name, display_name, description, type, path, docs_path, repo_pattern,
|
|
51
|
+
language, framework, package_manager, runtime_version, commands,
|
|
52
|
+
git_remote, git_branch, workflow_mode, metadata,
|
|
53
|
+
created_at, updated_at, last_activity_at
|
|
54
|
+
) VALUES (
|
|
55
|
+
@name, @display_name, @description, @type, @path, @docs_path, @repo_pattern,
|
|
56
|
+
@language, @framework, @package_manager, @runtime_version, @commands,
|
|
57
|
+
@git_remote, @git_branch, @workflow_mode, @metadata,
|
|
58
|
+
@created_at, @updated_at, @last_activity_at
|
|
59
|
+
)
|
|
60
|
+
`)
|
|
61
|
+
.run({
|
|
62
|
+
name: input.name,
|
|
63
|
+
display_name: input.display_name,
|
|
64
|
+
description: input.description ?? null,
|
|
65
|
+
type: input.type ?? 'general',
|
|
66
|
+
path: input.path,
|
|
67
|
+
docs_path: input.docs_path ?? null,
|
|
68
|
+
repo_pattern: input.repo_pattern ?? 'single',
|
|
69
|
+
language: input.language ?? null,
|
|
70
|
+
framework: input.framework ?? null,
|
|
71
|
+
package_manager: input.package_manager ?? null,
|
|
72
|
+
runtime_version: input.runtime_version ?? null,
|
|
73
|
+
commands: input.commands ? JSON.stringify(input.commands) : null,
|
|
74
|
+
git_remote: input.git_remote ?? null,
|
|
75
|
+
git_branch: input.git_branch ?? 'main',
|
|
76
|
+
workflow_mode: input.workflow_mode ?? 'flexible',
|
|
77
|
+
metadata: input.metadata ? JSON.stringify(input.metadata) : null,
|
|
78
|
+
created_at: now,
|
|
79
|
+
updated_at: now,
|
|
80
|
+
last_activity_at: now,
|
|
81
|
+
});
|
|
82
|
+
const project = this.getById(Number(result.lastInsertRowid));
|
|
83
|
+
if (!project)
|
|
84
|
+
throw new Error('Failed to create project');
|
|
85
|
+
return project;
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Get project by ID
|
|
89
|
+
*/
|
|
90
|
+
getById(id) {
|
|
91
|
+
const db = getDb();
|
|
92
|
+
const record = db
|
|
93
|
+
.prepare('SELECT * FROM projects WHERE id = ?')
|
|
94
|
+
.get(id);
|
|
95
|
+
return record ? recordToProject(record) : null;
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* Get project by name
|
|
99
|
+
*/
|
|
100
|
+
getByName(name) {
|
|
101
|
+
const db = getDb();
|
|
102
|
+
const record = db
|
|
103
|
+
.prepare('SELECT * FROM projects WHERE name = ?')
|
|
104
|
+
.get(name);
|
|
105
|
+
return record ? recordToProject(record) : null;
|
|
106
|
+
},
|
|
107
|
+
/**
|
|
108
|
+
* Get project by path (code repo)
|
|
109
|
+
*/
|
|
110
|
+
getByPath(projectPath) {
|
|
111
|
+
const db = getDb();
|
|
112
|
+
const record = db
|
|
113
|
+
.prepare('SELECT * FROM projects WHERE path = ?')
|
|
114
|
+
.get(projectPath);
|
|
115
|
+
return record ? recordToProject(record) : null;
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Get project by docs path (for two-repo pattern)
|
|
119
|
+
*/
|
|
120
|
+
getByDocsPath(docsPath) {
|
|
121
|
+
const db = getDb();
|
|
122
|
+
const record = db
|
|
123
|
+
.prepare('SELECT * FROM projects WHERE docs_path = ?')
|
|
124
|
+
.get(docsPath);
|
|
125
|
+
return record ? recordToProject(record) : null;
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Find project by path (checks both path and docs_path, including parent directories)
|
|
129
|
+
*/
|
|
130
|
+
findByPath(searchPath) {
|
|
131
|
+
// First try exact match on path
|
|
132
|
+
let project = this.getByPath(searchPath);
|
|
133
|
+
if (project)
|
|
134
|
+
return project;
|
|
135
|
+
// Try exact match on docs_path
|
|
136
|
+
project = this.getByDocsPath(searchPath);
|
|
137
|
+
if (project)
|
|
138
|
+
return project;
|
|
139
|
+
// Try parent directories
|
|
140
|
+
const parts = searchPath.split('/').filter(Boolean);
|
|
141
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
142
|
+
const parentPath = '/' + parts.slice(0, i).join('/');
|
|
143
|
+
if (!parentPath || parentPath === '/')
|
|
144
|
+
break;
|
|
145
|
+
project = this.getByPath(parentPath);
|
|
146
|
+
if (project)
|
|
147
|
+
return project;
|
|
148
|
+
project = this.getByDocsPath(parentPath);
|
|
149
|
+
if (project)
|
|
150
|
+
return project;
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
},
|
|
154
|
+
/**
|
|
155
|
+
* List projects with optional filters
|
|
156
|
+
*/
|
|
157
|
+
list(options) {
|
|
158
|
+
const db = getDb();
|
|
159
|
+
const conditions = [];
|
|
160
|
+
const params = {};
|
|
161
|
+
if (options?.status && options.status !== 'all') {
|
|
162
|
+
conditions.push('status = @status');
|
|
163
|
+
params.status = options.status;
|
|
164
|
+
}
|
|
165
|
+
if (options?.type && options.type !== 'all') {
|
|
166
|
+
conditions.push('type = @type');
|
|
167
|
+
params.type = options.type;
|
|
168
|
+
}
|
|
169
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
170
|
+
// Get total count
|
|
171
|
+
const countResult = db
|
|
172
|
+
.prepare(`SELECT COUNT(*) as count FROM projects ${whereClause}`)
|
|
173
|
+
.get(params);
|
|
174
|
+
// Get projects with pagination
|
|
175
|
+
let query = `SELECT * FROM projects ${whereClause} ORDER BY last_activity_at DESC NULLS LAST, updated_at DESC`;
|
|
176
|
+
if (options?.limit) {
|
|
177
|
+
query += ` LIMIT @limit`;
|
|
178
|
+
params.limit = options.limit;
|
|
179
|
+
}
|
|
180
|
+
if (options?.offset) {
|
|
181
|
+
query += ` OFFSET @offset`;
|
|
182
|
+
params.offset = options.offset;
|
|
183
|
+
}
|
|
184
|
+
const records = db.prepare(query).all(params);
|
|
185
|
+
return {
|
|
186
|
+
projects: records.map(recordToProject),
|
|
187
|
+
total: countResult.count,
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
/**
|
|
191
|
+
* Update a project
|
|
192
|
+
*/
|
|
193
|
+
update(id, input) {
|
|
194
|
+
const db = getDb();
|
|
195
|
+
const updates = [];
|
|
196
|
+
const params = { id };
|
|
197
|
+
// Build dynamic update query
|
|
198
|
+
if (input.display_name !== undefined) {
|
|
199
|
+
updates.push('display_name = @display_name');
|
|
200
|
+
params.display_name = input.display_name;
|
|
201
|
+
}
|
|
202
|
+
if (input.description !== undefined) {
|
|
203
|
+
updates.push('description = @description');
|
|
204
|
+
params.description = input.description;
|
|
205
|
+
}
|
|
206
|
+
if (input.type !== undefined) {
|
|
207
|
+
updates.push('type = @type');
|
|
208
|
+
params.type = input.type;
|
|
209
|
+
}
|
|
210
|
+
if (input.status !== undefined) {
|
|
211
|
+
updates.push('status = @status');
|
|
212
|
+
params.status = input.status;
|
|
213
|
+
}
|
|
214
|
+
if (input.docs_path !== undefined) {
|
|
215
|
+
updates.push('docs_path = @docs_path');
|
|
216
|
+
params.docs_path = input.docs_path;
|
|
217
|
+
}
|
|
218
|
+
if (input.repo_pattern !== undefined) {
|
|
219
|
+
updates.push('repo_pattern = @repo_pattern');
|
|
220
|
+
params.repo_pattern = input.repo_pattern;
|
|
221
|
+
}
|
|
222
|
+
if (input.language !== undefined) {
|
|
223
|
+
updates.push('language = @language');
|
|
224
|
+
params.language = input.language;
|
|
225
|
+
}
|
|
226
|
+
if (input.framework !== undefined) {
|
|
227
|
+
updates.push('framework = @framework');
|
|
228
|
+
params.framework = input.framework;
|
|
229
|
+
}
|
|
230
|
+
if (input.package_manager !== undefined) {
|
|
231
|
+
updates.push('package_manager = @package_manager');
|
|
232
|
+
params.package_manager = input.package_manager;
|
|
233
|
+
}
|
|
234
|
+
if (input.runtime_version !== undefined) {
|
|
235
|
+
updates.push('runtime_version = @runtime_version');
|
|
236
|
+
params.runtime_version = input.runtime_version;
|
|
237
|
+
}
|
|
238
|
+
if (input.commands !== undefined) {
|
|
239
|
+
updates.push('commands = @commands');
|
|
240
|
+
params.commands = JSON.stringify(input.commands);
|
|
241
|
+
}
|
|
242
|
+
if (input.git_remote !== undefined) {
|
|
243
|
+
updates.push('git_remote = @git_remote');
|
|
244
|
+
params.git_remote = input.git_remote;
|
|
245
|
+
}
|
|
246
|
+
if (input.git_branch !== undefined) {
|
|
247
|
+
updates.push('git_branch = @git_branch');
|
|
248
|
+
params.git_branch = input.git_branch;
|
|
249
|
+
}
|
|
250
|
+
if (input.workflow_mode !== undefined) {
|
|
251
|
+
updates.push('workflow_mode = @workflow_mode');
|
|
252
|
+
params.workflow_mode = input.workflow_mode;
|
|
253
|
+
}
|
|
254
|
+
if (input.lifecycle_state !== undefined) {
|
|
255
|
+
updates.push('lifecycle_state = @lifecycle_state');
|
|
256
|
+
params.lifecycle_state = input.lifecycle_state;
|
|
257
|
+
}
|
|
258
|
+
if (input.current_item_id !== undefined) {
|
|
259
|
+
updates.push('current_item_id = @current_item_id');
|
|
260
|
+
params.current_item_id = input.current_item_id;
|
|
261
|
+
}
|
|
262
|
+
if (input.last_context !== undefined) {
|
|
263
|
+
updates.push('last_context = @last_context');
|
|
264
|
+
params.last_context = JSON.stringify(input.last_context);
|
|
265
|
+
}
|
|
266
|
+
if (input.metadata !== undefined) {
|
|
267
|
+
updates.push('metadata = @metadata');
|
|
268
|
+
params.metadata = JSON.stringify(input.metadata);
|
|
269
|
+
}
|
|
270
|
+
if (updates.length === 0) {
|
|
271
|
+
return this.getById(id);
|
|
272
|
+
}
|
|
273
|
+
// Always update updated_at
|
|
274
|
+
updates.push('updated_at = @updated_at');
|
|
275
|
+
params.updated_at = new Date().toISOString();
|
|
276
|
+
const query = `UPDATE projects SET ${updates.join(', ')} WHERE id = @id`;
|
|
277
|
+
db.prepare(query).run(params);
|
|
278
|
+
return this.getById(id);
|
|
279
|
+
},
|
|
280
|
+
/**
|
|
281
|
+
* Update last activity timestamp
|
|
282
|
+
*/
|
|
283
|
+
touch(id) {
|
|
284
|
+
const db = getDb();
|
|
285
|
+
const now = new Date().toISOString();
|
|
286
|
+
db.prepare('UPDATE projects SET last_activity_at = ?, updated_at = ? WHERE id = ?').run(now, now, id);
|
|
287
|
+
},
|
|
288
|
+
/**
|
|
289
|
+
* Delete a project (cascades to work_items, documents, history)
|
|
290
|
+
*/
|
|
291
|
+
delete(id) {
|
|
292
|
+
const db = getDb();
|
|
293
|
+
const result = db.prepare('DELETE FROM projects WHERE id = ?').run(id);
|
|
294
|
+
return result.changes > 0;
|
|
295
|
+
},
|
|
296
|
+
/**
|
|
297
|
+
* Archive a project (set status to 'archived')
|
|
298
|
+
*/
|
|
299
|
+
archive(id) {
|
|
300
|
+
return this.update(id, { status: 'archived' });
|
|
301
|
+
},
|
|
302
|
+
/**
|
|
303
|
+
* Check if a project name is available
|
|
304
|
+
*/
|
|
305
|
+
isNameAvailable(name, excludeId) {
|
|
306
|
+
const db = getDb();
|
|
307
|
+
const query = excludeId
|
|
308
|
+
? 'SELECT id FROM projects WHERE name = ? AND id != ?'
|
|
309
|
+
: 'SELECT id FROM projects WHERE name = ?';
|
|
310
|
+
const params = excludeId ? [name, excludeId] : [name];
|
|
311
|
+
const result = db.prepare(query).get(...params);
|
|
312
|
+
return !result;
|
|
313
|
+
},
|
|
314
|
+
/**
|
|
315
|
+
* Get project counts by status
|
|
316
|
+
*/
|
|
317
|
+
getStatusCounts() {
|
|
318
|
+
const db = getDb();
|
|
319
|
+
const results = db
|
|
320
|
+
.prepare(`
|
|
321
|
+
SELECT status, COUNT(*) as count
|
|
322
|
+
FROM projects
|
|
323
|
+
GROUP BY status
|
|
324
|
+
`)
|
|
325
|
+
.all();
|
|
326
|
+
const counts = {
|
|
327
|
+
active: 0,
|
|
328
|
+
paused: 0,
|
|
329
|
+
completed: 0,
|
|
330
|
+
archived: 0,
|
|
331
|
+
};
|
|
332
|
+
for (const row of results) {
|
|
333
|
+
counts[row.status] = row.count;
|
|
334
|
+
}
|
|
335
|
+
return counts;
|
|
336
|
+
},
|
|
337
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Work Item Repository
|
|
3
|
+
*
|
|
4
|
+
* Handles all database operations for work items (backlog items, tasks, bugs).
|
|
5
|
+
*/
|
|
6
|
+
import type { WorkItemType, WorkItemStatus, WorkItemPriority, GuidedStep } from '../schema.js';
|
|
7
|
+
export interface CreateWorkItemInput {
|
|
8
|
+
project_id: number;
|
|
9
|
+
type: WorkItemType;
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
priority?: WorkItemPriority;
|
|
13
|
+
estimated_effort?: 'low' | 'medium' | 'high';
|
|
14
|
+
}
|
|
15
|
+
export interface UpdateWorkItemInput {
|
|
16
|
+
type?: WorkItemType;
|
|
17
|
+
status?: WorkItemStatus;
|
|
18
|
+
priority?: WorkItemPriority;
|
|
19
|
+
guided_step?: GuidedStep | null;
|
|
20
|
+
title?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
estimated_effort?: 'low' | 'medium' | 'high';
|
|
23
|
+
actual_minutes?: number;
|
|
24
|
+
commit_hash?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface QueryWorkItemsInput {
|
|
27
|
+
project_id?: number;
|
|
28
|
+
status?: WorkItemStatus | 'all';
|
|
29
|
+
type?: WorkItemType | 'all';
|
|
30
|
+
priority?: WorkItemPriority | 'all';
|
|
31
|
+
search?: string;
|
|
32
|
+
limit?: number;
|
|
33
|
+
offset?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface WorkItem {
|
|
36
|
+
id: number;
|
|
37
|
+
projectId: number;
|
|
38
|
+
itemNumber: number;
|
|
39
|
+
itemId: string;
|
|
40
|
+
type: WorkItemType;
|
|
41
|
+
status: WorkItemStatus;
|
|
42
|
+
priority: WorkItemPriority;
|
|
43
|
+
guidedStep: GuidedStep | null;
|
|
44
|
+
title: string;
|
|
45
|
+
description: string | null;
|
|
46
|
+
estimatedEffort: string | null;
|
|
47
|
+
actualMinutes: number | null;
|
|
48
|
+
completedAt: Date | null;
|
|
49
|
+
completedBy: string | null;
|
|
50
|
+
commitHash: string | null;
|
|
51
|
+
createdAt: Date;
|
|
52
|
+
updatedAt: Date;
|
|
53
|
+
}
|
|
54
|
+
export declare const workItemRepository: {
|
|
55
|
+
/**
|
|
56
|
+
* Create a new work item
|
|
57
|
+
*/
|
|
58
|
+
create(input: CreateWorkItemInput): WorkItem;
|
|
59
|
+
/**
|
|
60
|
+
* Get work item by database ID
|
|
61
|
+
*/
|
|
62
|
+
getById(id: number): WorkItem | null;
|
|
63
|
+
/**
|
|
64
|
+
* Get work item by item_id (e.g., "REQ-001")
|
|
65
|
+
*/
|
|
66
|
+
getByItemId(projectId: number, itemId: string): WorkItem | null;
|
|
67
|
+
/**
|
|
68
|
+
* Query work items with filters
|
|
69
|
+
*/
|
|
70
|
+
query(input: QueryWorkItemsInput): {
|
|
71
|
+
items: WorkItem[];
|
|
72
|
+
total: number;
|
|
73
|
+
hasMore: boolean;
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Get next work item (highest priority backlog item)
|
|
77
|
+
*/
|
|
78
|
+
getNext(projectId: number, type?: WorkItemType): WorkItem | null;
|
|
79
|
+
/**
|
|
80
|
+
* Update a work item
|
|
81
|
+
*/
|
|
82
|
+
update(id: number, input: UpdateWorkItemInput): WorkItem | null;
|
|
83
|
+
/**
|
|
84
|
+
* Record change in history
|
|
85
|
+
*/
|
|
86
|
+
recordHistory(workItemId: number, projectId: number, changes: UpdateWorkItemInput, oldItem: WorkItem): void;
|
|
87
|
+
/**
|
|
88
|
+
* Delete a work item
|
|
89
|
+
*/
|
|
90
|
+
delete(id: number): boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Get work item counts by status for a project
|
|
93
|
+
*/
|
|
94
|
+
getStatusCounts(projectId: number): Record<WorkItemStatus, number>;
|
|
95
|
+
/**
|
|
96
|
+
* Get history for a work item
|
|
97
|
+
*/
|
|
98
|
+
getHistory(workItemId: number): Array<{
|
|
99
|
+
action: string;
|
|
100
|
+
oldValue: string | null;
|
|
101
|
+
newValue: string | null;
|
|
102
|
+
notes: string | null;
|
|
103
|
+
changedBy: string | null;
|
|
104
|
+
changedAt: Date;
|
|
105
|
+
}>;
|
|
106
|
+
/**
|
|
107
|
+
* Bulk import work items (for /promote command)
|
|
108
|
+
*/
|
|
109
|
+
bulkCreate(projectId: number, items: Array<{
|
|
110
|
+
type: WorkItemType;
|
|
111
|
+
title: string;
|
|
112
|
+
description?: string;
|
|
113
|
+
priority?: WorkItemPriority;
|
|
114
|
+
}>): WorkItem[];
|
|
115
|
+
};
|