clitrigger 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.
- package/.env.example +9 -0
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/bin/clitrigger.js +106 -0
- package/dist/client/assets/index-BkOCv65b.css +1 -0
- package/dist/client/assets/index-Fbf16Lh1.js +129 -0
- package/dist/client/index.html +24 -0
- package/dist/server/db/connection.d.ts +4 -0
- package/dist/server/db/connection.d.ts.map +1 -0
- package/dist/server/db/connection.js +24 -0
- package/dist/server/db/connection.js.map +1 -0
- package/dist/server/db/queries.d.ts +265 -0
- package/dist/server/db/queries.d.ts.map +1 -0
- package/dist/server/db/queries.js +836 -0
- package/dist/server/db/queries.js.map +1 -0
- package/dist/server/db/schema.d.ts +3 -0
- package/dist/server/db/schema.d.ts.map +1 -0
- package/dist/server/db/schema.js +325 -0
- package/dist/server/db/schema.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +207 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware/auth.d.ts +5 -0
- package/dist/server/middleware/auth.d.ts.map +1 -0
- package/dist/server/middleware/auth.js +45 -0
- package/dist/server/middleware/auth.js.map +1 -0
- package/dist/server/plugins/github/index.d.ts +3 -0
- package/dist/server/plugins/github/index.d.ts.map +1 -0
- package/dist/server/plugins/github/index.js +18 -0
- package/dist/server/plugins/github/index.js.map +1 -0
- package/dist/server/plugins/github/router.d.ts +4 -0
- package/dist/server/plugins/github/router.d.ts.map +1 -0
- package/dist/server/plugins/github/router.js +250 -0
- package/dist/server/plugins/github/router.js.map +1 -0
- package/dist/server/plugins/gstack/index.d.ts +3 -0
- package/dist/server/plugins/gstack/index.d.ts.map +1 -0
- package/dist/server/plugins/gstack/index.js +36 -0
- package/dist/server/plugins/gstack/index.js.map +1 -0
- package/dist/server/plugins/jira/index.d.ts +3 -0
- package/dist/server/plugins/jira/index.d.ts.map +1 -0
- package/dist/server/plugins/jira/index.js +19 -0
- package/dist/server/plugins/jira/index.js.map +1 -0
- package/dist/server/plugins/jira/router.d.ts +4 -0
- package/dist/server/plugins/jira/router.d.ts.map +1 -0
- package/dist/server/plugins/jira/router.js +332 -0
- package/dist/server/plugins/jira/router.js.map +1 -0
- package/dist/server/plugins/notion/index.d.ts +3 -0
- package/dist/server/plugins/notion/index.d.ts.map +1 -0
- package/dist/server/plugins/notion/index.js +17 -0
- package/dist/server/plugins/notion/index.js.map +1 -0
- package/dist/server/plugins/notion/router.d.ts +4 -0
- package/dist/server/plugins/notion/router.d.ts.map +1 -0
- package/dist/server/plugins/notion/router.js +313 -0
- package/dist/server/plugins/notion/router.js.map +1 -0
- package/dist/server/plugins/registry.d.ts +8 -0
- package/dist/server/plugins/registry.d.ts.map +1 -0
- package/dist/server/plugins/registry.js +31 -0
- package/dist/server/plugins/registry.js.map +1 -0
- package/dist/server/plugins/types.d.ts +32 -0
- package/dist/server/plugins/types.d.ts.map +1 -0
- package/dist/server/plugins/types.js +2 -0
- package/dist/server/plugins/types.js.map +1 -0
- package/dist/server/resources/gstack-skills/LICENSE +21 -0
- package/dist/server/resources/gstack-skills/benchmark/SKILL.md +528 -0
- package/dist/server/resources/gstack-skills/careful/SKILL.md +59 -0
- package/dist/server/resources/gstack-skills/cso/SKILL.md +898 -0
- package/dist/server/resources/gstack-skills/investigate/SKILL.md +474 -0
- package/dist/server/resources/gstack-skills/qa/SKILL.md +1055 -0
- package/dist/server/resources/gstack-skills/qa-only/SKILL.md +672 -0
- package/dist/server/resources/gstack-skills/review/SKILL.md +1044 -0
- package/dist/server/resources/gstack-skills/skills-manifest.d.ts +9 -0
- package/dist/server/resources/gstack-skills/skills-manifest.d.ts.map +1 -0
- package/dist/server/resources/gstack-skills/skills-manifest.js +52 -0
- package/dist/server/resources/gstack-skills/skills-manifest.js.map +1 -0
- package/dist/server/resources/gstack-skills/skills-manifest.ts +59 -0
- package/dist/server/routes/auth.d.ts +3 -0
- package/dist/server/routes/auth.d.ts.map +1 -0
- package/dist/server/routes/auth.js +70 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/debug-logs.d.ts +3 -0
- package/dist/server/routes/debug-logs.d.ts.map +1 -0
- package/dist/server/routes/debug-logs.js +43 -0
- package/dist/server/routes/debug-logs.js.map +1 -0
- package/dist/server/routes/discussions.d.ts +3 -0
- package/dist/server/routes/discussions.d.ts.map +1 -0
- package/dist/server/routes/discussions.js +544 -0
- package/dist/server/routes/discussions.js.map +1 -0
- package/dist/server/routes/execution.d.ts +3 -0
- package/dist/server/routes/execution.d.ts.map +1 -0
- package/dist/server/routes/execution.js +339 -0
- package/dist/server/routes/execution.js.map +1 -0
- package/dist/server/routes/github.d.ts +3 -0
- package/dist/server/routes/github.d.ts.map +1 -0
- package/dist/server/routes/github.js +251 -0
- package/dist/server/routes/github.js.map +1 -0
- package/dist/server/routes/images.d.ts +17 -0
- package/dist/server/routes/images.d.ts.map +1 -0
- package/dist/server/routes/images.js +152 -0
- package/dist/server/routes/images.js.map +1 -0
- package/dist/server/routes/jira.d.ts +3 -0
- package/dist/server/routes/jira.d.ts.map +1 -0
- package/dist/server/routes/jira.js +333 -0
- package/dist/server/routes/jira.js.map +1 -0
- package/dist/server/routes/logs.d.ts +3 -0
- package/dist/server/routes/logs.d.ts.map +1 -0
- package/dist/server/routes/logs.js +156 -0
- package/dist/server/routes/logs.js.map +1 -0
- package/dist/server/routes/models.d.ts +3 -0
- package/dist/server/routes/models.d.ts.map +1 -0
- package/dist/server/routes/models.js +65 -0
- package/dist/server/routes/models.js.map +1 -0
- package/dist/server/routes/notion.d.ts +3 -0
- package/dist/server/routes/notion.d.ts.map +1 -0
- package/dist/server/routes/notion.js +312 -0
- package/dist/server/routes/notion.js.map +1 -0
- package/dist/server/routes/pipelines.d.ts +3 -0
- package/dist/server/routes/pipelines.d.ts.map +1 -0
- package/dist/server/routes/pipelines.js +315 -0
- package/dist/server/routes/pipelines.js.map +1 -0
- package/dist/server/routes/plugins.d.ts +3 -0
- package/dist/server/routes/plugins.d.ts.map +1 -0
- package/dist/server/routes/plugins.js +71 -0
- package/dist/server/routes/plugins.js.map +1 -0
- package/dist/server/routes/projects.d.ts +3 -0
- package/dist/server/routes/projects.d.ts.map +1 -0
- package/dist/server/routes/projects.js +557 -0
- package/dist/server/routes/projects.js.map +1 -0
- package/dist/server/routes/schedules.d.ts +3 -0
- package/dist/server/routes/schedules.d.ts.map +1 -0
- package/dist/server/routes/schedules.js +247 -0
- package/dist/server/routes/schedules.js.map +1 -0
- package/dist/server/routes/todos.d.ts +3 -0
- package/dist/server/routes/todos.d.ts.map +1 -0
- package/dist/server/routes/todos.js +103 -0
- package/dist/server/routes/todos.js.map +1 -0
- package/dist/server/routes/tunnel.d.ts +3 -0
- package/dist/server/routes/tunnel.d.ts.map +1 -0
- package/dist/server/routes/tunnel.js +44 -0
- package/dist/server/routes/tunnel.js.map +1 -0
- package/dist/server/services/claude-manager.d.ts +42 -0
- package/dist/server/services/claude-manager.d.ts.map +1 -0
- package/dist/server/services/claude-manager.js +275 -0
- package/dist/server/services/claude-manager.js.map +1 -0
- package/dist/server/services/cli-adapters.d.ts +35 -0
- package/dist/server/services/cli-adapters.d.ts.map +1 -0
- package/dist/server/services/cli-adapters.js +139 -0
- package/dist/server/services/cli-adapters.js.map +1 -0
- package/dist/server/services/debug-logger.d.ts +35 -0
- package/dist/server/services/debug-logger.d.ts.map +1 -0
- package/dist/server/services/debug-logger.js +168 -0
- package/dist/server/services/debug-logger.js.map +1 -0
- package/dist/server/services/discussion-orchestrator.d.ts +47 -0
- package/dist/server/services/discussion-orchestrator.d.ts.map +1 -0
- package/dist/server/services/discussion-orchestrator.js +599 -0
- package/dist/server/services/discussion-orchestrator.js.map +1 -0
- package/dist/server/services/log-streamer.d.ts +45 -0
- package/dist/server/services/log-streamer.d.ts.map +1 -0
- package/dist/server/services/log-streamer.js +348 -0
- package/dist/server/services/log-streamer.js.map +1 -0
- package/dist/server/services/orchestrator.d.ts +69 -0
- package/dist/server/services/orchestrator.d.ts.map +1 -0
- package/dist/server/services/orchestrator.js +642 -0
- package/dist/server/services/orchestrator.js.map +1 -0
- package/dist/server/services/pipeline-orchestrator.d.ts +43 -0
- package/dist/server/services/pipeline-orchestrator.d.ts.map +1 -0
- package/dist/server/services/pipeline-orchestrator.js +503 -0
- package/dist/server/services/pipeline-orchestrator.js.map +1 -0
- package/dist/server/services/prompt-guard.d.ts +19 -0
- package/dist/server/services/prompt-guard.d.ts.map +1 -0
- package/dist/server/services/prompt-guard.js +43 -0
- package/dist/server/services/prompt-guard.js.map +1 -0
- package/dist/server/services/scheduler.d.ts +43 -0
- package/dist/server/services/scheduler.d.ts.map +1 -0
- package/dist/server/services/scheduler.js +199 -0
- package/dist/server/services/scheduler.js.map +1 -0
- package/dist/server/services/skill-injector.d.ts +17 -0
- package/dist/server/services/skill-injector.d.ts.map +1 -0
- package/dist/server/services/skill-injector.js +60 -0
- package/dist/server/services/skill-injector.js.map +1 -0
- package/dist/server/services/tunnel-manager.d.ts +42 -0
- package/dist/server/services/tunnel-manager.d.ts.map +1 -0
- package/dist/server/services/tunnel-manager.js +265 -0
- package/dist/server/services/tunnel-manager.js.map +1 -0
- package/dist/server/services/worktree-manager.d.ts +117 -0
- package/dist/server/services/worktree-manager.d.ts.map +1 -0
- package/dist/server/services/worktree-manager.js +400 -0
- package/dist/server/services/worktree-manager.js.map +1 -0
- package/dist/server/websocket/broadcaster.d.ts +12 -0
- package/dist/server/websocket/broadcaster.d.ts.map +1 -0
- package/dist/server/websocket/broadcaster.js +23 -0
- package/dist/server/websocket/broadcaster.js.map +1 -0
- package/dist/server/websocket/events.d.ts +94 -0
- package/dist/server/websocket/events.d.ts.map +1 -0
- package/dist/server/websocket/events.js +2 -0
- package/dist/server/websocket/events.js.map +1 -0
- package/dist/server/websocket/index.d.ts +3 -0
- package/dist/server/websocket/index.d.ts.map +1 -0
- package/dist/server/websocket/index.js +82 -0
- package/dist/server/websocket/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,836 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
+
import { getDatabase } from './connection.js';
|
|
3
|
+
export function createProject(name, projectPath, defaultBranch = 'main', isGitRepo = 1) {
|
|
4
|
+
const db = getDatabase();
|
|
5
|
+
const id = uuidv4();
|
|
6
|
+
const now = new Date().toISOString();
|
|
7
|
+
db.prepare(`INSERT INTO projects (id, name, path, default_branch, is_git_repo, created_at, updated_at)
|
|
8
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(id, name, projectPath, defaultBranch, isGitRepo, now, now);
|
|
9
|
+
return getProjectById(id);
|
|
10
|
+
}
|
|
11
|
+
export function getAllProjects() {
|
|
12
|
+
const db = getDatabase();
|
|
13
|
+
return db.prepare('SELECT * FROM projects ORDER BY created_at DESC').all();
|
|
14
|
+
}
|
|
15
|
+
export function getProjectById(id) {
|
|
16
|
+
const db = getDatabase();
|
|
17
|
+
return db.prepare('SELECT * FROM projects WHERE id = ?').get(id);
|
|
18
|
+
}
|
|
19
|
+
export function updateProject(id, updates) {
|
|
20
|
+
const db = getDatabase();
|
|
21
|
+
const fields = [];
|
|
22
|
+
const values = [];
|
|
23
|
+
if (updates.name !== undefined) {
|
|
24
|
+
fields.push('name = ?');
|
|
25
|
+
values.push(updates.name);
|
|
26
|
+
}
|
|
27
|
+
if (updates.path !== undefined) {
|
|
28
|
+
fields.push('path = ?');
|
|
29
|
+
values.push(updates.path);
|
|
30
|
+
}
|
|
31
|
+
if (updates.default_branch !== undefined) {
|
|
32
|
+
fields.push('default_branch = ?');
|
|
33
|
+
values.push(updates.default_branch);
|
|
34
|
+
}
|
|
35
|
+
if (updates.is_git_repo !== undefined) {
|
|
36
|
+
fields.push('is_git_repo = ?');
|
|
37
|
+
values.push(updates.is_git_repo);
|
|
38
|
+
}
|
|
39
|
+
if (updates.max_concurrent !== undefined) {
|
|
40
|
+
fields.push('max_concurrent = ?');
|
|
41
|
+
values.push(updates.max_concurrent);
|
|
42
|
+
}
|
|
43
|
+
if (updates.claude_model !== undefined) {
|
|
44
|
+
fields.push('claude_model = ?');
|
|
45
|
+
values.push(updates.claude_model);
|
|
46
|
+
}
|
|
47
|
+
if (updates.claude_options !== undefined) {
|
|
48
|
+
fields.push('claude_options = ?');
|
|
49
|
+
values.push(updates.claude_options);
|
|
50
|
+
}
|
|
51
|
+
if (updates.cli_tool !== undefined) {
|
|
52
|
+
fields.push('cli_tool = ?');
|
|
53
|
+
values.push(updates.cli_tool);
|
|
54
|
+
}
|
|
55
|
+
if (updates.gstack_enabled !== undefined) {
|
|
56
|
+
fields.push('gstack_enabled = ?');
|
|
57
|
+
values.push(updates.gstack_enabled);
|
|
58
|
+
}
|
|
59
|
+
if (updates.gstack_skills !== undefined) {
|
|
60
|
+
fields.push('gstack_skills = ?');
|
|
61
|
+
values.push(updates.gstack_skills);
|
|
62
|
+
}
|
|
63
|
+
if (updates.jira_enabled !== undefined) {
|
|
64
|
+
fields.push('jira_enabled = ?');
|
|
65
|
+
values.push(updates.jira_enabled);
|
|
66
|
+
}
|
|
67
|
+
if (updates.jira_base_url !== undefined) {
|
|
68
|
+
fields.push('jira_base_url = ?');
|
|
69
|
+
values.push(updates.jira_base_url);
|
|
70
|
+
}
|
|
71
|
+
if (updates.jira_email !== undefined) {
|
|
72
|
+
fields.push('jira_email = ?');
|
|
73
|
+
values.push(updates.jira_email);
|
|
74
|
+
}
|
|
75
|
+
if (updates.jira_api_token !== undefined) {
|
|
76
|
+
fields.push('jira_api_token = ?');
|
|
77
|
+
values.push(updates.jira_api_token);
|
|
78
|
+
}
|
|
79
|
+
if (updates.jira_project_key !== undefined) {
|
|
80
|
+
fields.push('jira_project_key = ?');
|
|
81
|
+
values.push(updates.jira_project_key);
|
|
82
|
+
}
|
|
83
|
+
if (updates.notion_enabled !== undefined) {
|
|
84
|
+
fields.push('notion_enabled = ?');
|
|
85
|
+
values.push(updates.notion_enabled);
|
|
86
|
+
}
|
|
87
|
+
if (updates.notion_api_key !== undefined) {
|
|
88
|
+
fields.push('notion_api_key = ?');
|
|
89
|
+
values.push(updates.notion_api_key);
|
|
90
|
+
}
|
|
91
|
+
if (updates.notion_database_id !== undefined) {
|
|
92
|
+
fields.push('notion_database_id = ?');
|
|
93
|
+
values.push(updates.notion_database_id);
|
|
94
|
+
}
|
|
95
|
+
if (updates.github_enabled !== undefined) {
|
|
96
|
+
fields.push('github_enabled = ?');
|
|
97
|
+
values.push(updates.github_enabled);
|
|
98
|
+
}
|
|
99
|
+
if (updates.github_token !== undefined) {
|
|
100
|
+
fields.push('github_token = ?');
|
|
101
|
+
values.push(updates.github_token);
|
|
102
|
+
}
|
|
103
|
+
if (updates.github_owner !== undefined) {
|
|
104
|
+
fields.push('github_owner = ?');
|
|
105
|
+
values.push(updates.github_owner);
|
|
106
|
+
}
|
|
107
|
+
if (updates.github_repo !== undefined) {
|
|
108
|
+
fields.push('github_repo = ?');
|
|
109
|
+
values.push(updates.github_repo);
|
|
110
|
+
}
|
|
111
|
+
if (updates.cli_fallback_chain !== undefined) {
|
|
112
|
+
fields.push('cli_fallback_chain = ?');
|
|
113
|
+
values.push(updates.cli_fallback_chain);
|
|
114
|
+
}
|
|
115
|
+
if (updates.default_max_turns !== undefined) {
|
|
116
|
+
fields.push('default_max_turns = ?');
|
|
117
|
+
values.push(updates.default_max_turns);
|
|
118
|
+
}
|
|
119
|
+
if (updates.sandbox_mode !== undefined) {
|
|
120
|
+
fields.push('sandbox_mode = ?');
|
|
121
|
+
values.push(updates.sandbox_mode);
|
|
122
|
+
}
|
|
123
|
+
if (updates.debug_logging !== undefined) {
|
|
124
|
+
fields.push('debug_logging = ?');
|
|
125
|
+
values.push(updates.debug_logging);
|
|
126
|
+
}
|
|
127
|
+
if (updates.use_worktree !== undefined) {
|
|
128
|
+
fields.push('use_worktree = ?');
|
|
129
|
+
values.push(updates.use_worktree);
|
|
130
|
+
}
|
|
131
|
+
if (fields.length === 0)
|
|
132
|
+
return getProjectById(id);
|
|
133
|
+
fields.push('updated_at = ?');
|
|
134
|
+
values.push(new Date().toISOString());
|
|
135
|
+
values.push(id);
|
|
136
|
+
db.prepare(`UPDATE projects SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
137
|
+
return getProjectById(id);
|
|
138
|
+
}
|
|
139
|
+
export function syncProjectCliDefaults(projectId, previousTool, previousModel, nextTool, nextModel) {
|
|
140
|
+
const db = getDatabase();
|
|
141
|
+
const now = new Date().toISOString();
|
|
142
|
+
const todoResult = db.prepare(`UPDATE todos
|
|
143
|
+
SET cli_tool = ?, cli_model = ?, updated_at = ?
|
|
144
|
+
WHERE project_id = ?
|
|
145
|
+
AND status != 'running'
|
|
146
|
+
AND ((cli_tool = ?) OR (cli_tool IS NULL AND ? IS NULL))
|
|
147
|
+
AND ((cli_model = ?) OR (cli_model IS NULL AND ? IS NULL))`).run(nextTool, nextModel, now, projectId, previousTool, previousTool, previousModel, previousModel);
|
|
148
|
+
const scheduleResult = db.prepare(`UPDATE schedules
|
|
149
|
+
SET cli_tool = ?, cli_model = ?, updated_at = ?
|
|
150
|
+
WHERE project_id = ?
|
|
151
|
+
AND ((cli_tool = ?) OR (cli_tool IS NULL AND ? IS NULL))
|
|
152
|
+
AND ((cli_model = ?) OR (cli_model IS NULL AND ? IS NULL))`).run(nextTool, nextModel, now, projectId, previousTool, previousTool, previousModel, previousModel);
|
|
153
|
+
return {
|
|
154
|
+
updatedTodos: todoResult.changes,
|
|
155
|
+
updatedSchedules: scheduleResult.changes,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
export function deleteProject(id) {
|
|
159
|
+
const db = getDatabase();
|
|
160
|
+
const result = db.prepare('DELETE FROM projects WHERE id = ?').run(id);
|
|
161
|
+
return result.changes > 0;
|
|
162
|
+
}
|
|
163
|
+
export function createTodo(projectId, title, description, priority = 0, cliTool, cliModel, scheduleId, dependsOn, maxTurns) {
|
|
164
|
+
const db = getDatabase();
|
|
165
|
+
const id = uuidv4();
|
|
166
|
+
const now = new Date().toISOString();
|
|
167
|
+
db.prepare(`INSERT INTO todos (id, project_id, title, description, priority, cli_tool, cli_model, schedule_id, depends_on, max_turns, created_at, updated_at)
|
|
168
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, projectId, title, description ?? null, priority, cliTool ?? null, cliModel ?? null, scheduleId ?? null, dependsOn ?? null, maxTurns ?? null, now, now);
|
|
169
|
+
return getTodoById(id);
|
|
170
|
+
}
|
|
171
|
+
export function getTodosByProjectId(projectId) {
|
|
172
|
+
const db = getDatabase();
|
|
173
|
+
return db.prepare('SELECT * FROM todos WHERE project_id = ? ORDER BY priority DESC, created_at ASC').all(projectId);
|
|
174
|
+
}
|
|
175
|
+
export function getTodoById(id) {
|
|
176
|
+
const db = getDatabase();
|
|
177
|
+
return db.prepare('SELECT * FROM todos WHERE id = ?').get(id);
|
|
178
|
+
}
|
|
179
|
+
export function updateTodo(id, updates) {
|
|
180
|
+
const db = getDatabase();
|
|
181
|
+
const fields = [];
|
|
182
|
+
const values = [];
|
|
183
|
+
if (updates.title !== undefined) {
|
|
184
|
+
fields.push('title = ?');
|
|
185
|
+
values.push(updates.title);
|
|
186
|
+
}
|
|
187
|
+
if (updates.description !== undefined) {
|
|
188
|
+
fields.push('description = ?');
|
|
189
|
+
values.push(updates.description);
|
|
190
|
+
}
|
|
191
|
+
if (updates.priority !== undefined) {
|
|
192
|
+
fields.push('priority = ?');
|
|
193
|
+
values.push(updates.priority);
|
|
194
|
+
}
|
|
195
|
+
if (updates.branch_name !== undefined) {
|
|
196
|
+
fields.push('branch_name = ?');
|
|
197
|
+
values.push(updates.branch_name);
|
|
198
|
+
}
|
|
199
|
+
if (updates.worktree_path !== undefined) {
|
|
200
|
+
fields.push('worktree_path = ?');
|
|
201
|
+
values.push(updates.worktree_path);
|
|
202
|
+
}
|
|
203
|
+
if (updates.process_pid !== undefined) {
|
|
204
|
+
fields.push('process_pid = ?');
|
|
205
|
+
values.push(updates.process_pid);
|
|
206
|
+
}
|
|
207
|
+
if (updates.cli_tool !== undefined) {
|
|
208
|
+
fields.push('cli_tool = ?');
|
|
209
|
+
values.push(updates.cli_tool);
|
|
210
|
+
}
|
|
211
|
+
if (updates.cli_model !== undefined) {
|
|
212
|
+
fields.push('cli_model = ?');
|
|
213
|
+
values.push(updates.cli_model);
|
|
214
|
+
}
|
|
215
|
+
if (updates.images !== undefined) {
|
|
216
|
+
fields.push('images = ?');
|
|
217
|
+
values.push(updates.images);
|
|
218
|
+
}
|
|
219
|
+
if (updates.depends_on !== undefined) {
|
|
220
|
+
fields.push('depends_on = ?');
|
|
221
|
+
values.push(updates.depends_on);
|
|
222
|
+
}
|
|
223
|
+
if (updates.max_turns !== undefined) {
|
|
224
|
+
fields.push('max_turns = ?');
|
|
225
|
+
values.push(updates.max_turns);
|
|
226
|
+
}
|
|
227
|
+
if (updates.token_usage !== undefined) {
|
|
228
|
+
fields.push('token_usage = ?');
|
|
229
|
+
values.push(updates.token_usage);
|
|
230
|
+
}
|
|
231
|
+
if (updates.position_x !== undefined) {
|
|
232
|
+
fields.push('position_x = ?');
|
|
233
|
+
values.push(updates.position_x);
|
|
234
|
+
}
|
|
235
|
+
if (updates.position_y !== undefined) {
|
|
236
|
+
fields.push('position_y = ?');
|
|
237
|
+
values.push(updates.position_y);
|
|
238
|
+
}
|
|
239
|
+
if (updates.merged_from_branch !== undefined) {
|
|
240
|
+
fields.push('merged_from_branch = ?');
|
|
241
|
+
values.push(updates.merged_from_branch);
|
|
242
|
+
}
|
|
243
|
+
if (updates.context_switch_count !== undefined) {
|
|
244
|
+
fields.push('context_switch_count = ?');
|
|
245
|
+
values.push(updates.context_switch_count);
|
|
246
|
+
}
|
|
247
|
+
if (fields.length === 0)
|
|
248
|
+
return getTodoById(id);
|
|
249
|
+
fields.push('updated_at = ?');
|
|
250
|
+
values.push(new Date().toISOString());
|
|
251
|
+
values.push(id);
|
|
252
|
+
db.prepare(`UPDATE todos SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
253
|
+
return getTodoById(id);
|
|
254
|
+
}
|
|
255
|
+
export function updateTodoStatus(id, status) {
|
|
256
|
+
const db = getDatabase();
|
|
257
|
+
db.prepare('UPDATE todos SET status = ?, updated_at = ? WHERE id = ?').run(status, new Date().toISOString(), id);
|
|
258
|
+
return getTodoById(id);
|
|
259
|
+
}
|
|
260
|
+
export function getTodosByStatus(status) {
|
|
261
|
+
const db = getDatabase();
|
|
262
|
+
return db.prepare('SELECT * FROM todos WHERE status = ? ORDER BY priority DESC, created_at ASC').all(status);
|
|
263
|
+
}
|
|
264
|
+
export function deleteTodo(id) {
|
|
265
|
+
const db = getDatabase();
|
|
266
|
+
const result = db.prepare('DELETE FROM todos WHERE id = ?').run(id);
|
|
267
|
+
return result.changes > 0;
|
|
268
|
+
}
|
|
269
|
+
export function createTaskLog(todoId, logType, message) {
|
|
270
|
+
const db = getDatabase();
|
|
271
|
+
const id = uuidv4();
|
|
272
|
+
const now = new Date().toISOString();
|
|
273
|
+
db.prepare(`INSERT INTO task_logs (id, todo_id, log_type, message, created_at)
|
|
274
|
+
VALUES (?, ?, ?, ?, ?)`).run(id, todoId, logType, message, now);
|
|
275
|
+
return db.prepare('SELECT * FROM task_logs WHERE id = ?').get(id);
|
|
276
|
+
}
|
|
277
|
+
export function getTaskLogsByTodoId(todoId) {
|
|
278
|
+
const db = getDatabase();
|
|
279
|
+
return db.prepare('SELECT * FROM task_logs WHERE todo_id = ? ORDER BY created_at ASC').all(todoId);
|
|
280
|
+
}
|
|
281
|
+
export function deleteTaskLogsByTodoId(todoId) {
|
|
282
|
+
const db = getDatabase();
|
|
283
|
+
const result = db.prepare('DELETE FROM task_logs WHERE todo_id = ?').run(todoId);
|
|
284
|
+
return result.changes;
|
|
285
|
+
}
|
|
286
|
+
export function createPipeline(projectId, title, description) {
|
|
287
|
+
const db = getDatabase();
|
|
288
|
+
const id = uuidv4();
|
|
289
|
+
const now = new Date().toISOString();
|
|
290
|
+
db.prepare(`INSERT INTO pipelines (id, project_id, title, description, created_at, updated_at)
|
|
291
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(id, projectId, title, description, now, now);
|
|
292
|
+
return getPipelineById(id);
|
|
293
|
+
}
|
|
294
|
+
export function getPipelinesByProjectId(projectId) {
|
|
295
|
+
const db = getDatabase();
|
|
296
|
+
return db.prepare('SELECT * FROM pipelines WHERE project_id = ? ORDER BY created_at DESC').all(projectId);
|
|
297
|
+
}
|
|
298
|
+
export function getPipelineById(id) {
|
|
299
|
+
const db = getDatabase();
|
|
300
|
+
return db.prepare('SELECT * FROM pipelines WHERE id = ?').get(id);
|
|
301
|
+
}
|
|
302
|
+
export function updatePipeline(id, updates) {
|
|
303
|
+
const db = getDatabase();
|
|
304
|
+
const fields = [];
|
|
305
|
+
const values = [];
|
|
306
|
+
if (updates.title !== undefined) {
|
|
307
|
+
fields.push('title = ?');
|
|
308
|
+
values.push(updates.title);
|
|
309
|
+
}
|
|
310
|
+
if (updates.description !== undefined) {
|
|
311
|
+
fields.push('description = ?');
|
|
312
|
+
values.push(updates.description);
|
|
313
|
+
}
|
|
314
|
+
if (updates.current_phase !== undefined) {
|
|
315
|
+
fields.push('current_phase = ?');
|
|
316
|
+
values.push(updates.current_phase);
|
|
317
|
+
}
|
|
318
|
+
if (updates.branch_name !== undefined) {
|
|
319
|
+
fields.push('branch_name = ?');
|
|
320
|
+
values.push(updates.branch_name);
|
|
321
|
+
}
|
|
322
|
+
if (updates.worktree_path !== undefined) {
|
|
323
|
+
fields.push('worktree_path = ?');
|
|
324
|
+
values.push(updates.worktree_path);
|
|
325
|
+
}
|
|
326
|
+
if (updates.process_pid !== undefined) {
|
|
327
|
+
fields.push('process_pid = ?');
|
|
328
|
+
values.push(updates.process_pid);
|
|
329
|
+
}
|
|
330
|
+
if (fields.length === 0)
|
|
331
|
+
return getPipelineById(id);
|
|
332
|
+
fields.push('updated_at = ?');
|
|
333
|
+
values.push(new Date().toISOString());
|
|
334
|
+
values.push(id);
|
|
335
|
+
db.prepare(`UPDATE pipelines SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
336
|
+
return getPipelineById(id);
|
|
337
|
+
}
|
|
338
|
+
export function updatePipelineStatus(id, status) {
|
|
339
|
+
const db = getDatabase();
|
|
340
|
+
db.prepare('UPDATE pipelines SET status = ?, updated_at = ? WHERE id = ?').run(status, new Date().toISOString(), id);
|
|
341
|
+
return getPipelineById(id);
|
|
342
|
+
}
|
|
343
|
+
export function getPipelinesByStatus(status) {
|
|
344
|
+
const db = getDatabase();
|
|
345
|
+
return db.prepare('SELECT * FROM pipelines WHERE status = ? ORDER BY created_at DESC').all(status);
|
|
346
|
+
}
|
|
347
|
+
export function deletePipeline(id) {
|
|
348
|
+
const db = getDatabase();
|
|
349
|
+
const result = db.prepare('DELETE FROM pipelines WHERE id = ?').run(id);
|
|
350
|
+
return result.changes > 0;
|
|
351
|
+
}
|
|
352
|
+
export function createPipelinePhase(pipelineId, phaseType, phaseOrder) {
|
|
353
|
+
const db = getDatabase();
|
|
354
|
+
const id = uuidv4();
|
|
355
|
+
const now = new Date().toISOString();
|
|
356
|
+
db.prepare(`INSERT INTO pipeline_phases (id, pipeline_id, phase_type, phase_order, created_at)
|
|
357
|
+
VALUES (?, ?, ?, ?, ?)`).run(id, pipelineId, phaseType, phaseOrder, now);
|
|
358
|
+
return db.prepare('SELECT * FROM pipeline_phases WHERE id = ?').get(id);
|
|
359
|
+
}
|
|
360
|
+
export function getPipelinePhases(pipelineId) {
|
|
361
|
+
const db = getDatabase();
|
|
362
|
+
return db.prepare('SELECT * FROM pipeline_phases WHERE pipeline_id = ? ORDER BY phase_order ASC').all(pipelineId);
|
|
363
|
+
}
|
|
364
|
+
export function updatePipelinePhase(id, updates) {
|
|
365
|
+
const db = getDatabase();
|
|
366
|
+
const fields = [];
|
|
367
|
+
const values = [];
|
|
368
|
+
if (updates.status !== undefined) {
|
|
369
|
+
fields.push('status = ?');
|
|
370
|
+
values.push(updates.status);
|
|
371
|
+
}
|
|
372
|
+
if (updates.output !== undefined) {
|
|
373
|
+
fields.push('output = ?');
|
|
374
|
+
values.push(updates.output);
|
|
375
|
+
}
|
|
376
|
+
if (updates.started_at !== undefined) {
|
|
377
|
+
fields.push('started_at = ?');
|
|
378
|
+
values.push(updates.started_at);
|
|
379
|
+
}
|
|
380
|
+
if (updates.completed_at !== undefined) {
|
|
381
|
+
fields.push('completed_at = ?');
|
|
382
|
+
values.push(updates.completed_at);
|
|
383
|
+
}
|
|
384
|
+
if (fields.length === 0)
|
|
385
|
+
return undefined;
|
|
386
|
+
values.push(id);
|
|
387
|
+
db.prepare(`UPDATE pipeline_phases SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
388
|
+
return db.prepare('SELECT * FROM pipeline_phases WHERE id = ?').get(id);
|
|
389
|
+
}
|
|
390
|
+
export function createPipelineLog(pipelineId, phaseType, logType, message) {
|
|
391
|
+
const db = getDatabase();
|
|
392
|
+
const id = uuidv4();
|
|
393
|
+
const now = new Date().toISOString();
|
|
394
|
+
db.prepare(`INSERT INTO pipeline_logs (id, pipeline_id, phase_type, log_type, message, created_at)
|
|
395
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(id, pipelineId, phaseType, logType, message, now);
|
|
396
|
+
return db.prepare('SELECT * FROM pipeline_logs WHERE id = ?').get(id);
|
|
397
|
+
}
|
|
398
|
+
export function getPipelineLogs(pipelineId, phaseType) {
|
|
399
|
+
const db = getDatabase();
|
|
400
|
+
if (phaseType) {
|
|
401
|
+
return db.prepare('SELECT * FROM pipeline_logs WHERE pipeline_id = ? AND phase_type = ? ORDER BY created_at ASC').all(pipelineId, phaseType);
|
|
402
|
+
}
|
|
403
|
+
return db.prepare('SELECT * FROM pipeline_logs WHERE pipeline_id = ? ORDER BY created_at ASC').all(pipelineId);
|
|
404
|
+
}
|
|
405
|
+
export function createSchedule(projectId, title, description, cronExpression, cliTool, cliModel, skipIfRunning = 1, scheduleType = 'recurring', runAt) {
|
|
406
|
+
const db = getDatabase();
|
|
407
|
+
const id = uuidv4();
|
|
408
|
+
const now = new Date().toISOString();
|
|
409
|
+
db.prepare(`INSERT INTO schedules (id, project_id, title, description, cron_expression, cli_tool, cli_model, skip_if_running, schedule_type, run_at, created_at, updated_at)
|
|
410
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, projectId, title, description ?? null, cronExpression, cliTool ?? null, cliModel ?? null, skipIfRunning, scheduleType, runAt ?? null, now, now);
|
|
411
|
+
return getScheduleById(id);
|
|
412
|
+
}
|
|
413
|
+
export function getSchedulesByProjectId(projectId) {
|
|
414
|
+
const db = getDatabase();
|
|
415
|
+
return db.prepare('SELECT * FROM schedules WHERE project_id = ? ORDER BY created_at DESC').all(projectId);
|
|
416
|
+
}
|
|
417
|
+
export function getScheduleById(id) {
|
|
418
|
+
const db = getDatabase();
|
|
419
|
+
return db.prepare('SELECT * FROM schedules WHERE id = ?').get(id);
|
|
420
|
+
}
|
|
421
|
+
export function getActiveSchedules() {
|
|
422
|
+
const db = getDatabase();
|
|
423
|
+
return db.prepare('SELECT * FROM schedules WHERE is_active = 1').all();
|
|
424
|
+
}
|
|
425
|
+
export function getActiveOnceSchedules() {
|
|
426
|
+
const db = getDatabase();
|
|
427
|
+
return db.prepare("SELECT * FROM schedules WHERE is_active = 1 AND schedule_type = 'once'").all();
|
|
428
|
+
}
|
|
429
|
+
export function updateSchedule(id, updates) {
|
|
430
|
+
const db = getDatabase();
|
|
431
|
+
const fields = [];
|
|
432
|
+
const values = [];
|
|
433
|
+
if (updates.title !== undefined) {
|
|
434
|
+
fields.push('title = ?');
|
|
435
|
+
values.push(updates.title);
|
|
436
|
+
}
|
|
437
|
+
if (updates.description !== undefined) {
|
|
438
|
+
fields.push('description = ?');
|
|
439
|
+
values.push(updates.description);
|
|
440
|
+
}
|
|
441
|
+
if (updates.cron_expression !== undefined) {
|
|
442
|
+
fields.push('cron_expression = ?');
|
|
443
|
+
values.push(updates.cron_expression);
|
|
444
|
+
}
|
|
445
|
+
if (updates.cli_tool !== undefined) {
|
|
446
|
+
fields.push('cli_tool = ?');
|
|
447
|
+
values.push(updates.cli_tool);
|
|
448
|
+
}
|
|
449
|
+
if (updates.cli_model !== undefined) {
|
|
450
|
+
fields.push('cli_model = ?');
|
|
451
|
+
values.push(updates.cli_model);
|
|
452
|
+
}
|
|
453
|
+
if (updates.skip_if_running !== undefined) {
|
|
454
|
+
fields.push('skip_if_running = ?');
|
|
455
|
+
values.push(updates.skip_if_running);
|
|
456
|
+
}
|
|
457
|
+
if (updates.schedule_type !== undefined) {
|
|
458
|
+
fields.push('schedule_type = ?');
|
|
459
|
+
values.push(updates.schedule_type);
|
|
460
|
+
}
|
|
461
|
+
if (updates.run_at !== undefined) {
|
|
462
|
+
fields.push('run_at = ?');
|
|
463
|
+
values.push(updates.run_at);
|
|
464
|
+
}
|
|
465
|
+
if (fields.length === 0)
|
|
466
|
+
return getScheduleById(id);
|
|
467
|
+
fields.push('updated_at = ?');
|
|
468
|
+
values.push(new Date().toISOString());
|
|
469
|
+
values.push(id);
|
|
470
|
+
db.prepare(`UPDATE schedules SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
471
|
+
return getScheduleById(id);
|
|
472
|
+
}
|
|
473
|
+
export function updateScheduleStatus(id, isActive) {
|
|
474
|
+
const db = getDatabase();
|
|
475
|
+
db.prepare('UPDATE schedules SET is_active = ?, updated_at = ? WHERE id = ?').run(isActive, new Date().toISOString(), id);
|
|
476
|
+
return getScheduleById(id);
|
|
477
|
+
}
|
|
478
|
+
export function updateScheduleLastRun(id, lastRunAt) {
|
|
479
|
+
const db = getDatabase();
|
|
480
|
+
db.prepare('UPDATE schedules SET last_run_at = ?, updated_at = ? WHERE id = ?').run(lastRunAt, new Date().toISOString(), id);
|
|
481
|
+
}
|
|
482
|
+
export function deleteSchedule(id) {
|
|
483
|
+
const db = getDatabase();
|
|
484
|
+
const result = db.prepare('DELETE FROM schedules WHERE id = ?').run(id);
|
|
485
|
+
return result.changes > 0;
|
|
486
|
+
}
|
|
487
|
+
export function getTodosByScheduleId(scheduleId) {
|
|
488
|
+
const db = getDatabase();
|
|
489
|
+
return db.prepare('SELECT * FROM todos WHERE schedule_id = ? ORDER BY created_at DESC').all(scheduleId);
|
|
490
|
+
}
|
|
491
|
+
export function createScheduleRun(scheduleId, todoId, status, skippedReason) {
|
|
492
|
+
const db = getDatabase();
|
|
493
|
+
const id = uuidv4();
|
|
494
|
+
const now = new Date().toISOString();
|
|
495
|
+
db.prepare(`INSERT INTO schedule_runs (id, schedule_id, todo_id, status, skipped_reason, started_at)
|
|
496
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(id, scheduleId, todoId, status, skippedReason ?? null, now);
|
|
497
|
+
return db.prepare('SELECT * FROM schedule_runs WHERE id = ?').get(id);
|
|
498
|
+
}
|
|
499
|
+
export function updateScheduleRun(id, updates) {
|
|
500
|
+
const db = getDatabase();
|
|
501
|
+
const fields = [];
|
|
502
|
+
const values = [];
|
|
503
|
+
if (updates.status !== undefined) {
|
|
504
|
+
fields.push('status = ?');
|
|
505
|
+
values.push(updates.status);
|
|
506
|
+
}
|
|
507
|
+
if (updates.completed_at !== undefined) {
|
|
508
|
+
fields.push('completed_at = ?');
|
|
509
|
+
values.push(updates.completed_at);
|
|
510
|
+
}
|
|
511
|
+
if (fields.length === 0)
|
|
512
|
+
return undefined;
|
|
513
|
+
values.push(id);
|
|
514
|
+
db.prepare(`UPDATE schedule_runs SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
515
|
+
return db.prepare('SELECT * FROM schedule_runs WHERE id = ?').get(id);
|
|
516
|
+
}
|
|
517
|
+
export function getScheduleRunsByScheduleId(scheduleId, limit = 50) {
|
|
518
|
+
const db = getDatabase();
|
|
519
|
+
return db.prepare(`
|
|
520
|
+
SELECT sr.*, t.branch_name AS todo_branch_name, t.worktree_path AS todo_worktree_path, t.status AS todo_status
|
|
521
|
+
FROM schedule_runs sr
|
|
522
|
+
LEFT JOIN todos t ON sr.todo_id = t.id
|
|
523
|
+
WHERE sr.schedule_id = ?
|
|
524
|
+
ORDER BY sr.started_at DESC LIMIT ?
|
|
525
|
+
`).all(scheduleId, limit);
|
|
526
|
+
}
|
|
527
|
+
export function getModelsByTool(tool) {
|
|
528
|
+
const db = getDatabase();
|
|
529
|
+
return db.prepare('SELECT * FROM cli_models WHERE cli_tool = ? ORDER BY sort_order ASC').all(tool);
|
|
530
|
+
}
|
|
531
|
+
export function getAllModels() {
|
|
532
|
+
const db = getDatabase();
|
|
533
|
+
const rows = db.prepare('SELECT * FROM cli_models ORDER BY cli_tool ASC, sort_order ASC').all();
|
|
534
|
+
const grouped = {};
|
|
535
|
+
for (const row of rows) {
|
|
536
|
+
if (!grouped[row.cli_tool])
|
|
537
|
+
grouped[row.cli_tool] = [];
|
|
538
|
+
grouped[row.cli_tool].push(row);
|
|
539
|
+
}
|
|
540
|
+
return grouped;
|
|
541
|
+
}
|
|
542
|
+
export function addModel(cliTool, modelValue, modelLabel) {
|
|
543
|
+
const db = getDatabase();
|
|
544
|
+
const id = uuidv4();
|
|
545
|
+
const maxOrder = db.prepare('SELECT MAX(sort_order) as max_order FROM cli_models WHERE cli_tool = ?').get(cliTool);
|
|
546
|
+
const sortOrder = (maxOrder.max_order ?? -1) + 1;
|
|
547
|
+
db.prepare(`INSERT INTO cli_models (id, cli_tool, model_value, model_label, sort_order, is_default) VALUES (?, ?, ?, ?, ?, 0)`).run(id, cliTool, modelValue, modelLabel, sortOrder);
|
|
548
|
+
return db.prepare('SELECT * FROM cli_models WHERE id = ?').get(id);
|
|
549
|
+
}
|
|
550
|
+
export function removeModel(id) {
|
|
551
|
+
const db = getDatabase();
|
|
552
|
+
const model = db.prepare('SELECT * FROM cli_models WHERE id = ?').get(id);
|
|
553
|
+
if (!model || model.is_default === 1)
|
|
554
|
+
return false;
|
|
555
|
+
const result = db.prepare('DELETE FROM cli_models WHERE id = ? AND is_default = 0').run(id);
|
|
556
|
+
return result.changes > 0;
|
|
557
|
+
}
|
|
558
|
+
export function isModelSupported(cliTool, modelValue) {
|
|
559
|
+
const db = getDatabase();
|
|
560
|
+
const row = db.prepare('SELECT 1 FROM cli_models WHERE cli_tool = ? AND model_value = ?').get(cliTool, modelValue);
|
|
561
|
+
return !!row;
|
|
562
|
+
}
|
|
563
|
+
// ── CLI Fallback ──
|
|
564
|
+
export function getNextFallbackCli(projectId, currentCliTool) {
|
|
565
|
+
const project = getProjectById(projectId);
|
|
566
|
+
if (!project?.cli_fallback_chain)
|
|
567
|
+
return null;
|
|
568
|
+
let chain;
|
|
569
|
+
try {
|
|
570
|
+
chain = JSON.parse(project.cli_fallback_chain);
|
|
571
|
+
}
|
|
572
|
+
catch {
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
if (!Array.isArray(chain) || chain.length === 0)
|
|
576
|
+
return null;
|
|
577
|
+
const currentIndex = chain.indexOf(currentCliTool);
|
|
578
|
+
if (currentIndex === -1 || currentIndex >= chain.length - 1)
|
|
579
|
+
return null;
|
|
580
|
+
return { cliTool: chain[currentIndex + 1], cliModel: null };
|
|
581
|
+
}
|
|
582
|
+
// ── Plugin Configs ──
|
|
583
|
+
export function getPluginConfig(projectId, pluginId) {
|
|
584
|
+
const db = getDatabase();
|
|
585
|
+
const rows = db.prepare('SELECT config_key, config_value FROM plugin_configs WHERE project_id = ? AND plugin_id = ?').all(projectId, pluginId);
|
|
586
|
+
if (rows.length === 0)
|
|
587
|
+
return null;
|
|
588
|
+
const config = {};
|
|
589
|
+
for (const row of rows) {
|
|
590
|
+
config[row.config_key] = row.config_value;
|
|
591
|
+
}
|
|
592
|
+
return config;
|
|
593
|
+
}
|
|
594
|
+
export function setPluginConfigs(projectId, pluginId, configs) {
|
|
595
|
+
const db = getDatabase();
|
|
596
|
+
const now = new Date().toISOString();
|
|
597
|
+
const upsert = db.prepare(`INSERT INTO plugin_configs (id, project_id, plugin_id, config_key, config_value, created_at, updated_at)
|
|
598
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
599
|
+
ON CONFLICT(project_id, plugin_id, config_key) DO UPDATE SET config_value = excluded.config_value, updated_at = excluded.updated_at`);
|
|
600
|
+
const transaction = db.transaction(() => {
|
|
601
|
+
for (const [key, value] of Object.entries(configs)) {
|
|
602
|
+
upsert.run(uuidv4(), projectId, pluginId, key, value, now, now);
|
|
603
|
+
}
|
|
604
|
+
});
|
|
605
|
+
transaction();
|
|
606
|
+
}
|
|
607
|
+
export function isPluginEnabled(projectId, pluginId) {
|
|
608
|
+
const db = getDatabase();
|
|
609
|
+
const row = db.prepare("SELECT config_value FROM plugin_configs WHERE project_id = ? AND plugin_id = ? AND config_key = 'enabled'").get(projectId, pluginId);
|
|
610
|
+
return row?.config_value === '1';
|
|
611
|
+
}
|
|
612
|
+
export function deletePluginConfigs(projectId, pluginId) {
|
|
613
|
+
const db = getDatabase();
|
|
614
|
+
db.prepare('DELETE FROM plugin_configs WHERE project_id = ? AND plugin_id = ?').run(projectId, pluginId);
|
|
615
|
+
}
|
|
616
|
+
export function createDiscussionAgent(projectId, name, role, systemPrompt, cliTool, cliModel, avatarColor) {
|
|
617
|
+
const db = getDatabase();
|
|
618
|
+
const id = uuidv4();
|
|
619
|
+
const now = new Date().toISOString();
|
|
620
|
+
const maxOrder = db.prepare('SELECT MAX(sort_order) as max_order FROM discussion_agents WHERE project_id = ?').get(projectId);
|
|
621
|
+
const sortOrder = (maxOrder.max_order ?? -1) + 1;
|
|
622
|
+
db.prepare(`INSERT INTO discussion_agents (id, project_id, name, role, system_prompt, cli_tool, cli_model, avatar_color, sort_order, created_at, updated_at)
|
|
623
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, projectId, name, role, systemPrompt, cliTool ?? null, cliModel ?? null, avatarColor ?? null, sortOrder, now, now);
|
|
624
|
+
return getDiscussionAgentById(id);
|
|
625
|
+
}
|
|
626
|
+
export function getDiscussionAgentsByProjectId(projectId) {
|
|
627
|
+
const db = getDatabase();
|
|
628
|
+
return db.prepare('SELECT * FROM discussion_agents WHERE project_id = ? ORDER BY sort_order ASC').all(projectId);
|
|
629
|
+
}
|
|
630
|
+
export function getDiscussionAgentById(id) {
|
|
631
|
+
const db = getDatabase();
|
|
632
|
+
return db.prepare('SELECT * FROM discussion_agents WHERE id = ?').get(id);
|
|
633
|
+
}
|
|
634
|
+
export function updateDiscussionAgent(id, updates) {
|
|
635
|
+
const db = getDatabase();
|
|
636
|
+
const fields = [];
|
|
637
|
+
const values = [];
|
|
638
|
+
if (updates.name !== undefined) {
|
|
639
|
+
fields.push('name = ?');
|
|
640
|
+
values.push(updates.name);
|
|
641
|
+
}
|
|
642
|
+
if (updates.role !== undefined) {
|
|
643
|
+
fields.push('role = ?');
|
|
644
|
+
values.push(updates.role);
|
|
645
|
+
}
|
|
646
|
+
if (updates.system_prompt !== undefined) {
|
|
647
|
+
fields.push('system_prompt = ?');
|
|
648
|
+
values.push(updates.system_prompt);
|
|
649
|
+
}
|
|
650
|
+
if (updates.cli_tool !== undefined) {
|
|
651
|
+
fields.push('cli_tool = ?');
|
|
652
|
+
values.push(updates.cli_tool);
|
|
653
|
+
}
|
|
654
|
+
if (updates.cli_model !== undefined) {
|
|
655
|
+
fields.push('cli_model = ?');
|
|
656
|
+
values.push(updates.cli_model);
|
|
657
|
+
}
|
|
658
|
+
if (updates.avatar_color !== undefined) {
|
|
659
|
+
fields.push('avatar_color = ?');
|
|
660
|
+
values.push(updates.avatar_color);
|
|
661
|
+
}
|
|
662
|
+
if (updates.sort_order !== undefined) {
|
|
663
|
+
fields.push('sort_order = ?');
|
|
664
|
+
values.push(updates.sort_order);
|
|
665
|
+
}
|
|
666
|
+
if (fields.length === 0)
|
|
667
|
+
return getDiscussionAgentById(id);
|
|
668
|
+
fields.push('updated_at = ?');
|
|
669
|
+
values.push(new Date().toISOString());
|
|
670
|
+
values.push(id);
|
|
671
|
+
db.prepare(`UPDATE discussion_agents SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
672
|
+
return getDiscussionAgentById(id);
|
|
673
|
+
}
|
|
674
|
+
export function deleteDiscussionAgent(id) {
|
|
675
|
+
const db = getDatabase();
|
|
676
|
+
const result = db.prepare('DELETE FROM discussion_agents WHERE id = ?').run(id);
|
|
677
|
+
return result.changes > 0;
|
|
678
|
+
}
|
|
679
|
+
export function createDiscussion(projectId, title, description, agentIds, maxRounds = 3, autoImplement = false, implementAgentId) {
|
|
680
|
+
const db = getDatabase();
|
|
681
|
+
const id = uuidv4();
|
|
682
|
+
const now = new Date().toISOString();
|
|
683
|
+
db.prepare(`INSERT INTO discussions (id, project_id, title, description, max_rounds, agent_ids, auto_implement, implement_agent_id, created_at, updated_at)
|
|
684
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, projectId, title, description, maxRounds, JSON.stringify(agentIds), autoImplement ? 1 : 0, implementAgentId || null, now, now);
|
|
685
|
+
return getDiscussionById(id);
|
|
686
|
+
}
|
|
687
|
+
export function getDiscussionsByProjectId(projectId) {
|
|
688
|
+
const db = getDatabase();
|
|
689
|
+
return db.prepare('SELECT * FROM discussions WHERE project_id = ? ORDER BY created_at DESC').all(projectId);
|
|
690
|
+
}
|
|
691
|
+
export function getDiscussionById(id) {
|
|
692
|
+
const db = getDatabase();
|
|
693
|
+
return db.prepare('SELECT * FROM discussions WHERE id = ?').get(id);
|
|
694
|
+
}
|
|
695
|
+
export function updateDiscussion(id, updates) {
|
|
696
|
+
const db = getDatabase();
|
|
697
|
+
const fields = [];
|
|
698
|
+
const values = [];
|
|
699
|
+
if (updates.title !== undefined) {
|
|
700
|
+
fields.push('title = ?');
|
|
701
|
+
values.push(updates.title);
|
|
702
|
+
}
|
|
703
|
+
if (updates.description !== undefined) {
|
|
704
|
+
fields.push('description = ?');
|
|
705
|
+
values.push(updates.description);
|
|
706
|
+
}
|
|
707
|
+
if (updates.current_round !== undefined) {
|
|
708
|
+
fields.push('current_round = ?');
|
|
709
|
+
values.push(updates.current_round);
|
|
710
|
+
}
|
|
711
|
+
if (updates.max_rounds !== undefined) {
|
|
712
|
+
fields.push('max_rounds = ?');
|
|
713
|
+
values.push(updates.max_rounds);
|
|
714
|
+
}
|
|
715
|
+
if (updates.current_agent_id !== undefined) {
|
|
716
|
+
fields.push('current_agent_id = ?');
|
|
717
|
+
values.push(updates.current_agent_id);
|
|
718
|
+
}
|
|
719
|
+
if (updates.branch_name !== undefined) {
|
|
720
|
+
fields.push('branch_name = ?');
|
|
721
|
+
values.push(updates.branch_name);
|
|
722
|
+
}
|
|
723
|
+
if (updates.worktree_path !== undefined) {
|
|
724
|
+
fields.push('worktree_path = ?');
|
|
725
|
+
values.push(updates.worktree_path);
|
|
726
|
+
}
|
|
727
|
+
if (updates.process_pid !== undefined) {
|
|
728
|
+
fields.push('process_pid = ?');
|
|
729
|
+
values.push(updates.process_pid);
|
|
730
|
+
}
|
|
731
|
+
if (updates.agent_ids !== undefined) {
|
|
732
|
+
fields.push('agent_ids = ?');
|
|
733
|
+
values.push(updates.agent_ids);
|
|
734
|
+
}
|
|
735
|
+
if (updates.auto_implement !== undefined) {
|
|
736
|
+
fields.push('auto_implement = ?');
|
|
737
|
+
values.push(updates.auto_implement);
|
|
738
|
+
}
|
|
739
|
+
if (updates.implement_agent_id !== undefined) {
|
|
740
|
+
fields.push('implement_agent_id = ?');
|
|
741
|
+
values.push(updates.implement_agent_id);
|
|
742
|
+
}
|
|
743
|
+
if (fields.length === 0)
|
|
744
|
+
return getDiscussionById(id);
|
|
745
|
+
fields.push('updated_at = ?');
|
|
746
|
+
values.push(new Date().toISOString());
|
|
747
|
+
values.push(id);
|
|
748
|
+
db.prepare(`UPDATE discussions SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
749
|
+
return getDiscussionById(id);
|
|
750
|
+
}
|
|
751
|
+
export function updateDiscussionStatus(id, status) {
|
|
752
|
+
const db = getDatabase();
|
|
753
|
+
db.prepare('UPDATE discussions SET status = ?, updated_at = ? WHERE id = ?').run(status, new Date().toISOString(), id);
|
|
754
|
+
return getDiscussionById(id);
|
|
755
|
+
}
|
|
756
|
+
export function getDiscussionsByStatus(status) {
|
|
757
|
+
const db = getDatabase();
|
|
758
|
+
return db.prepare('SELECT * FROM discussions WHERE status = ? ORDER BY created_at DESC').all(status);
|
|
759
|
+
}
|
|
760
|
+
export function deleteDiscussion(id) {
|
|
761
|
+
const db = getDatabase();
|
|
762
|
+
const result = db.prepare('DELETE FROM discussions WHERE id = ?').run(id);
|
|
763
|
+
return result.changes > 0;
|
|
764
|
+
}
|
|
765
|
+
export function createDiscussionMessage(discussionId, agentId, roundNumber, turnOrder, role, agentName) {
|
|
766
|
+
const db = getDatabase();
|
|
767
|
+
const id = uuidv4();
|
|
768
|
+
const now = new Date().toISOString();
|
|
769
|
+
db.prepare(`INSERT INTO discussion_messages (id, discussion_id, agent_id, round_number, turn_order, role, agent_name, created_at)
|
|
770
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(id, discussionId, agentId, roundNumber, turnOrder, role, agentName, now);
|
|
771
|
+
return db.prepare('SELECT * FROM discussion_messages WHERE id = ?').get(id);
|
|
772
|
+
}
|
|
773
|
+
export function getDiscussionMessages(discussionId) {
|
|
774
|
+
const db = getDatabase();
|
|
775
|
+
return db.prepare('SELECT * FROM discussion_messages WHERE discussion_id = ? ORDER BY round_number ASC, turn_order ASC').all(discussionId);
|
|
776
|
+
}
|
|
777
|
+
export function getDiscussionMessageById(id) {
|
|
778
|
+
const db = getDatabase();
|
|
779
|
+
return db.prepare('SELECT * FROM discussion_messages WHERE id = ?').get(id);
|
|
780
|
+
}
|
|
781
|
+
export function updateDiscussionMessage(id, updates) {
|
|
782
|
+
const db = getDatabase();
|
|
783
|
+
const fields = [];
|
|
784
|
+
const values = [];
|
|
785
|
+
if (updates.content !== undefined) {
|
|
786
|
+
fields.push('content = ?');
|
|
787
|
+
values.push(updates.content);
|
|
788
|
+
}
|
|
789
|
+
if (updates.status !== undefined) {
|
|
790
|
+
fields.push('status = ?');
|
|
791
|
+
values.push(updates.status);
|
|
792
|
+
}
|
|
793
|
+
if (updates.started_at !== undefined) {
|
|
794
|
+
fields.push('started_at = ?');
|
|
795
|
+
values.push(updates.started_at);
|
|
796
|
+
}
|
|
797
|
+
if (updates.completed_at !== undefined) {
|
|
798
|
+
fields.push('completed_at = ?');
|
|
799
|
+
values.push(updates.completed_at);
|
|
800
|
+
}
|
|
801
|
+
if (fields.length === 0)
|
|
802
|
+
return undefined;
|
|
803
|
+
values.push(id);
|
|
804
|
+
db.prepare(`UPDATE discussion_messages SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
805
|
+
return db.prepare('SELECT * FROM discussion_messages WHERE id = ?').get(id);
|
|
806
|
+
}
|
|
807
|
+
export function createDiscussionLog(discussionId, messageId, logType, message) {
|
|
808
|
+
const db = getDatabase();
|
|
809
|
+
const id = uuidv4();
|
|
810
|
+
const now = new Date().toISOString();
|
|
811
|
+
db.prepare(`INSERT INTO discussion_logs (id, discussion_id, message_id, log_type, message, created_at)
|
|
812
|
+
VALUES (?, ?, ?, ?, ?, ?)`).run(id, discussionId, messageId, logType, message, now);
|
|
813
|
+
return db.prepare('SELECT * FROM discussion_logs WHERE id = ?').get(id);
|
|
814
|
+
}
|
|
815
|
+
export function getDiscussionLogs(discussionId, messageId) {
|
|
816
|
+
const db = getDatabase();
|
|
817
|
+
if (messageId) {
|
|
818
|
+
return db.prepare('SELECT * FROM discussion_logs WHERE discussion_id = ? AND message_id = ? ORDER BY created_at ASC').all(discussionId, messageId);
|
|
819
|
+
}
|
|
820
|
+
return db.prepare('SELECT * FROM discussion_logs WHERE discussion_id = ? ORDER BY created_at ASC').all(discussionId);
|
|
821
|
+
}
|
|
822
|
+
export function deleteDiscussionLogs(discussionId) {
|
|
823
|
+
const db = getDatabase();
|
|
824
|
+
const result = db.prepare('DELETE FROM discussion_logs WHERE discussion_id = ?').run(discussionId);
|
|
825
|
+
return result.changes;
|
|
826
|
+
}
|
|
827
|
+
// ── Cleanup ──
|
|
828
|
+
export function cleanOldLogs(daysToKeep) {
|
|
829
|
+
const db = getDatabase();
|
|
830
|
+
const cutoff = new Date(Date.now() - daysToKeep * 24 * 60 * 60 * 1000).toISOString();
|
|
831
|
+
const taskResult = db.prepare('DELETE FROM task_logs WHERE created_at < ?').run(cutoff);
|
|
832
|
+
const pipelineResult = db.prepare('DELETE FROM pipeline_logs WHERE created_at < ?').run(cutoff);
|
|
833
|
+
const discussionResult = db.prepare('DELETE FROM discussion_logs WHERE created_at < ?').run(cutoff);
|
|
834
|
+
return taskResult.changes + pipelineResult.changes + discussionResult.changes;
|
|
835
|
+
}
|
|
836
|
+
//# sourceMappingURL=queries.js.map
|