botnote 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +277 -0
  2. package/dist/bin.d.ts +2 -0
  3. package/dist/bin.js +320 -0
  4. package/dist/bin.js.map +1 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +61 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/db/client.d.ts +10 -0
  9. package/dist/db/client.js +16 -0
  10. package/dist/db/client.js.map +1 -0
  11. package/dist/db/migrate.d.ts +1 -0
  12. package/dist/db/migrate.js +57 -0
  13. package/dist/db/migrate.js.map +1 -0
  14. package/dist/db/migrations/0001_init.sql +89 -0
  15. package/dist/db/migrations/0002_tasks_due_at.sql +16 -0
  16. package/dist/db/migrations/0003_task_priority_and_sequence.sql +45 -0
  17. package/dist/db/migrations/0004_pinned.sql +8 -0
  18. package/dist/db/migrations/0005_nullable_title_and_parent.sql +5 -0
  19. package/dist/db/migrations/0006_project_color_icon.sql +3 -0
  20. package/dist/db/migrations/0007_tokens.sql +14 -0
  21. package/dist/db/migrations/0008_simplify_kinds_drop_actors.sql +21 -0
  22. package/dist/db/migrations/0009_sessions.sql +14 -0
  23. package/dist/db/migrations/0010_completed_at.sql +17 -0
  24. package/dist/db/migrations/0011_completed_at_backfill_fix.sql +14 -0
  25. package/dist/db/migrations/0012_completed_at_backfill_due.sql +16 -0
  26. package/dist/db/migrations/0013_due_at_noon_utc.sql +13 -0
  27. package/dist/db/schema.d.ts +811 -0
  28. package/dist/db/schema.js +112 -0
  29. package/dist/db/schema.js.map +1 -0
  30. package/dist/mcp/http-client.d.ts +154 -0
  31. package/dist/mcp/http-client.js +113 -0
  32. package/dist/mcp/http-client.js.map +1 -0
  33. package/dist/mcp/server.d.ts +7 -0
  34. package/dist/mcp/server.js +492 -0
  35. package/dist/mcp/server.js.map +1 -0
  36. package/dist/rest/routes.d.ts +3 -0
  37. package/dist/rest/routes.js +320 -0
  38. package/dist/rest/routes.js.map +1 -0
  39. package/dist/rest/server.d.ts +12 -0
  40. package/dist/rest/server.js +282 -0
  41. package/dist/rest/server.js.map +1 -0
  42. package/dist/service/embedding.d.ts +25 -0
  43. package/dist/service/embedding.js +112 -0
  44. package/dist/service/embedding.js.map +1 -0
  45. package/dist/service/entities.d.ts +22 -0
  46. package/dist/service/entities.js +174 -0
  47. package/dist/service/entities.js.map +1 -0
  48. package/dist/service/index.d.ts +8 -0
  49. package/dist/service/index.js +8 -0
  50. package/dist/service/index.js.map +1 -0
  51. package/dist/service/opening_brief.d.ts +14 -0
  52. package/dist/service/opening_brief.js +104 -0
  53. package/dist/service/opening_brief.js.map +1 -0
  54. package/dist/service/projects.d.ts +8 -0
  55. package/dist/service/projects.js +36 -0
  56. package/dist/service/projects.js.map +1 -0
  57. package/dist/service/search.d.ts +15 -0
  58. package/dist/service/search.js +101 -0
  59. package/dist/service/search.js.map +1 -0
  60. package/dist/service/sessions.d.ts +25 -0
  61. package/dist/service/sessions.js +89 -0
  62. package/dist/service/sessions.js.map +1 -0
  63. package/dist/service/tasks.d.ts +23 -0
  64. package/dist/service/tasks.js +130 -0
  65. package/dist/service/tasks.js.map +1 -0
  66. package/dist/service/tokens.d.ts +18 -0
  67. package/dist/service/tokens.js +41 -0
  68. package/dist/service/tokens.js.map +1 -0
  69. package/dist/service/types.d.ts +294 -0
  70. package/dist/service/types.js +132 -0
  71. package/dist/service/types.js.map +1 -0
  72. package/dist/version.d.ts +1 -0
  73. package/dist/version.js +13 -0
  74. package/dist/version.js.map +1 -0
  75. package/package.json +73 -0
  76. package/web/dist/assets/index-Bddg7h_x.css +1 -0
  77. package/web/dist/assets/index-DYW6stVx.js +542 -0
  78. package/web/dist/favicon.svg +13 -0
  79. package/web/dist/index.html +17 -0
@@ -0,0 +1,25 @@
1
+ import type { Database } from "../db/client.js";
2
+ export declare const EMBED_MODEL = "text-embedding-3-small";
3
+ export declare const EMBED_DIM = 384;
4
+ export interface EmbedFn {
5
+ (text: string): Promise<number[]>;
6
+ }
7
+ export declare class EmbeddingService {
8
+ private db;
9
+ private embedFn;
10
+ private queue;
11
+ private working;
12
+ constructor(db: Database["db"], opts?: {
13
+ apiKey?: string | undefined;
14
+ embedFn?: EmbedFn;
15
+ logger?: (msg: string) => void;
16
+ });
17
+ private log;
18
+ isEnabled(): boolean;
19
+ enqueue(id: string, text: string): void;
20
+ embedQuery(text: string): Promise<number[] | null>;
21
+ drain(timeoutMs?: number): Promise<void>;
22
+ pendingCount(): number;
23
+ private tick;
24
+ private process;
25
+ }
@@ -0,0 +1,112 @@
1
+ import OpenAI from "openai";
2
+ import { setBodyVec } from "./entities.js";
3
+ export const EMBED_MODEL = "text-embedding-3-small";
4
+ export const EMBED_DIM = 384;
5
+ export class EmbeddingService {
6
+ db;
7
+ embedFn;
8
+ queue = [];
9
+ working = false;
10
+ constructor(db, opts = {}) {
11
+ this.db = db;
12
+ if (opts.embedFn) {
13
+ this.embedFn = opts.embedFn;
14
+ }
15
+ else if (opts.apiKey) {
16
+ const client = new OpenAI({ apiKey: opts.apiKey });
17
+ this.embedFn = async (text) => {
18
+ const res = await client.embeddings.create({
19
+ model: EMBED_MODEL,
20
+ input: text,
21
+ dimensions: EMBED_DIM
22
+ });
23
+ const vec = res.data[0]?.embedding;
24
+ if (!vec)
25
+ throw new Error("openai returned no embedding");
26
+ return vec;
27
+ };
28
+ }
29
+ else {
30
+ this.embedFn = null;
31
+ }
32
+ this.log = opts.logger ?? ((msg) => console.log(`[embed] ${msg}`));
33
+ }
34
+ log;
35
+ isEnabled() {
36
+ return this.embedFn != null;
37
+ }
38
+ enqueue(id, text) {
39
+ if (!this.embedFn)
40
+ return;
41
+ if (!text.trim())
42
+ return;
43
+ this.queue.push({ id, text, attempts: 0 });
44
+ this.tick();
45
+ }
46
+ async embedQuery(text) {
47
+ if (!this.embedFn)
48
+ return null;
49
+ if (!text.trim())
50
+ return null;
51
+ try {
52
+ return await this.embedFn(text);
53
+ }
54
+ catch (err) {
55
+ this.log(`query embed failed: ${err}`);
56
+ return null;
57
+ }
58
+ }
59
+ async drain(timeoutMs = 30000) {
60
+ const start = Date.now();
61
+ while (this.queue.length > 0 || this.working) {
62
+ if (Date.now() - start > timeoutMs) {
63
+ throw new Error(`drain timeout after ${timeoutMs}ms; ${this.queue.length} jobs pending`);
64
+ }
65
+ await new Promise((r) => setTimeout(r, 20));
66
+ }
67
+ }
68
+ pendingCount() {
69
+ return this.queue.length + (this.working ? 1 : 0);
70
+ }
71
+ tick() {
72
+ if (this.working)
73
+ return;
74
+ if (this.queue.length === 0)
75
+ return;
76
+ this.working = true;
77
+ this.process()
78
+ .catch((e) => this.log(`worker crashed: ${e}`))
79
+ .finally(() => {
80
+ this.working = false;
81
+ if (this.queue.length > 0)
82
+ setImmediate(() => this.tick());
83
+ });
84
+ }
85
+ async process() {
86
+ const embedFn = this.embedFn;
87
+ if (!embedFn)
88
+ return;
89
+ while (this.queue.length > 0) {
90
+ const job = this.queue.shift();
91
+ if (!job)
92
+ break;
93
+ try {
94
+ const vec = await embedFn(job.text);
95
+ await setBodyVec(this.db, job.id, vec);
96
+ }
97
+ catch (err) {
98
+ job.attempts += 1;
99
+ if (job.attempts >= 3) {
100
+ this.log(`failed permanently for ${job.id}: ${err}`);
101
+ }
102
+ else {
103
+ this.log(`retry ${job.attempts}/3 for ${job.id}: ${err}`);
104
+ const backoff = 200 * 2 ** job.attempts;
105
+ await new Promise((r) => setTimeout(r, backoff));
106
+ this.queue.push(job);
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ //# sourceMappingURL=embedding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding.js","sourceRoot":"","sources":["../../src/service/embedding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { Database } from "../db/client.js";
2
+ import { type Entity } from "../db/schema.js";
3
+ import type { LinkInput, RecentInput, UpdateInput, WriteInput } from "./types.js";
4
+ export declare function write(db: Database["db"], input: WriteInput): Promise<Entity>;
5
+ export declare function update(db: Database["db"], id: string, fields: UpdateInput): Promise<Entity>;
6
+ export declare function listRelated(db: Database["db"], parentId: string): Promise<Entity[]>;
7
+ export declare function get(db: Database["db"], id: string): Promise<Entity | null>;
8
+ /**
9
+ * Look up an entity by its human-readable identifier — e.g. project key `BOT`
10
+ * + sequence id `12` resolves to the entity displayed as `BOT-12`.
11
+ */
12
+ export declare function getByKey(db: Database["db"], projectKey: string, sequenceId: number): Promise<Entity | null>;
13
+ export declare function remove(db: Database["db"], id: string): Promise<boolean>;
14
+ export declare function recent(db: Database["db"], input: RecentInput): Promise<Entity[]>;
15
+ export declare function link(db: Database["db"], input: LinkInput): Promise<{
16
+ fromId: string;
17
+ toId: string;
18
+ kind: string;
19
+ created: boolean;
20
+ }>;
21
+ export declare function listChildren(db: Database["db"], parentId: string): Promise<Entity[]>;
22
+ export declare function setBodyVec(db: Database["db"], id: string, vec: number[]): Promise<void>;
@@ -0,0 +1,174 @@
1
+ import { and, desc, eq, gte, inArray, isNull, sql } from "drizzle-orm";
2
+ import { edges, entities, projects } from "../db/schema.js";
3
+ /**
4
+ * Snap an exact-midnight-UTC due date to noon UTC. Date-only intents (e.g.
5
+ * "due 2026-06-03") arriving as `2026-06-03T00:00:00Z` would render as the
6
+ * previous calendar day in any UTC-negative timezone. Noon UTC stays on the
7
+ * intended day across UTC-12..UTC+11. Anything with a non-zero time
8
+ * component is left alone — that's a real datetime, not a calendar date.
9
+ */
10
+ function normalizeDueAt(value) {
11
+ if (value == null)
12
+ return null;
13
+ if (value.getUTCHours() === 0 &&
14
+ value.getUTCMinutes() === 0 &&
15
+ value.getUTCSeconds() === 0 &&
16
+ value.getUTCMilliseconds() === 0) {
17
+ const noon = new Date(value);
18
+ noon.setUTCHours(12);
19
+ return noon;
20
+ }
21
+ return value;
22
+ }
23
+ export async function write(db, input) {
24
+ if (input.idempotencyKey) {
25
+ const existing = await db
26
+ .select()
27
+ .from(entities)
28
+ .where(eq(entities.idempotencyKey, input.idempotencyKey))
29
+ .limit(1);
30
+ if (existing.length > 0)
31
+ return existing[0];
32
+ }
33
+ const [row] = await db
34
+ .insert(entities)
35
+ .values({
36
+ kind: input.kind,
37
+ projectId: input.projectId ?? null,
38
+ title: input.title ?? null,
39
+ body: input.body,
40
+ tags: input.tags,
41
+ status: input.status,
42
+ parentId: input.parentId ?? null,
43
+ actorKind: input.actorKind,
44
+ metadata: input.metadata,
45
+ dueAt: normalizeDueAt(input.dueAt),
46
+ priority: input.priority,
47
+ pinned: input.pinned,
48
+ // Mirror the PATCH path: a task created already-done gets a
49
+ // completedAt stamp so the calendar renders it on the right day.
50
+ completedAt: input.status === "done" ? new Date() : null,
51
+ idempotencyKey: input.idempotencyKey ?? null
52
+ })
53
+ .returning();
54
+ if (!row)
55
+ throw new Error("entities insert returned no row");
56
+ if (input.parentId) {
57
+ await db
58
+ .insert(edges)
59
+ .values({ fromId: input.parentId, toId: row.id, kind: "parent_of" })
60
+ .onConflictDoNothing();
61
+ }
62
+ return row;
63
+ }
64
+ export async function update(db, id, fields) {
65
+ const set = { ...fields, updatedAt: new Date() };
66
+ if (fields.dueAt !== undefined) {
67
+ set.dueAt = normalizeDueAt(fields.dueAt);
68
+ }
69
+ // Maintain completedAt as a side effect of status transitions. We need the
70
+ // prior status to know whether this is an entry into or exit from 'done',
71
+ // so do a tiny read first — cheaper than a CASE expression on UPDATE and
72
+ // keeps the SQL the same shape as other writes.
73
+ if (fields.status !== undefined) {
74
+ const prior = await db
75
+ .select({ status: entities.status })
76
+ .from(entities)
77
+ .where(eq(entities.id, id))
78
+ .limit(1);
79
+ if (!prior[0])
80
+ throw new Error(`entity ${id} not found`);
81
+ const wasDone = prior[0].status === "done";
82
+ const isDone = fields.status === "done";
83
+ if (isDone && !wasDone)
84
+ set.completedAt = new Date();
85
+ else if (!isDone && wasDone)
86
+ set.completedAt = null;
87
+ }
88
+ const [row] = await db.update(entities).set(set).where(eq(entities.id, id)).returning();
89
+ if (!row)
90
+ throw new Error(`entity ${id} not found`);
91
+ if (fields.parentId !== undefined && fields.parentId !== null) {
92
+ await db
93
+ .insert(edges)
94
+ .values({ fromId: fields.parentId, toId: row.id, kind: "parent_of" })
95
+ .onConflictDoNothing();
96
+ }
97
+ return row;
98
+ }
99
+ export async function listRelated(db, parentId) {
100
+ return db
101
+ .select()
102
+ .from(entities)
103
+ .where(eq(entities.parentId, parentId))
104
+ .orderBy(desc(entities.createdAt));
105
+ }
106
+ export async function get(db, id) {
107
+ const rows = await db.select().from(entities).where(eq(entities.id, id)).limit(1);
108
+ return rows[0] ?? null;
109
+ }
110
+ /**
111
+ * Look up an entity by its human-readable identifier — e.g. project key `BOT`
112
+ * + sequence id `12` resolves to the entity displayed as `BOT-12`.
113
+ */
114
+ export async function getByKey(db, projectKey, sequenceId) {
115
+ const rows = await db
116
+ .select({ e: entities })
117
+ .from(entities)
118
+ .innerJoin(projects, eq(entities.projectId, projects.id))
119
+ .where(and(eq(projects.key, projectKey), eq(entities.sequenceId, sequenceId)))
120
+ .limit(1);
121
+ return rows[0]?.e ?? null;
122
+ }
123
+ export async function remove(db, id) {
124
+ const res = await db.delete(entities).where(eq(entities.id, id)).returning({ id: entities.id });
125
+ return res.length > 0;
126
+ }
127
+ export async function recent(db, input) {
128
+ const conds = [];
129
+ if (input.projectId)
130
+ conds.push(eq(entities.projectId, input.projectId));
131
+ else if (input.projectId === null)
132
+ conds.push(isNull(entities.projectId));
133
+ if (input.since)
134
+ conds.push(gte(entities.createdAt, input.since));
135
+ if (input.kinds?.length)
136
+ conds.push(inArray(entities.kind, input.kinds));
137
+ const where = conds.length ? and(...conds) : undefined;
138
+ return db
139
+ .select()
140
+ .from(entities)
141
+ .where(where)
142
+ .orderBy(desc(entities.createdAt))
143
+ .limit(input.limit);
144
+ }
145
+ export async function link(db, input) {
146
+ const result = await db
147
+ .insert(edges)
148
+ .values({ fromId: input.fromId, toId: input.toId, kind: input.kind })
149
+ .onConflictDoNothing()
150
+ .returning();
151
+ return {
152
+ fromId: input.fromId,
153
+ toId: input.toId,
154
+ kind: input.kind,
155
+ created: result.length > 0
156
+ };
157
+ }
158
+ export async function listChildren(db, parentId) {
159
+ const childIds = await db
160
+ .select({ toId: edges.toId })
161
+ .from(edges)
162
+ .where(and(eq(edges.fromId, parentId), eq(edges.kind, "parent_of")));
163
+ if (childIds.length === 0)
164
+ return [];
165
+ return db
166
+ .select()
167
+ .from(entities)
168
+ .where(inArray(entities.id, childIds.map((c) => c.toId)))
169
+ .orderBy(desc(entities.createdAt));
170
+ }
171
+ export async function setBodyVec(db, id, vec) {
172
+ await db.execute(sql `UPDATE entities SET body_vec = ${`[${vec.join(",")}]`}::vector WHERE id = ${id}`);
173
+ }
174
+ //# sourceMappingURL=entities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entities.js","sourceRoot":"","sources":["../../src/service/entities.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export * from "./types.js";
2
+ export * as entityService from "./entities.js";
3
+ export * as projectService from "./projects.js";
4
+ export * as searchService from "./search.js";
5
+ export * as briefService from "./opening_brief.js";
6
+ export * as tasksService from "./tasks.js";
7
+ export { EmbeddingService, EMBED_DIM, EMBED_MODEL } from "./embedding.js";
8
+ export type { EmbedFn } from "./embedding.js";
@@ -0,0 +1,8 @@
1
+ export * from "./types.js";
2
+ export * as entityService from "./entities.js";
3
+ export * as projectService from "./projects.js";
4
+ export * as searchService from "./search.js";
5
+ export * as briefService from "./opening_brief.js";
6
+ export * as tasksService from "./tasks.js";
7
+ export { EmbeddingService, EMBED_DIM, EMBED_MODEL } from "./embedding.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/service/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,KAAK,aAAa,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,cAAc,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,aAAa,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,YAAY,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,YAAY,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Database } from "../db/client.js";
2
+ import { type Entity, type Project } from "../db/schema.js";
3
+ import type { OpeningBriefInput } from "./types.js";
4
+ export interface OpeningBrief {
5
+ project: Project | null;
6
+ agentsMd: string;
7
+ pinnedNotes: Entity[];
8
+ openTasks: Entity[];
9
+ pendingDecisions: Entity[];
10
+ recent: Entity[];
11
+ generatedAt: Date;
12
+ }
13
+ export declare function openingBrief(db: Database["db"], input: OpeningBriefInput): Promise<OpeningBrief>;
14
+ export declare function formatOpeningBrief(brief: OpeningBrief): string;
@@ -0,0 +1,104 @@
1
+ import { and, desc, eq, isNull, ne } from "drizzle-orm";
2
+ import { entities } from "../db/schema.js";
3
+ import { getProject } from "./projects.js";
4
+ export async function openingBrief(db, input) {
5
+ const project = input.projectId ? await getProject(db, input.projectId) : null;
6
+ const projectFilter = input.projectId
7
+ ? eq(entities.projectId, input.projectId)
8
+ : isNull(entities.projectId);
9
+ const [pinnedNotes, openTasks, pendingDecisions, recentRows] = await Promise.all([
10
+ db
11
+ .select()
12
+ .from(entities)
13
+ .where(and(projectFilter, eq(entities.pinned, true)))
14
+ .orderBy(desc(entities.updatedAt))
15
+ .limit(20),
16
+ db
17
+ .select()
18
+ .from(entities)
19
+ .where(and(projectFilter, eq(entities.kind, "task"), eq(entities.status, "open")))
20
+ .orderBy(desc(entities.createdAt))
21
+ .limit(20),
22
+ db
23
+ .select()
24
+ .from(entities)
25
+ .where(and(projectFilter, eq(entities.kind, "decision"), eq(entities.status, "open")))
26
+ .orderBy(desc(entities.createdAt))
27
+ .limit(10),
28
+ db
29
+ .select()
30
+ .from(entities)
31
+ .where(and(projectFilter, ne(entities.kind, "log")))
32
+ .orderBy(desc(entities.createdAt))
33
+ .limit(input.recentLimit)
34
+ ]);
35
+ return {
36
+ project,
37
+ agentsMd: project?.agentsMd ?? "",
38
+ pinnedNotes,
39
+ openTasks,
40
+ pendingDecisions,
41
+ recent: recentRows,
42
+ generatedAt: new Date()
43
+ };
44
+ }
45
+ function titleFor(e) {
46
+ if (e.title && e.title.trim())
47
+ return e.title;
48
+ const firstLine = e.body.split("\n").find((l) => l.trim())?.trim() ?? "";
49
+ if (firstLine)
50
+ return firstLine.length > 60 ? `${firstLine.slice(0, 60)}…` : firstLine;
51
+ return "(untitled)";
52
+ }
53
+ export function formatOpeningBrief(brief) {
54
+ const lines = [];
55
+ if (brief.project) {
56
+ lines.push(`# Project: ${brief.project.key} — ${brief.project.name}`);
57
+ }
58
+ else {
59
+ lines.push(`# Workspace`);
60
+ }
61
+ lines.push("");
62
+ if (brief.agentsMd) {
63
+ lines.push("## AGENTS.md");
64
+ lines.push(brief.agentsMd.trim());
65
+ lines.push("");
66
+ }
67
+ if (brief.pinnedNotes.length) {
68
+ lines.push(`## Pinned Notes (${brief.pinnedNotes.length})`);
69
+ lines.push("_These are pinned by the user as always-relevant context for this project. Read them before acting._");
70
+ lines.push("");
71
+ for (const n of brief.pinnedNotes) {
72
+ lines.push(`### 📌 ${titleFor(n)}`);
73
+ if (n.body.trim()) {
74
+ lines.push(n.body.trim());
75
+ }
76
+ lines.push("");
77
+ }
78
+ }
79
+ if (brief.openTasks.length) {
80
+ lines.push(`## Open Tasks (${brief.openTasks.length})`);
81
+ for (const t of brief.openTasks) {
82
+ lines.push(`- [${t.id.slice(0, 8)}] ${titleFor(t)}${t.tags.length ? ` [${t.tags.join(", ")}]` : ""}`);
83
+ }
84
+ lines.push("");
85
+ }
86
+ if (brief.pendingDecisions.length) {
87
+ lines.push(`## Pending Decisions (${brief.pendingDecisions.length})`);
88
+ for (const d of brief.pendingDecisions) {
89
+ lines.push(`- [${d.id.slice(0, 8)}] ${titleFor(d)}`);
90
+ }
91
+ lines.push("");
92
+ }
93
+ if (brief.recent.length) {
94
+ lines.push(`## Recent Activity (${brief.recent.length})`);
95
+ for (const r of brief.recent) {
96
+ const when = r.createdAt.toISOString().slice(0, 16).replace("T", " ");
97
+ lines.push(`- ${when} · ${r.kind} · ${titleFor(r)}`);
98
+ }
99
+ lines.push("");
100
+ }
101
+ lines.push(`_Generated at ${brief.generatedAt.toISOString()}_`);
102
+ return lines.join("\n");
103
+ }
104
+ //# sourceMappingURL=opening_brief.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opening_brief.js","sourceRoot":"","sources":["../../src/service/opening_brief.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Database } from "../db/client.js";
2
+ import { type Project } from "../db/schema.js";
3
+ import type { CreateProjectInput, UpdateProjectInput } from "./types.js";
4
+ export declare function createProject(db: Database["db"], input: CreateProjectInput): Promise<Project>;
5
+ export declare function updateProject(db: Database["db"], id: string, input: UpdateProjectInput): Promise<Project>;
6
+ export declare function getProjectByKey(db: Database["db"], key: string): Promise<Project | null>;
7
+ export declare function getProject(db: Database["db"], id: string): Promise<Project | null>;
8
+ export declare function listProjects(db: Database["db"]): Promise<Project[]>;
@@ -0,0 +1,36 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { projects } from "../db/schema.js";
3
+ export async function createProject(db, input) {
4
+ const [row] = await db
5
+ .insert(projects)
6
+ .values({
7
+ key: input.key,
8
+ name: input.name,
9
+ color: input.color,
10
+ icon: input.icon,
11
+ agentsMd: input.agentsMd
12
+ })
13
+ .returning();
14
+ if (!row)
15
+ throw new Error("project insert returned no row");
16
+ return row;
17
+ }
18
+ export async function updateProject(db, id, input) {
19
+ const set = { ...input, updatedAt: new Date() };
20
+ const [row] = await db.update(projects).set(set).where(eq(projects.id, id)).returning();
21
+ if (!row)
22
+ throw new Error(`project ${id} not found`);
23
+ return row;
24
+ }
25
+ export async function getProjectByKey(db, key) {
26
+ const rows = await db.select().from(projects).where(eq(projects.key, key)).limit(1);
27
+ return rows[0] ?? null;
28
+ }
29
+ export async function getProject(db, id) {
30
+ const rows = await db.select().from(projects).where(eq(projects.id, id)).limit(1);
31
+ return rows[0] ?? null;
32
+ }
33
+ export async function listProjects(db) {
34
+ return db.select().from(projects).orderBy(projects.key);
35
+ }
36
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/service/projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEjC,OAAO,EAAE,QAAQ,EAAgB,MAAM,iBAAiB,CAAC;AAGzD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAkB,EAClB,KAAyB;IAEzB,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE;SACnB,MAAM,CAAC,QAAQ,CAAC;SAChB,MAAM,CAAC;QACN,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC;SACD,SAAS,EAAE,CAAC;IACf,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAC5D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAkB,EAClB,EAAU,EACV,KAAyB;IAEzB,MAAM,GAAG,GAA4B,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;IACzE,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IACxF,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IACrD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,EAAkB,EAClB,GAAW;IAEX,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,EAAkB,EAAE,EAAU;IAC7D,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClF,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAkB;IACnD,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Database } from "../db/client.js";
2
+ import { type Entity } from "../db/schema.js";
3
+ import type { SearchInput } from "./types.js";
4
+ export interface SearchHit {
5
+ entity: Entity;
6
+ score: number;
7
+ components: {
8
+ bm25?: number;
9
+ cosine?: number;
10
+ timeDecay?: number;
11
+ };
12
+ }
13
+ export declare function search(db: Database["db"], input: SearchInput, opts?: {
14
+ queryEmbedding?: number[];
15
+ }): Promise<SearchHit[]>;