@grackle-ai/database 0.73.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 +34 -0
- package/dist/credential-providers.d.ts +41 -0
- package/dist/credential-providers.d.ts.map +1 -0
- package/dist/credential-providers.js +97 -0
- package/dist/credential-providers.js.map +1 -0
- package/dist/crypto.d.ts +5 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +75 -0
- package/dist/crypto.js.map +1 -0
- package/dist/db-seed.d.ts +16 -0
- package/dist/db-seed.d.ts.map +1 -0
- package/dist/db-seed.js +176 -0
- package/dist/db-seed.js.map +1 -0
- package/dist/db.d.ts +43 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +478 -0
- package/dist/db.js.map +1 -0
- package/dist/env-registry.d.ts +29 -0
- package/dist/env-registry.d.ts.map +1 -0
- package/dist/env-registry.js +78 -0
- package/dist/env-registry.js.map +1 -0
- package/dist/event-store.d.ts +19 -0
- package/dist/event-store.d.ts.map +1 -0
- package/dist/event-store.js +16 -0
- package/dist/event-store.js.map +1 -0
- package/dist/finding-store.d.ts +7 -0
- package/dist/finding-store.d.ts.map +1 -0
- package/dist/finding-store.js +45 -0
- package/dist/finding-store.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/json-helpers.d.ts +7 -0
- package/dist/json-helpers.d.ts.map +1 -0
- package/dist/json-helpers.js +22 -0
- package/dist/json-helpers.js.map +1 -0
- package/dist/paths.d.ts +7 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +12 -0
- package/dist/paths.js.map +1 -0
- package/dist/persona-store.d.ts +15 -0
- package/dist/persona-store.d.ts.map +1 -0
- package/dist/persona-store.js +57 -0
- package/dist/persona-store.js.map +1 -0
- package/dist/schema.d.ts +1784 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +152 -0
- package/dist/schema.js.map +1 -0
- package/dist/session-store.d.ts +57 -0
- package/dist/session-store.d.ts.map +1 -0
- package/dist/session-store.js +204 -0
- package/dist/session-store.js.map +1 -0
- package/dist/settings-store.d.ts +14 -0
- package/dist/settings-store.d.ts.map +1 -0
- package/dist/settings-store.js +30 -0
- package/dist/settings-store.js.map +1 -0
- package/dist/task-store.d.ts +71 -0
- package/dist/task-store.d.ts.map +1 -0
- package/dist/task-store.js +301 -0
- package/dist/task-store.js.map +1 -0
- package/dist/test-db.d.ts +13 -0
- package/dist/test-db.d.ts.map +1 -0
- package/dist/test-db.js +14 -0
- package/dist/test-db.js.map +1 -0
- package/dist/token-store.d.ts +25 -0
- package/dist/token-store.d.ts.map +1 -0
- package/dist/token-store.js +58 -0
- package/dist/token-store.js.map +1 -0
- package/dist/utils/slugify.d.ts +20 -0
- package/dist/utils/slugify.d.ts.map +1 -0
- package/dist/utils/slugify.js +22 -0
- package/dist/utils/slugify.js.map +1 -0
- package/dist/workspace-store.d.ts +29 -0
- package/dist/workspace-store.d.ts.map +1 -0
- package/dist/workspace-store.js +74 -0
- package/dist/workspace-store.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import db from "./db.js";
|
|
2
|
+
import { tasks } from "./schema.js";
|
|
3
|
+
import { eq, and, or, sql, asc } from "drizzle-orm";
|
|
4
|
+
import { TASK_STATUS, taskStatusToEnum, taskStatusToString } from "@grackle-ai/common";
|
|
5
|
+
import { MAX_TASK_DEPTH } from "@grackle-ai/common";
|
|
6
|
+
import { safeParseJsonArray } from "./json-helpers.js";
|
|
7
|
+
import { slugify } from "./utils/slugify.js";
|
|
8
|
+
/**
|
|
9
|
+
* Low-level insert — writes a task row with all fields pre-computed.
|
|
10
|
+
* Auto-assigns `sortOrder` based on the workspace's current max.
|
|
11
|
+
* No business logic (parent validation, branch generation, depth limits).
|
|
12
|
+
*/
|
|
13
|
+
export function insertTask(fields) {
|
|
14
|
+
const depsJson = JSON.stringify(fields.dependsOn);
|
|
15
|
+
const sortOrderConditions = [];
|
|
16
|
+
if (fields.workspaceId) {
|
|
17
|
+
sortOrderConditions.push(eq(tasks.workspaceId, fields.workspaceId));
|
|
18
|
+
}
|
|
19
|
+
const maxRowQuery = db
|
|
20
|
+
.select({ maxOrder: sql `max(sort_order)` })
|
|
21
|
+
.from(tasks);
|
|
22
|
+
const maxRow = sortOrderConditions.length > 0
|
|
23
|
+
? maxRowQuery.where(and(...sortOrderConditions)).get()
|
|
24
|
+
: maxRowQuery.get();
|
|
25
|
+
const sortOrder = (maxRow?.maxOrder ?? -1) + 1;
|
|
26
|
+
db.insert(tasks)
|
|
27
|
+
.values({
|
|
28
|
+
id: fields.id,
|
|
29
|
+
workspaceId: fields.workspaceId || null,
|
|
30
|
+
title: fields.title,
|
|
31
|
+
description: fields.description,
|
|
32
|
+
branch: fields.branch,
|
|
33
|
+
dependsOn: depsJson,
|
|
34
|
+
sortOrder,
|
|
35
|
+
parentTaskId: fields.parentTaskId,
|
|
36
|
+
depth: fields.depth,
|
|
37
|
+
canDecompose: fields.canDecompose,
|
|
38
|
+
defaultPersonaId: fields.defaultPersonaId,
|
|
39
|
+
})
|
|
40
|
+
.run();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a task with business logic: validates parent, enforces depth limits,
|
|
44
|
+
* auto-generates branch name, and derives canDecompose.
|
|
45
|
+
* Delegates the actual insert to {@link insertTask}.
|
|
46
|
+
*/
|
|
47
|
+
export function createTask(id, workspaceId, title, description, dependsOn, workspaceSlug, parentTaskId = "", canDecompose, defaultPersonaId = "") {
|
|
48
|
+
let depth = 0;
|
|
49
|
+
let branch;
|
|
50
|
+
if (parentTaskId) {
|
|
51
|
+
const parent = getTask(parentTaskId);
|
|
52
|
+
if (!parent) {
|
|
53
|
+
throw new Error(`Parent task not found: ${parentTaskId}`);
|
|
54
|
+
}
|
|
55
|
+
if (!parent.canDecompose) {
|
|
56
|
+
throw new Error(`Parent task "${parent.title}" (${parentTaskId}) does not have decomposition rights`);
|
|
57
|
+
}
|
|
58
|
+
depth = parent.depth + 1;
|
|
59
|
+
if (depth > MAX_TASK_DEPTH) {
|
|
60
|
+
throw new Error(`Task depth would exceed maximum of ${MAX_TASK_DEPTH}`);
|
|
61
|
+
}
|
|
62
|
+
branch = `${parent.branch}/${slugify(title)}`;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const prefix = workspaceSlug || "task";
|
|
66
|
+
branch = `${prefix}/${slugify(title)}`;
|
|
67
|
+
}
|
|
68
|
+
// Derive canDecompose when not explicitly set: root=true, child=false
|
|
69
|
+
const resolvedCanDecompose = canDecompose ?? !parentTaskId;
|
|
70
|
+
insertTask({
|
|
71
|
+
id,
|
|
72
|
+
workspaceId,
|
|
73
|
+
title,
|
|
74
|
+
description,
|
|
75
|
+
branch,
|
|
76
|
+
dependsOn,
|
|
77
|
+
parentTaskId,
|
|
78
|
+
depth,
|
|
79
|
+
canDecompose: resolvedCanDecompose,
|
|
80
|
+
defaultPersonaId,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/** Retrieve a single task by ID. */
|
|
84
|
+
export function getTask(id) {
|
|
85
|
+
return db.select().from(tasks).where(eq(tasks.id, id)).get();
|
|
86
|
+
}
|
|
87
|
+
/** Escape LIKE special characters so they match literally. */
|
|
88
|
+
function escapeLikePattern(value) {
|
|
89
|
+
return value.replace(/[%_\\]/g, (ch) => `\\${ch}`);
|
|
90
|
+
}
|
|
91
|
+
/** Return tasks for a workspace (or all tasks when workspaceId is omitted), with optional search/status filters, ordered by sort_order then created_at. */
|
|
92
|
+
export function listTasks(workspaceId, options) {
|
|
93
|
+
const conditions = [];
|
|
94
|
+
if (workspaceId) {
|
|
95
|
+
conditions.push(eq(tasks.workspaceId, workspaceId));
|
|
96
|
+
}
|
|
97
|
+
if (options?.status) {
|
|
98
|
+
// Normalize legacy status aliases (e.g. "in_progress" → "working")
|
|
99
|
+
const canonical = taskStatusToString(taskStatusToEnum(options.status));
|
|
100
|
+
if (canonical) {
|
|
101
|
+
conditions.push(eq(tasks.status, canonical));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// Unknown status — match nothing rather than ignoring the filter
|
|
105
|
+
conditions.push(sql `0`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (options?.search) {
|
|
109
|
+
const escaped = escapeLikePattern(options.search);
|
|
110
|
+
const pattern = `%${escaped}%`;
|
|
111
|
+
conditions.push(or(sql `${tasks.title} LIKE ${pattern} ESCAPE '\\'`, sql `${tasks.description} LIKE ${pattern} ESCAPE '\\'`));
|
|
112
|
+
}
|
|
113
|
+
const query = db
|
|
114
|
+
.select()
|
|
115
|
+
.from(tasks);
|
|
116
|
+
const filtered = conditions.length > 0
|
|
117
|
+
? query.where(and(...conditions))
|
|
118
|
+
: query;
|
|
119
|
+
return filtered
|
|
120
|
+
.orderBy(asc(tasks.sortOrder), asc(tasks.createdAt))
|
|
121
|
+
.all();
|
|
122
|
+
}
|
|
123
|
+
/** Update multiple task fields at once. */
|
|
124
|
+
export function updateTask(id, title, description, status, dependsOn, defaultPersonaId) {
|
|
125
|
+
const sets = {
|
|
126
|
+
title,
|
|
127
|
+
description,
|
|
128
|
+
status,
|
|
129
|
+
dependsOn: JSON.stringify(dependsOn),
|
|
130
|
+
updatedAt: sql `datetime('now')`,
|
|
131
|
+
};
|
|
132
|
+
if (defaultPersonaId !== undefined) {
|
|
133
|
+
sets.defaultPersonaId = defaultPersonaId;
|
|
134
|
+
}
|
|
135
|
+
db.update(tasks)
|
|
136
|
+
.set(sets)
|
|
137
|
+
.where(eq(tasks.id, id))
|
|
138
|
+
.run();
|
|
139
|
+
}
|
|
140
|
+
/** Assign a workspace to a task. */
|
|
141
|
+
export function setTaskWorkspace(id, workspaceId) {
|
|
142
|
+
db.update(tasks)
|
|
143
|
+
.set({
|
|
144
|
+
workspaceId,
|
|
145
|
+
updatedAt: sql `datetime('now')`,
|
|
146
|
+
})
|
|
147
|
+
.where(eq(tasks.id, id))
|
|
148
|
+
.run();
|
|
149
|
+
}
|
|
150
|
+
/** Update only the dependsOn array of a task. */
|
|
151
|
+
export function setTaskDependsOn(id, dependsOn) {
|
|
152
|
+
db.update(tasks)
|
|
153
|
+
.set({
|
|
154
|
+
dependsOn: JSON.stringify(dependsOn),
|
|
155
|
+
updatedAt: sql `datetime('now')`,
|
|
156
|
+
})
|
|
157
|
+
.where(eq(tasks.id, id))
|
|
158
|
+
.run();
|
|
159
|
+
}
|
|
160
|
+
/** Update only the task status. */
|
|
161
|
+
export function updateTaskStatus(id, status) {
|
|
162
|
+
db.update(tasks)
|
|
163
|
+
.set({
|
|
164
|
+
status,
|
|
165
|
+
updatedAt: sql `datetime('now')`,
|
|
166
|
+
})
|
|
167
|
+
.where(eq(tasks.id, id))
|
|
168
|
+
.run();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Mark a task as complete with a completed_at timestamp.
|
|
172
|
+
* Used only for human-authoritative status transitions (complete).
|
|
173
|
+
*/
|
|
174
|
+
export function markTaskComplete(id, status = "complete") {
|
|
175
|
+
db.update(tasks)
|
|
176
|
+
.set({
|
|
177
|
+
status,
|
|
178
|
+
completedAt: sql `datetime('now')`,
|
|
179
|
+
updatedAt: sql `datetime('now')`,
|
|
180
|
+
})
|
|
181
|
+
.where(eq(tasks.id, id))
|
|
182
|
+
.run();
|
|
183
|
+
}
|
|
184
|
+
/** Delete a task by ID. Returns the number of rows affected. */
|
|
185
|
+
export function deleteTask(id) {
|
|
186
|
+
const result = db.delete(tasks).where(eq(tasks.id, id)).run();
|
|
187
|
+
return result.changes;
|
|
188
|
+
}
|
|
189
|
+
/** Return all not_started tasks whose dependencies are fully met. */
|
|
190
|
+
export function getUnblockedTasks(workspaceId) {
|
|
191
|
+
const all = listTasks(workspaceId);
|
|
192
|
+
return all.filter((task) => {
|
|
193
|
+
if (task.status !== TASK_STATUS.NOT_STARTED) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
const deps = safeParseJsonArray(task.dependsOn);
|
|
197
|
+
if (deps.length === 0) {
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
return deps.every((depId) => {
|
|
201
|
+
const dep = all.find((t) => t.id === depId);
|
|
202
|
+
return dep?.status === TASK_STATUS.COMPLETE;
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/** Alias for getUnblockedTasks — check which pending tasks are now unblocked. */
|
|
207
|
+
export function checkAndUnblock(workspaceId) {
|
|
208
|
+
return getUnblockedTasks(workspaceId);
|
|
209
|
+
}
|
|
210
|
+
/** Check whether all dependencies of a task are in "complete" status. */
|
|
211
|
+
export function areDependenciesMet(taskId) {
|
|
212
|
+
const task = getTask(taskId);
|
|
213
|
+
if (!task) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
const deps = safeParseJsonArray(task.dependsOn);
|
|
217
|
+
if (deps.length === 0) {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
return deps.every((depId) => {
|
|
221
|
+
const dep = getTask(depId);
|
|
222
|
+
return dep?.status === TASK_STATUS.COMPLETE;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// ─── Tree Queries ────────────────────────────────────
|
|
226
|
+
/** Build a map from parentTaskId to child IDs from a pre-fetched list of rows. Avoids N+1 queries. */
|
|
227
|
+
export function buildChildIdsMap(rows) {
|
|
228
|
+
const map = new Map();
|
|
229
|
+
for (const row of rows) {
|
|
230
|
+
if (row.parentTaskId) {
|
|
231
|
+
const siblings = map.get(row.parentTaskId);
|
|
232
|
+
if (siblings) {
|
|
233
|
+
siblings.push(row.id);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
map.set(row.parentTaskId, [row.id]);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return map;
|
|
241
|
+
}
|
|
242
|
+
/** Get direct children of a task, ordered by sort_order. */
|
|
243
|
+
export function getChildren(taskId) {
|
|
244
|
+
return db
|
|
245
|
+
.select()
|
|
246
|
+
.from(tasks)
|
|
247
|
+
.where(eq(tasks.parentTaskId, taskId))
|
|
248
|
+
.orderBy(asc(tasks.sortOrder), asc(tasks.createdAt))
|
|
249
|
+
.all();
|
|
250
|
+
}
|
|
251
|
+
/** Get all descendants of a task (full subtree) via in-memory BFS. Fetches all workspace tasks once to avoid N+1 queries. */
|
|
252
|
+
export function getDescendants(taskId) {
|
|
253
|
+
const task = getTask(taskId);
|
|
254
|
+
if (!task) {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
const allRows = listTasks(task.workspaceId || undefined);
|
|
258
|
+
const childIdsMap = buildChildIdsMap(allRows);
|
|
259
|
+
const rowById = new Map(allRows.map((r) => [r.id, r]));
|
|
260
|
+
const result = [];
|
|
261
|
+
const queue = [taskId];
|
|
262
|
+
for (let i = 0; i < queue.length; i++) {
|
|
263
|
+
const currentId = queue[i];
|
|
264
|
+
const childIds = childIdsMap.get(currentId);
|
|
265
|
+
if (!childIds) {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
for (const childId of childIds) {
|
|
269
|
+
const child = rowById.get(childId);
|
|
270
|
+
if (child) {
|
|
271
|
+
result.push(child);
|
|
272
|
+
queue.push(child.id);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
/** Get ancestor chain from task up to root, ordered root-first. */
|
|
279
|
+
export function getAncestors(taskId) {
|
|
280
|
+
const ancestors = [];
|
|
281
|
+
let current = getTask(taskId);
|
|
282
|
+
while (current?.parentTaskId) {
|
|
283
|
+
const parent = getTask(current.parentTaskId);
|
|
284
|
+
if (!parent) {
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
ancestors.unshift(parent);
|
|
288
|
+
current = parent;
|
|
289
|
+
}
|
|
290
|
+
return ancestors;
|
|
291
|
+
}
|
|
292
|
+
/** Count children by status for a parent task. */
|
|
293
|
+
export function getChildStatusCounts(taskId) {
|
|
294
|
+
const children = getChildren(taskId);
|
|
295
|
+
const counts = {};
|
|
296
|
+
for (const child of children) {
|
|
297
|
+
counts[child.status] = (counts[child.status] ?? 0) + 1;
|
|
298
|
+
}
|
|
299
|
+
return counts;
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=task-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-store.js","sourceRoot":"","sources":["../src/task-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory SQLite database instance for unit tests.
|
|
3
|
+
* Imported by test files and used via vi.mock to replace the production db module.
|
|
4
|
+
*/
|
|
5
|
+
import Database from "better-sqlite3";
|
|
6
|
+
import * as schema from "./schema.js";
|
|
7
|
+
/** Raw better-sqlite3 instance for DDL operations in tests. */
|
|
8
|
+
export declare const sqlite: InstanceType<typeof Database>;
|
|
9
|
+
/** Drizzle ORM instance wrapping the in-memory database. */
|
|
10
|
+
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
|
|
11
|
+
declare const db: BetterSQLite3Database<typeof schema>;
|
|
12
|
+
export default db;
|
|
13
|
+
//# sourceMappingURL=test-db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-db.d.ts","sourceRoot":"","sources":["../src/test-db.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,+DAA+D;AAC/D,eAAO,MAAM,MAAM,EAAE,YAAY,CAAC,OAAO,QAAQ,CAA4B,CAAC;AAI9E,4DAA4D;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,QAAA,MAAM,EAAE,EAAE,qBAAqB,CAAC,OAAO,MAAM,CAA+B,CAAC;AAC7E,eAAe,EAAE,CAAC"}
|
package/dist/test-db.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory SQLite database instance for unit tests.
|
|
3
|
+
* Imported by test files and used via vi.mock to replace the production db module.
|
|
4
|
+
*/
|
|
5
|
+
import Database from "better-sqlite3";
|
|
6
|
+
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
7
|
+
import * as schema from "./schema.js";
|
|
8
|
+
/** Raw better-sqlite3 instance for DDL operations in tests. */
|
|
9
|
+
export const sqlite = new Database(":memory:");
|
|
10
|
+
sqlite.pragma("journal_mode = WAL");
|
|
11
|
+
sqlite.pragma("foreign_keys = ON");
|
|
12
|
+
const db = drizzle(sqlite, { schema });
|
|
13
|
+
export default db;
|
|
14
|
+
//# sourceMappingURL=test-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-db.js","sourceRoot":"","sources":["../src/test-db.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,MAAM,GAAkC,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC9E,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAInC,MAAM,EAAE,GAAyC,OAAO,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAC7E,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { powerline } from "@grackle-ai/common";
|
|
2
|
+
/** Shape of a token's stored configuration. */
|
|
3
|
+
export interface TokenConfig {
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
envVar?: string;
|
|
7
|
+
filePath?: string;
|
|
8
|
+
value: string;
|
|
9
|
+
expiresAt?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Encrypt and store (or update) a token. */
|
|
12
|
+
export declare function setToken(entry: TokenConfig): void;
|
|
13
|
+
/** Delete a token by name. */
|
|
14
|
+
export declare function deleteToken(name: string): void;
|
|
15
|
+
/** List all stored tokens (values are omitted for security). */
|
|
16
|
+
export declare function listTokens(): Array<{
|
|
17
|
+
name: string;
|
|
18
|
+
type: string;
|
|
19
|
+
envVar?: string;
|
|
20
|
+
filePath?: string;
|
|
21
|
+
expiresAt?: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** Build a decrypted token bundle suitable for pushing to a PowerLine. */
|
|
24
|
+
export declare function getBundle(): powerline.TokenBundle;
|
|
25
|
+
//# sourceMappingURL=token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store.d.ts","sourceRoot":"","sources":["../src/token-store.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,+CAA+C;AAC/C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,6CAA6C;AAC7C,wBAAgB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAYjD;AAED,8BAA8B;AAC9B,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED,gEAAgE;AAChE,wBAAgB,UAAU,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAY1H;AAED,0EAA0E;AAC1E,wBAAgB,SAAS,IAAI,SAAS,CAAC,WAAW,CAcjD"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure persistence layer for encrypted token storage.
|
|
3
|
+
* No network operations — see {@link ./token-push.ts} for push orchestration.
|
|
4
|
+
*/
|
|
5
|
+
import { eq } from "drizzle-orm";
|
|
6
|
+
import db from "./db.js";
|
|
7
|
+
import { tokens } from "./schema.js";
|
|
8
|
+
import { encrypt, decrypt } from "./crypto.js";
|
|
9
|
+
import { create } from "@bufbuild/protobuf";
|
|
10
|
+
import { powerline } from "@grackle-ai/common";
|
|
11
|
+
/** Encrypt and store (or update) a token. */
|
|
12
|
+
export function setToken(entry) {
|
|
13
|
+
const encrypted = {
|
|
14
|
+
...entry,
|
|
15
|
+
value: encrypt(entry.value),
|
|
16
|
+
};
|
|
17
|
+
db.insert(tokens)
|
|
18
|
+
.values({ id: entry.name, config: JSON.stringify(encrypted) })
|
|
19
|
+
.onConflictDoUpdate({
|
|
20
|
+
target: tokens.id,
|
|
21
|
+
set: { config: JSON.stringify(encrypted) },
|
|
22
|
+
})
|
|
23
|
+
.run();
|
|
24
|
+
}
|
|
25
|
+
/** Delete a token by name. */
|
|
26
|
+
export function deleteToken(name) {
|
|
27
|
+
db.delete(tokens).where(eq(tokens.id, name)).run();
|
|
28
|
+
}
|
|
29
|
+
/** List all stored tokens (values are omitted for security). */
|
|
30
|
+
export function listTokens() {
|
|
31
|
+
const rows = db.select().from(tokens).all();
|
|
32
|
+
return rows.map((row) => {
|
|
33
|
+
const cfg = JSON.parse(row.config);
|
|
34
|
+
return {
|
|
35
|
+
name: cfg.name,
|
|
36
|
+
type: cfg.type,
|
|
37
|
+
envVar: cfg.envVar,
|
|
38
|
+
filePath: cfg.filePath,
|
|
39
|
+
expiresAt: cfg.expiresAt,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** Build a decrypted token bundle suitable for pushing to a PowerLine. */
|
|
44
|
+
export function getBundle() {
|
|
45
|
+
const rows = db.select().from(tokens).all();
|
|
46
|
+
const items = rows.map((row) => {
|
|
47
|
+
const cfg = JSON.parse(row.config);
|
|
48
|
+
return create(powerline.TokenItemSchema, {
|
|
49
|
+
name: cfg.name,
|
|
50
|
+
type: cfg.type,
|
|
51
|
+
envVar: cfg.envVar || "",
|
|
52
|
+
filePath: cfg.filePath || "",
|
|
53
|
+
value: decrypt(cfg.value),
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
return create(powerline.TokenBundleSchema, { tokens: items });
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../src/token-store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAY/C,6CAA6C;AAC7C,MAAM,UAAU,QAAQ,CAAC,KAAkB;IACzC,MAAM,SAAS,GAAgB;QAC7B,GAAG,KAAK;QACR,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;KAC5B,CAAC;IACF,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;SACd,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;SAC7D,kBAAkB,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC,EAAE;QACjB,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;KAC3C,CAAC;SACD,GAAG,EAAE,CAAC;AACX,CAAC;AAED,8BAA8B;AAC9B,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AACrD,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,UAAU;IACxB,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;IAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAa,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAgB,CAAC;QAClD,OAAO;YACL,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,SAAS,EAAE,GAAG,CAAC,SAAS;SACzB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,SAAS;IACvB,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAa,EAAE,EAAE;QACvC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAgB,CAAC;QAClD,OAAO,MAAM,CAAC,SAAS,CAAC,eAAe,EAAE;YACvC,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;YACxB,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,SAAS,CAAC,iBAAiB,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts arbitrary text into a URL-safe slug.
|
|
3
|
+
*
|
|
4
|
+
* The conversion process:
|
|
5
|
+
* 1. Lowercases the entire string.
|
|
6
|
+
* 2. Replaces any sequence of non-alphanumeric characters with a single hyphen.
|
|
7
|
+
* 3. Strips leading and trailing hyphens.
|
|
8
|
+
* 4. Truncates the result to a maximum of 40 characters.
|
|
9
|
+
*
|
|
10
|
+
* @param text - The input string to slugify (e.g. a task title or workspace name).
|
|
11
|
+
* @returns A lowercase, hyphen-separated, URL-safe string of at most 40 characters.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* slugify("Hello World!") // "hello-world"
|
|
15
|
+
* slugify(" My New Task ") // "my-new-task"
|
|
16
|
+
* slugify("A very long title that exceeds the forty character limit")
|
|
17
|
+
* // "a-very-long-title-that-exceeds-the-forty"
|
|
18
|
+
*/
|
|
19
|
+
export declare function slugify(text: string): string;
|
|
20
|
+
//# sourceMappingURL=slugify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slugify.d.ts","sourceRoot":"","sources":["../../src/utils/slugify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts arbitrary text into a URL-safe slug.
|
|
3
|
+
*
|
|
4
|
+
* The conversion process:
|
|
5
|
+
* 1. Lowercases the entire string.
|
|
6
|
+
* 2. Replaces any sequence of non-alphanumeric characters with a single hyphen.
|
|
7
|
+
* 3. Strips leading and trailing hyphens.
|
|
8
|
+
* 4. Truncates the result to a maximum of 40 characters.
|
|
9
|
+
*
|
|
10
|
+
* @param text - The input string to slugify (e.g. a task title or workspace name).
|
|
11
|
+
* @returns A lowercase, hyphen-separated, URL-safe string of at most 40 characters.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* slugify("Hello World!") // "hello-world"
|
|
15
|
+
* slugify(" My New Task ") // "my-new-task"
|
|
16
|
+
* slugify("A very long title that exceeds the forty character limit")
|
|
17
|
+
* // "a-very-long-title-that-exceeds-the-forty"
|
|
18
|
+
*/
|
|
19
|
+
export function slugify(text) {
|
|
20
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 40);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=slugify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slugify.js","sourceRoot":"","sources":["../../src/utils/slugify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type WorkspaceRow } from "./schema.js";
|
|
2
|
+
export type { WorkspaceRow };
|
|
3
|
+
/** Insert a new workspace record. */
|
|
4
|
+
export declare function createWorkspace(id: string, name: string, description: string, repoUrl: string, environmentId: string, useWorktrees?: boolean, worktreeBasePath?: string, defaultPersonaId?: string): void;
|
|
5
|
+
/** Retrieve a single workspace by ID. */
|
|
6
|
+
export declare function getWorkspace(id: string): WorkspaceRow | undefined;
|
|
7
|
+
/** Return all active workspaces, newest first. Optionally filter by environment. */
|
|
8
|
+
export declare function listWorkspaces(environmentId?: string): WorkspaceRow[];
|
|
9
|
+
/** Count all workspaces (active and archived) belonging to an environment. */
|
|
10
|
+
export declare function countWorkspacesByEnvironment(environmentId: string): number;
|
|
11
|
+
/** Mark a workspace as archived. */
|
|
12
|
+
export declare function archiveWorkspace(id: string): void;
|
|
13
|
+
/** Partial-update fields for a workspace. Undefined means "no change"; empty string means "clear". */
|
|
14
|
+
export interface UpdateWorkspaceFields {
|
|
15
|
+
name?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
repoUrl?: string;
|
|
18
|
+
/** Reparent workspace to a different environment. */
|
|
19
|
+
environmentId?: string;
|
|
20
|
+
/** When false, agents work directly in the main checkout instead of creating a worktree. */
|
|
21
|
+
useWorktrees?: boolean;
|
|
22
|
+
/** Custom base path for worktrees (e.g. /workspaces/my-repo). Empty means use default. */
|
|
23
|
+
worktreeBasePath?: string;
|
|
24
|
+
/** Default persona for tasks in this workspace. */
|
|
25
|
+
defaultPersonaId?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Update one or more fields on an existing workspace. Returns the updated row, or undefined if not found. */
|
|
28
|
+
export declare function updateWorkspace(id: string, fields: UpdateWorkspaceFields): WorkspaceRow | undefined;
|
|
29
|
+
//# sourceMappingURL=workspace-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-store.d.ts","sourceRoot":"","sources":["../src/workspace-store.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAG5D,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,qCAAqC;AACrC,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,EACrB,YAAY,GAAE,OAAc,EAC5B,gBAAgB,GAAE,MAAW,EAC7B,gBAAgB,GAAE,MAAW,GAC5B,IAAI,CAWN;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEjE;AAED,oFAAoF;AACpF,wBAAgB,cAAc,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE,CASrE;AAED,8EAA8E;AAC9E,wBAAgB,4BAA4B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAM1E;AAED,oCAAoC;AACpC,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAKjD;AAED,sGAAsG;AACtG,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4FAA4F;IAC5F,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,8GAA8G;AAC9G,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,YAAY,GAAG,SAAS,CAyBnG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import db from "./db.js";
|
|
2
|
+
import { workspaces } from "./schema.js";
|
|
3
|
+
import { eq, and, desc, sql } from "drizzle-orm";
|
|
4
|
+
/** Insert a new workspace record. */
|
|
5
|
+
export function createWorkspace(id, name, description, repoUrl, environmentId, useWorktrees = true, worktreeBasePath = "", defaultPersonaId = "") {
|
|
6
|
+
db.insert(workspaces).values({
|
|
7
|
+
id,
|
|
8
|
+
name,
|
|
9
|
+
description,
|
|
10
|
+
repoUrl,
|
|
11
|
+
environmentId,
|
|
12
|
+
useWorktrees,
|
|
13
|
+
worktreeBasePath: worktreeBasePath.trim(),
|
|
14
|
+
defaultPersonaId,
|
|
15
|
+
}).run();
|
|
16
|
+
}
|
|
17
|
+
/** Retrieve a single workspace by ID. */
|
|
18
|
+
export function getWorkspace(id) {
|
|
19
|
+
return db.select().from(workspaces).where(eq(workspaces.id, id)).get();
|
|
20
|
+
}
|
|
21
|
+
/** Return all active workspaces, newest first. Optionally filter by environment. */
|
|
22
|
+
export function listWorkspaces(environmentId) {
|
|
23
|
+
const conditions = [eq(workspaces.status, "active")];
|
|
24
|
+
if (environmentId) {
|
|
25
|
+
conditions.push(eq(workspaces.environmentId, environmentId));
|
|
26
|
+
}
|
|
27
|
+
return db.select().from(workspaces)
|
|
28
|
+
.where(and(...conditions))
|
|
29
|
+
.orderBy(desc(workspaces.createdAt))
|
|
30
|
+
.all();
|
|
31
|
+
}
|
|
32
|
+
/** Count all workspaces (active and archived) belonging to an environment. */
|
|
33
|
+
export function countWorkspacesByEnvironment(environmentId) {
|
|
34
|
+
const row = db.select({ count: sql `count(*)` })
|
|
35
|
+
.from(workspaces)
|
|
36
|
+
.where(eq(workspaces.environmentId, environmentId))
|
|
37
|
+
.get();
|
|
38
|
+
return row?.count ?? 0;
|
|
39
|
+
}
|
|
40
|
+
/** Mark a workspace as archived. */
|
|
41
|
+
export function archiveWorkspace(id) {
|
|
42
|
+
db.update(workspaces)
|
|
43
|
+
.set({ status: "archived", updatedAt: sql `datetime('now')` })
|
|
44
|
+
.where(eq(workspaces.id, id))
|
|
45
|
+
.run();
|
|
46
|
+
}
|
|
47
|
+
/** Update one or more fields on an existing workspace. Returns the updated row, or undefined if not found. */
|
|
48
|
+
export function updateWorkspace(id, fields) {
|
|
49
|
+
const sets = { updatedAt: sql `datetime('now')` };
|
|
50
|
+
if (fields.name !== undefined) {
|
|
51
|
+
sets.name = fields.name;
|
|
52
|
+
}
|
|
53
|
+
if (fields.description !== undefined) {
|
|
54
|
+
sets.description = fields.description;
|
|
55
|
+
}
|
|
56
|
+
if (fields.repoUrl !== undefined) {
|
|
57
|
+
sets.repoUrl = fields.repoUrl;
|
|
58
|
+
}
|
|
59
|
+
if (fields.environmentId !== undefined) {
|
|
60
|
+
sets.environmentId = fields.environmentId;
|
|
61
|
+
}
|
|
62
|
+
if (fields.useWorktrees !== undefined) {
|
|
63
|
+
sets.useWorktrees = fields.useWorktrees;
|
|
64
|
+
}
|
|
65
|
+
if (fields.worktreeBasePath !== undefined) {
|
|
66
|
+
sets.worktreeBasePath = fields.worktreeBasePath.trim();
|
|
67
|
+
}
|
|
68
|
+
if (fields.defaultPersonaId !== undefined) {
|
|
69
|
+
sets.defaultPersonaId = fields.defaultPersonaId;
|
|
70
|
+
}
|
|
71
|
+
db.update(workspaces).set(sets).where(eq(workspaces.id, id)).run();
|
|
72
|
+
return getWorkspace(id);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=workspace-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-store.js","sourceRoot":"","sources":["../src/workspace-store.ts"],"names":[],"mappings":"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"}
|