kortext 2.2.3 → 3.0.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.
Files changed (208) hide show
  1. package/AGENTS.md +0 -4
  2. package/CHANGELOG.md +81 -0
  3. package/LICENSE +21 -0
  4. package/README.md +145 -55
  5. package/USER-GUIDE.md +505 -0
  6. package/bin/kortext.js +23 -0
  7. package/bin/kortext.ts +377 -0
  8. package/dist/bin/kortext.js +346 -0
  9. package/dist/bin/kortext.js.map +1 -0
  10. package/dist/mcp/index.js +4 -0
  11. package/dist/mcp/index.js.map +1 -0
  12. package/dist/mcp/server.js +553 -0
  13. package/dist/mcp/server.js.map +1 -0
  14. package/dist/mcp/sse.js +38 -0
  15. package/dist/mcp/sse.js.map +1 -0
  16. package/dist/mcp/stdio.js +44 -0
  17. package/dist/mcp/stdio.js.map +1 -0
  18. package/dist/server/cli/cleanup.js +73 -0
  19. package/dist/server/cli/cleanup.js.map +1 -0
  20. package/dist/server/cli/commands.js +73 -0
  21. package/dist/server/cli/commands.js.map +1 -0
  22. package/dist/server/cli/doctor.js +118 -0
  23. package/dist/server/cli/doctor.js.map +1 -0
  24. package/dist/server/cli/executor-factory.js +39 -0
  25. package/dist/server/cli/executor-factory.js.map +1 -0
  26. package/dist/server/cli/init.js +121 -0
  27. package/dist/server/cli/init.js.map +1 -0
  28. package/dist/server/cli/logs.js +28 -0
  29. package/dist/server/cli/logs.js.map +1 -0
  30. package/dist/server/cli/serve.js +72 -0
  31. package/dist/server/cli/serve.js.map +1 -0
  32. package/dist/server/config/env.js +12 -0
  33. package/dist/server/config/env.js.map +1 -0
  34. package/dist/server/db/client.js +32 -0
  35. package/dist/server/db/client.js.map +1 -0
  36. package/dist/server/db/json.js +21 -0
  37. package/dist/server/db/json.js.map +1 -0
  38. package/dist/server/db/migrate.js +70 -0
  39. package/dist/server/db/migrate.js.map +1 -0
  40. package/dist/server/db/migrations/001_init.sql +243 -0
  41. package/dist/server/db/repositories/audit-log.js +58 -0
  42. package/dist/server/db/repositories/audit-log.js.map +1 -0
  43. package/dist/server/db/repositories/backlog.js +96 -0
  44. package/dist/server/db/repositories/backlog.js.map +1 -0
  45. package/dist/server/db/repositories/contexts.js +54 -0
  46. package/dist/server/db/repositories/contexts.js.map +1 -0
  47. package/dist/server/db/repositories/decisions.js +71 -0
  48. package/dist/server/db/repositories/decisions.js.map +1 -0
  49. package/dist/server/db/repositories/handovers.js +53 -0
  50. package/dist/server/db/repositories/handovers.js.map +1 -0
  51. package/dist/server/db/repositories/index.js +30 -0
  52. package/dist/server/db/repositories/index.js.map +1 -0
  53. package/dist/server/db/repositories/locks.js +59 -0
  54. package/dist/server/db/repositories/locks.js.map +1 -0
  55. package/dist/server/db/repositories/notifications.js +63 -0
  56. package/dist/server/db/repositories/notifications.js.map +1 -0
  57. package/dist/server/db/repositories/pending-questions.js +63 -0
  58. package/dist/server/db/repositories/pending-questions.js.map +1 -0
  59. package/dist/server/db/repositories/runs.js +138 -0
  60. package/dist/server/db/repositories/runs.js.map +1 -0
  61. package/dist/server/db/repositories/runtime-artifacts.js +39 -0
  62. package/dist/server/db/repositories/runtime-artifacts.js.map +1 -0
  63. package/dist/server/db/repositories/secrets.js +65 -0
  64. package/dist/server/db/repositories/secrets.js.map +1 -0
  65. package/dist/server/db/repositories/sessions.js +48 -0
  66. package/dist/server/db/repositories/sessions.js.map +1 -0
  67. package/dist/server/db/schemas.js +308 -0
  68. package/dist/server/db/schemas.js.map +1 -0
  69. package/dist/server/engine/consistency.js +25 -0
  70. package/dist/server/engine/consistency.js.map +1 -0
  71. package/dist/server/engine/dag.js +86 -0
  72. package/dist/server/engine/dag.js.map +1 -0
  73. package/dist/server/engine/executor.js +2 -0
  74. package/dist/server/engine/executor.js.map +1 -0
  75. package/dist/server/engine/executors/claude-cli-executor.js +83 -0
  76. package/dist/server/engine/executors/claude-cli-executor.js.map +1 -0
  77. package/dist/server/engine/executors/cli-spawn.js +127 -0
  78. package/dist/server/engine/executors/cli-spawn.js.map +1 -0
  79. package/dist/server/engine/executors/codex-cli-executor.js +69 -0
  80. package/dist/server/engine/executors/codex-cli-executor.js.map +1 -0
  81. package/dist/server/engine/executors/gemini-cli-executor.js +69 -0
  82. package/dist/server/engine/executors/gemini-cli-executor.js.map +1 -0
  83. package/dist/server/engine/executors/mock-executor.js +52 -0
  84. package/dist/server/engine/executors/mock-executor.js.map +1 -0
  85. package/dist/server/engine/executors/persona-routed-executor.js +17 -0
  86. package/dist/server/engine/executors/persona-routed-executor.js.map +1 -0
  87. package/dist/server/engine/gate-enforcer.js +75 -0
  88. package/dist/server/engine/gate-enforcer.js.map +1 -0
  89. package/dist/server/engine/git-commit.js +42 -0
  90. package/dist/server/engine/git-commit.js.map +1 -0
  91. package/dist/server/engine/handover.js +120 -0
  92. package/dist/server/engine/handover.js.map +1 -0
  93. package/dist/server/engine/item-lifecycle.js +74 -0
  94. package/dist/server/engine/item-lifecycle.js.map +1 -0
  95. package/dist/server/engine/persona-registry.js +108 -0
  96. package/dist/server/engine/persona-registry.js.map +1 -0
  97. package/dist/server/engine/worker-pool.js +324 -0
  98. package/dist/server/engine/worker-pool.js.map +1 -0
  99. package/dist/server/engine/workflow-loader.js +55 -0
  100. package/dist/server/engine/workflow-loader.js.map +1 -0
  101. package/dist/server/engine/workflow-parser.js +158 -0
  102. package/dist/server/engine/workflow-parser.js.map +1 -0
  103. package/dist/server/engine/worktree.js +176 -0
  104. package/dist/server/engine/worktree.js.map +1 -0
  105. package/dist/server/index.js +99 -0
  106. package/dist/server/index.js.map +1 -0
  107. package/dist/server/notifications/dispatcher.js +60 -0
  108. package/dist/server/notifications/dispatcher.js.map +1 -0
  109. package/dist/server/notifications/slack.js +37 -0
  110. package/dist/server/notifications/slack.js.map +1 -0
  111. package/dist/server/notifications/telegram.js +33 -0
  112. package/dist/server/notifications/telegram.js.map +1 -0
  113. package/dist/server/orchestrator/approval-queue.js +83 -0
  114. package/dist/server/orchestrator/approval-queue.js.map +1 -0
  115. package/dist/server/orchestrator/blueprint-watcher.js +94 -0
  116. package/dist/server/orchestrator/blueprint-watcher.js.map +1 -0
  117. package/dist/server/orchestrator/orchestrator.js +283 -0
  118. package/dist/server/orchestrator/orchestrator.js.map +1 -0
  119. package/dist/server/orchestrator/pipeline-chainer.js +96 -0
  120. package/dist/server/orchestrator/pipeline-chainer.js.map +1 -0
  121. package/dist/server/orchestrator/resume.js +36 -0
  122. package/dist/server/orchestrator/resume.js.map +1 -0
  123. package/dist/server/routes/approvals.js +52 -0
  124. package/dist/server/routes/approvals.js.map +1 -0
  125. package/dist/server/routes/backlog.js +44 -0
  126. package/dist/server/routes/backlog.js.map +1 -0
  127. package/dist/server/routes/db-info.js +21 -0
  128. package/dist/server/routes/db-info.js.map +1 -0
  129. package/dist/server/routes/docs.js +70 -0
  130. package/dist/server/routes/docs.js.map +1 -0
  131. package/dist/server/routes/doctor.js +19 -0
  132. package/dist/server/routes/doctor.js.map +1 -0
  133. package/dist/server/routes/handovers.js +25 -0
  134. package/dist/server/routes/handovers.js.map +1 -0
  135. package/dist/server/routes/health.js +11 -0
  136. package/dist/server/routes/health.js.map +1 -0
  137. package/dist/server/routes/personas.js +96 -0
  138. package/dist/server/routes/personas.js.map +1 -0
  139. package/dist/server/routes/runs.js +41 -0
  140. package/dist/server/routes/runs.js.map +1 -0
  141. package/dist/server/routes/workflows.js +38 -0
  142. package/dist/server/routes/workflows.js.map +1 -0
  143. package/dist/server/safety/harmful-output-filter.js +40 -0
  144. package/dist/server/safety/harmful-output-filter.js.map +1 -0
  145. package/dist/server/safety/secret-scanner.js +169 -0
  146. package/dist/server/safety/secret-scanner.js.map +1 -0
  147. package/dist/server/services/markdown-sync.js +101 -0
  148. package/dist/server/services/markdown-sync.js.map +1 -0
  149. package/dist/web/assets/index-B80d5ZPZ.js +75 -0
  150. package/dist/web/assets/index-B80d5ZPZ.js.map +1 -0
  151. package/dist/web/assets/index-Bge5Gzqv.css +1 -0
  152. package/dist/web/index.html +13 -0
  153. package/docs/architecture.md +413 -0
  154. package/package.json +83 -11
  155. package/scripts/copy-migrations.mjs +29 -0
  156. package/workspace/.locks/workspace_handover.md.lock +3 -0
  157. package/hooks/audit-logger.sh +0 -25
  158. package/hooks/auto-locker.sh +0 -74
  159. package/hooks/auto-unlocker.sh +0 -17
  160. package/hooks/backlog-sync-guard.sh +0 -12
  161. package/hooks/branch-guard.sh +0 -32
  162. package/hooks/commit-msg-guard.sh +0 -43
  163. package/hooks/git-pre-commit.sh +0 -76
  164. package/hooks/git-pre-push.sh +0 -17
  165. package/hooks/handover-guard.sh +0 -33
  166. package/hooks/kortext-init.sh +0 -194
  167. package/hooks/kortext-lib.sh +0 -151
  168. package/hooks/lint-guard.sh +0 -50
  169. package/hooks/secret-scanner.sh +0 -89
  170. package/hooks/size-guard.sh +0 -48
  171. package/hooks/snapshot-guard.sh +0 -39
  172. package/hooks/write-guard.sh +0 -77
  173. package/scripts/kortext-backlog-add.py +0 -123
  174. package/scripts/kortext-backlog-health.py +0 -112
  175. package/scripts/kortext-backlog-sync.py +0 -117
  176. package/scripts/kortext-bulk-plan.py +0 -63
  177. package/scripts/kortext-cli.py +0 -376
  178. package/scripts/kortext-consistency-check.py +0 -74
  179. package/scripts/kortext-context-check.py +0 -146
  180. package/scripts/kortext-handover.py +0 -107
  181. package/scripts/kortext-item-check.py +0 -61
  182. package/scripts/kortext-item-start.py +0 -70
  183. package/scripts/kortext-item-transition.py +0 -78
  184. package/scripts/kortext-lock.py +0 -174
  185. package/scripts/kortext-session-start.py +0 -127
  186. package/scripts/lock_kortext.sh +0 -34
  187. package/settings/.claude-settings.template.json +0 -48
  188. package/settings/CHANGELOG.md +0 -176
  189. package/settings/INTEGRATION-MAP.md +0 -276
  190. package/settings/README.md +0 -255
  191. package/settings/USER-GUIDE.md +0 -502
  192. package/settings/VERSION +0 -1
  193. package/settings/config.md +0 -8
  194. package/settings/runtime-adapters.md +0 -104
  195. package/skills/backend-developer/.gitkeep +0 -0
  196. package/skills/compliance-expert/.gitkeep +0 -0
  197. package/skills/copywriter/.gitkeep +0 -0
  198. package/skills/db-admin/.gitkeep +0 -0
  199. package/skills/delivery-manager/.gitkeep +0 -0
  200. package/skills/designer/.gitkeep +0 -0
  201. package/skills/devops-engineer/.gitkeep +0 -0
  202. package/skills/engineering-manager/.gitkeep +0 -0
  203. package/skills/frontend-developer/.gitkeep +0 -0
  204. package/skills/growth-expert/.gitkeep +0 -0
  205. package/skills/operation-manager/.gitkeep +0 -0
  206. package/skills/product-manager/.gitkeep +0 -0
  207. package/skills/qa-engineer/.gitkeep +0 -0
  208. package/skills/security-engineer/.gitkeep +0 -0
@@ -0,0 +1,32 @@
1
+ import Database from 'better-sqlite3';
2
+ import { mkdirSync } from 'node:fs';
3
+ import { dirname } from 'node:path';
4
+ import { env } from "../config/env.js";
5
+ import { runMigrations, getSchemaVersion } from "./migrate.js";
6
+ import { createRepositories } from "./repositories/index.js";
7
+ let bundle = null;
8
+ export function openDb(options = {}) {
9
+ const path = options.path ?? env.KORTEXT_DB_PATH;
10
+ if (path !== ':memory:') {
11
+ mkdirSync(dirname(path), { recursive: true });
12
+ }
13
+ const db = new Database(path);
14
+ db.pragma('journal_mode = WAL');
15
+ db.pragma('foreign_keys = ON');
16
+ db.pragma('synchronous = NORMAL');
17
+ if (!options.skipMigrations) {
18
+ runMigrations(db);
19
+ }
20
+ const repositories = createRepositories(db);
21
+ return { db, repositories, schemaVersion: getSchemaVersion(db) };
22
+ }
23
+ export function getDb() {
24
+ if (!bundle) {
25
+ bundle = openDb();
26
+ }
27
+ return bundle;
28
+ }
29
+ export function resetDbForTests() {
30
+ bundle = null;
31
+ }
32
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../server/db/client.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAqB,MAAM,yBAAyB,CAAC;AAQhF,IAAI,MAAM,GAAoB,IAAI,CAAC;AAQnC,MAAM,UAAU,MAAM,CAAC,UAAyB,EAAE;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,GAAG,CAAC,eAAe,CAAC;IACjD,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;IAElC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC5B,aAAa,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IACD,MAAM,YAAY,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,MAAM,EAAE,CAAC;IACpB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Tiny helpers for JSON column round-tripping.
3
+ * SQLite stores JSON as TEXT; these wrap stringify/parse with safe fallbacks
4
+ * so callers can keep working with native objects.
5
+ */
6
+ export function packJson(value) {
7
+ if (value === undefined)
8
+ return '{}';
9
+ return JSON.stringify(value);
10
+ }
11
+ export function unpackJson(text, fallback) {
12
+ if (!text)
13
+ return fallback;
14
+ try {
15
+ return JSON.parse(text);
16
+ }
17
+ catch {
18
+ return fallback;
19
+ }
20
+ }
21
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../../server/db/json.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,UAAU,CAAc,IAA+B,EAAE,QAAW;IAClF,IAAI,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { readdirSync, readFileSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const MIGRATIONS_DIR = join(dirname(fileURLToPath(import.meta.url)), 'migrations');
5
+ function loadMigrations() {
6
+ const files = readdirSync(MIGRATIONS_DIR).filter((f) => f.endsWith('.sql'));
7
+ const migrations = [];
8
+ for (const file of files) {
9
+ const match = /^(\d+)_(.+)\.sql$/.exec(file);
10
+ if (!match)
11
+ continue;
12
+ const idStr = match[1];
13
+ const name = match[2];
14
+ if (!idStr || !name)
15
+ continue;
16
+ migrations.push({
17
+ id: Number(idStr),
18
+ name,
19
+ sql: readFileSync(join(MIGRATIONS_DIR, file), 'utf8'),
20
+ });
21
+ }
22
+ migrations.sort((a, b) => a.id - b.id);
23
+ return migrations;
24
+ }
25
+ const TRACKING_TABLE_DDL = `
26
+ CREATE TABLE IF NOT EXISTS schema_migrations (
27
+ id INTEGER PRIMARY KEY,
28
+ name TEXT NOT NULL,
29
+ applied_at INTEGER NOT NULL
30
+ );
31
+ `;
32
+ function ensureMigrationsTable(db) {
33
+ const runMulti = db.exec.bind(db);
34
+ runMulti(TRACKING_TABLE_DDL);
35
+ }
36
+ export function runMigrations(db) {
37
+ ensureMigrationsTable(db);
38
+ const appliedRows = db
39
+ .prepare('SELECT id FROM schema_migrations ORDER BY id')
40
+ .all();
41
+ const appliedIds = new Set(appliedRows.map((r) => r.id));
42
+ const migrations = loadMigrations();
43
+ const insertMigration = db.prepare('INSERT INTO schema_migrations (id, name, applied_at) VALUES (?, ?, ?)');
44
+ const runMulti = db.exec.bind(db);
45
+ const applied = [];
46
+ for (const m of migrations) {
47
+ if (appliedIds.has(m.id))
48
+ continue;
49
+ const runTx = db.transaction(() => {
50
+ runMulti(m.sql);
51
+ insertMigration.run(m.id, m.name, Date.now());
52
+ });
53
+ runTx();
54
+ applied.push({ id: m.id, name: m.name });
55
+ }
56
+ const latest = migrations.length > 0 ? (migrations[migrations.length - 1]?.id ?? 0) : 0;
57
+ return {
58
+ applied,
59
+ alreadyApplied: appliedIds.size,
60
+ latestId: latest,
61
+ };
62
+ }
63
+ export function getSchemaVersion(db) {
64
+ ensureMigrationsTable(db);
65
+ const row = db
66
+ .prepare('SELECT MAX(id) as v FROM schema_migrations')
67
+ .get();
68
+ return row?.v ?? 0;
69
+ }
70
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../server/db/migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,243 @@
1
+ -- Kortext v3.0 — initial schema
2
+ -- All timestamps are Unix milliseconds (INTEGER). All JSON columns are TEXT with json1 access.
3
+
4
+ ----------------------------------------------------------------------
5
+ -- backlog_items: Epic / Task / Bug / Debt / Spike / Hotfix
6
+ ----------------------------------------------------------------------
7
+ CREATE TABLE backlog_items (
8
+ id TEXT PRIMARY KEY, -- e.g. T01, E01-auth
9
+ type TEXT NOT NULL CHECK (type IN ('task','bug','debt','epic','spike','hotfix')),
10
+ title TEXT NOT NULL,
11
+ status TEXT NOT NULL DEFAULT 'to_do'
12
+ CHECK (status IN ('to_do','in_progress','blocked','review','done','cancelled')),
13
+ owner TEXT, -- persona handle, e.g. '+backend-engineer'
14
+ parent_id TEXT REFERENCES backlog_items(id) ON DELETE SET NULL,
15
+ version TEXT, -- target version, e.g. 'v3.0.0'
16
+ frontmatter TEXT NOT NULL DEFAULT '{}', -- JSON metadata
17
+ body_md TEXT NOT NULL DEFAULT '', -- full markdown body
18
+ created_at INTEGER NOT NULL,
19
+ updated_at INTEGER NOT NULL
20
+ );
21
+
22
+ CREATE INDEX idx_backlog_status ON backlog_items(status);
23
+ CREATE INDEX idx_backlog_owner ON backlog_items(owner);
24
+ CREATE INDEX idx_backlog_parent ON backlog_items(parent_id);
25
+ CREATE INDEX idx_backlog_type ON backlog_items(type);
26
+
27
+ ----------------------------------------------------------------------
28
+ -- sessions: runtime oturumları
29
+ ----------------------------------------------------------------------
30
+ CREATE TABLE sessions (
31
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
32
+ started_by TEXT NOT NULL, -- persona or 'user' or 'system'
33
+ entry_point TEXT NOT NULL CHECK (entry_point IN ('cli','mcp','dashboard','cron','system')),
34
+ metadata TEXT NOT NULL DEFAULT '{}',
35
+ started_at INTEGER NOT NULL,
36
+ ended_at INTEGER
37
+ );
38
+
39
+ CREATE INDEX idx_sessions_started_at ON sessions(started_at);
40
+
41
+ ----------------------------------------------------------------------
42
+ -- contexts: aktif ajan oturum context'leri
43
+ ----------------------------------------------------------------------
44
+ CREATE TABLE contexts (
45
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46
+ persona TEXT NOT NULL,
47
+ item_id TEXT REFERENCES backlog_items(id) ON DELETE CASCADE,
48
+ session_id INTEGER REFERENCES sessions(id) ON DELETE CASCADE,
49
+ payload TEXT NOT NULL DEFAULT '{}',
50
+ created_at INTEGER NOT NULL,
51
+ updated_at INTEGER NOT NULL,
52
+ UNIQUE(persona, item_id)
53
+ );
54
+
55
+ CREATE INDEX idx_contexts_persona ON contexts(persona);
56
+ CREATE INDEX idx_contexts_item ON contexts(item_id);
57
+
58
+ ----------------------------------------------------------------------
59
+ -- locks: dosya/path kilitleri
60
+ ----------------------------------------------------------------------
61
+ CREATE TABLE locks (
62
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
63
+ resource TEXT NOT NULL UNIQUE, -- path or logical resource id
64
+ holder TEXT NOT NULL, -- persona handle
65
+ reason TEXT,
66
+ acquired_at INTEGER NOT NULL,
67
+ expires_at INTEGER -- nullable: null = manual release
68
+ );
69
+
70
+ CREATE INDEX idx_locks_holder ON locks(holder);
71
+ CREATE INDEX idx_locks_expires_at ON locks(expires_at);
72
+
73
+ ----------------------------------------------------------------------
74
+ -- handovers: persona devir kayıtları
75
+ ----------------------------------------------------------------------
76
+ CREATE TABLE handovers (
77
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
78
+ item_id TEXT REFERENCES backlog_items(id) ON DELETE CASCADE,
79
+ from_persona TEXT NOT NULL,
80
+ to_persona TEXT NOT NULL,
81
+ reason TEXT,
82
+ context_payload TEXT NOT NULL DEFAULT '{}', -- JSON snapshot
83
+ markdown_path TEXT, -- mirrored handover.md
84
+ created_at INTEGER NOT NULL
85
+ );
86
+
87
+ CREATE INDEX idx_handovers_item ON handovers(item_id);
88
+ CREATE INDEX idx_handovers_to ON handovers(to_persona);
89
+ CREATE INDEX idx_handovers_created_at ON handovers(created_at);
90
+
91
+ ----------------------------------------------------------------------
92
+ -- decisions_index: ADR markdown index
93
+ ----------------------------------------------------------------------
94
+ CREATE TABLE decisions_index (
95
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
96
+ decision_id TEXT NOT NULL UNIQUE, -- e.g. 'ADR-001'
97
+ title TEXT NOT NULL,
98
+ status TEXT NOT NULL DEFAULT 'proposed'
99
+ CHECK (status IN ('proposed','accepted','superseded','rejected')),
100
+ markdown_path TEXT NOT NULL, -- relative path to .md file
101
+ item_id TEXT REFERENCES backlog_items(id) ON DELETE SET NULL,
102
+ tags TEXT NOT NULL DEFAULT '[]', -- JSON array
103
+ created_at INTEGER NOT NULL,
104
+ decided_at INTEGER
105
+ );
106
+
107
+ CREATE INDEX idx_decisions_status ON decisions_index(status);
108
+ CREATE INDEX idx_decisions_item ON decisions_index(item_id);
109
+
110
+ ----------------------------------------------------------------------
111
+ -- runs: pipeline çalıştırmaları
112
+ ----------------------------------------------------------------------
113
+ CREATE TABLE runs (
114
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
115
+ workflow_id TEXT NOT NULL, -- e.g. '01a-analysis-pipeline'
116
+ item_id TEXT REFERENCES backlog_items(id) ON DELETE SET NULL,
117
+ status TEXT NOT NULL DEFAULT 'queued'
118
+ CHECK (status IN ('queued','running','succeeded','failed','cancelled','awaiting_approval')),
119
+ worktree_path TEXT,
120
+ triggered_by TEXT NOT NULL, -- persona / 'auto' / 'user'
121
+ error_message TEXT,
122
+ started_at INTEGER,
123
+ ended_at INTEGER,
124
+ created_at INTEGER NOT NULL
125
+ );
126
+
127
+ CREATE INDEX idx_runs_status ON runs(status);
128
+ CREATE INDEX idx_runs_workflow ON runs(workflow_id);
129
+ CREATE INDEX idx_runs_item ON runs(item_id);
130
+ CREATE INDEX idx_runs_created_at ON runs(created_at);
131
+
132
+ ----------------------------------------------------------------------
133
+ -- run_steps: her pipeline adımı
134
+ ----------------------------------------------------------------------
135
+ CREATE TABLE run_steps (
136
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
137
+ run_id INTEGER NOT NULL REFERENCES runs(id) ON DELETE CASCADE,
138
+ step_index INTEGER NOT NULL,
139
+ step_name TEXT NOT NULL,
140
+ persona TEXT,
141
+ status TEXT NOT NULL DEFAULT 'pending'
142
+ CHECK (status IN ('pending','running','succeeded','failed','skipped')),
143
+ started_at INTEGER,
144
+ ended_at INTEGER,
145
+ log_path TEXT,
146
+ output_summary TEXT,
147
+ error_message TEXT,
148
+ UNIQUE(run_id, step_index)
149
+ );
150
+
151
+ CREATE INDEX idx_run_steps_run ON run_steps(run_id);
152
+ CREATE INDEX idx_run_steps_status ON run_steps(status);
153
+
154
+ ----------------------------------------------------------------------
155
+ -- pending_questions: +prime onay kuyruğu
156
+ ----------------------------------------------------------------------
157
+ CREATE TABLE pending_questions (
158
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
159
+ run_id INTEGER REFERENCES runs(id) ON DELETE CASCADE,
160
+ step_id INTEGER REFERENCES run_steps(id) ON DELETE SET NULL,
161
+ question TEXT NOT NULL,
162
+ choices TEXT NOT NULL DEFAULT '[]', -- JSON array; empty = free-form
163
+ status TEXT NOT NULL DEFAULT 'open'
164
+ CHECK (status IN ('open','answered','expired','cancelled')),
165
+ answer TEXT,
166
+ answered_by TEXT,
167
+ answered_at INTEGER,
168
+ created_at INTEGER NOT NULL
169
+ );
170
+
171
+ CREATE INDEX idx_pending_q_status ON pending_questions(status);
172
+ CREATE INDEX idx_pending_q_run ON pending_questions(run_id);
173
+
174
+ ----------------------------------------------------------------------
175
+ -- runtime_artifacts: worktree, log, diff snapshot
176
+ ----------------------------------------------------------------------
177
+ CREATE TABLE runtime_artifacts (
178
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
179
+ run_id INTEGER REFERENCES runs(id) ON DELETE CASCADE,
180
+ step_id INTEGER REFERENCES run_steps(id) ON DELETE CASCADE,
181
+ kind TEXT NOT NULL CHECK (kind IN ('worktree','log','diff','stdout','stderr','file','screenshot')),
182
+ path TEXT NOT NULL,
183
+ bytes INTEGER,
184
+ created_at INTEGER NOT NULL
185
+ );
186
+
187
+ CREATE INDEX idx_artifacts_run ON runtime_artifacts(run_id);
188
+ CREATE INDEX idx_artifacts_kind ON runtime_artifacts(kind);
189
+
190
+ ----------------------------------------------------------------------
191
+ -- notifications_sent: bildirim deduplication
192
+ ----------------------------------------------------------------------
193
+ CREATE TABLE notifications_sent (
194
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
195
+ channel TEXT NOT NULL CHECK (channel IN ('slack','telegram','ui','email')),
196
+ event_key TEXT NOT NULL, -- dedup key per channel+event
197
+ payload TEXT NOT NULL DEFAULT '{}',
198
+ status TEXT NOT NULL DEFAULT 'sent'
199
+ CHECK (status IN ('sent','failed','suppressed')),
200
+ error_message TEXT,
201
+ created_at INTEGER NOT NULL,
202
+ UNIQUE(channel, event_key)
203
+ );
204
+
205
+ CREATE INDEX idx_notif_created_at ON notifications_sent(created_at);
206
+
207
+ ----------------------------------------------------------------------
208
+ -- secrets_scan_results: secret-scanner bulguları
209
+ ----------------------------------------------------------------------
210
+ CREATE TABLE secrets_scan_results (
211
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
212
+ run_id INTEGER REFERENCES runs(id) ON DELETE SET NULL,
213
+ scanned_path TEXT NOT NULL,
214
+ finding_type TEXT NOT NULL, -- e.g. 'aws_access_key','generic_api_key'
215
+ severity TEXT NOT NULL CHECK (severity IN ('low','medium','high','critical')),
216
+ line_number INTEGER,
217
+ context TEXT,
218
+ masked_snippet TEXT,
219
+ resolved INTEGER NOT NULL DEFAULT 0 CHECK (resolved IN (0,1)),
220
+ created_at INTEGER NOT NULL
221
+ );
222
+
223
+ CREATE INDEX idx_secrets_severity ON secrets_scan_results(severity);
224
+ CREATE INDEX idx_secrets_resolved ON secrets_scan_results(resolved);
225
+ CREATE INDEX idx_secrets_run ON secrets_scan_results(run_id);
226
+
227
+ ----------------------------------------------------------------------
228
+ -- audit_log: tüm aksiyonların append-only kaydı
229
+ ----------------------------------------------------------------------
230
+ CREATE TABLE audit_log (
231
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
232
+ actor TEXT NOT NULL, -- persona, 'user', 'system'
233
+ action TEXT NOT NULL, -- e.g. 'backlog.item.created'
234
+ resource_type TEXT,
235
+ resource_id TEXT,
236
+ payload TEXT NOT NULL DEFAULT '{}',
237
+ created_at INTEGER NOT NULL
238
+ );
239
+
240
+ CREATE INDEX idx_audit_actor ON audit_log(actor);
241
+ CREATE INDEX idx_audit_action ON audit_log(action);
242
+ CREATE INDEX idx_audit_resource ON audit_log(resource_type, resource_id);
243
+ CREATE INDEX idx_audit_created_at ON audit_log(created_at);
@@ -0,0 +1,58 @@
1
+ import { AuditLogInsertSchema, AuditLogSchema, } from "../schemas.js";
2
+ import { packJson, unpackJson } from "../json.js";
3
+ function rowToAudit(row) {
4
+ return AuditLogSchema.parse({
5
+ ...row,
6
+ payload: unpackJson(row.payload, {}),
7
+ });
8
+ }
9
+ export class AuditLogRepository {
10
+ db;
11
+ insertStmt;
12
+ listStmt;
13
+ constructor(db) {
14
+ this.db = db;
15
+ this.insertStmt = db.prepare(`
16
+ INSERT INTO audit_log (actor, action, resource_type, resource_id, payload, created_at)
17
+ VALUES (@actor, @action, @resource_type, @resource_id, @payload, @created_at)
18
+ `);
19
+ this.listStmt = db.prepare(`
20
+ SELECT * FROM audit_log
21
+ WHERE (@actor IS NULL OR actor = @actor)
22
+ AND (@action IS NULL OR action = @action)
23
+ AND (@resource_type IS NULL OR resource_type = @resource_type)
24
+ AND (@resource_id IS NULL OR resource_id = @resource_id)
25
+ AND (@since IS NULL OR created_at >= @since)
26
+ ORDER BY created_at DESC
27
+ LIMIT @limit OFFSET @offset
28
+ `);
29
+ }
30
+ append(input) {
31
+ const parsed = AuditLogInsertSchema.parse(input);
32
+ const result = this.insertStmt.run({
33
+ actor: parsed.actor,
34
+ action: parsed.action,
35
+ resource_type: parsed.resource_type,
36
+ resource_id: parsed.resource_id,
37
+ payload: packJson(parsed.payload),
38
+ created_at: Date.now(),
39
+ });
40
+ const row = this.db
41
+ .prepare('SELECT * FROM audit_log WHERE id = ?')
42
+ .get(Number(result.lastInsertRowid));
43
+ return rowToAudit(row);
44
+ }
45
+ list(filter = {}) {
46
+ const rows = this.listStmt.all({
47
+ actor: filter.actor ?? null,
48
+ action: filter.action ?? null,
49
+ resource_type: filter.resource_type ?? null,
50
+ resource_id: filter.resource_id ?? null,
51
+ since: filter.since ?? null,
52
+ limit: filter.limit ?? 200,
53
+ offset: filter.offset ?? 0,
54
+ });
55
+ return rows.map(rowToAudit);
56
+ }
57
+ }
58
+ //# sourceMappingURL=audit-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log.js","sourceRoot":"","sources":["../../../../server/db/repositories/audit-log.ts"],"names":[],"mappings":"AACA,OAAO,EACL,oBAAoB,EACpB,cAAc,GAGf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAYlD,SAAS,UAAU,CAAC,GAAQ;IAC1B,OAAO,cAAc,CAAC,KAAK,CAAC;QAC1B,GAAG,GAAG;QACN,OAAO,EAAE,UAAU,CAA0B,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;KAC9D,CAAC,CAAC;AACL,CAAC;AAED,MAAM,OAAO,kBAAkB;IAIA;IAHZ,UAAU,CAAC;IACX,QAAQ,CAAC;IAE1B,YAA6B,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;QAChD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC;;;KAG5B,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;;KAS1B,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,KAAqB;QAC1B,MAAM,MAAM,GAAG,oBAAoB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YACjC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;YACjC,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;SACvB,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE;aAChB,OAAO,CAAC,sCAAsC,CAAC;aAC/C,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAQ,CAAC;QAC9C,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,IAAI,CACF,SAQI,EAAE;QAEN,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAC7B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;YAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;YAC7B,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,IAAI;YAC3C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI;YACvC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;YAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG;YAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;SAC3B,CAAU,CAAC;QACZ,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,96 @@
1
+ import { BacklogItemInsertSchema, BacklogItemSchema, BacklogStatusSchema, } from "../schemas.js";
2
+ import { packJson, unpackJson } from "../json.js";
3
+ function rowToItem(row) {
4
+ return BacklogItemSchema.parse({
5
+ ...row,
6
+ frontmatter: unpackJson(row.frontmatter, {}),
7
+ });
8
+ }
9
+ export class BacklogRepository {
10
+ db;
11
+ insertStmt;
12
+ selectByIdStmt;
13
+ listStmt;
14
+ updateStatusStmt;
15
+ updateBodyStmt;
16
+ deleteStmt;
17
+ countStmt;
18
+ constructor(db) {
19
+ this.db = db;
20
+ this.insertStmt = db.prepare(`
21
+ INSERT INTO backlog_items
22
+ (id, type, title, status, owner, parent_id, version, frontmatter, body_md, created_at, updated_at)
23
+ VALUES
24
+ (@id, @type, @title, @status, @owner, @parent_id, @version, @frontmatter, @body_md, @ts, @ts)
25
+ `);
26
+ this.selectByIdStmt = db.prepare('SELECT * FROM backlog_items WHERE id = ?');
27
+ this.listStmt = db.prepare(`
28
+ SELECT * FROM backlog_items
29
+ WHERE (@type IS NULL OR type = @type)
30
+ AND (@status IS NULL OR status = @status)
31
+ AND (@owner IS NULL OR owner = @owner)
32
+ AND (@parent_id IS NULL OR parent_id = @parent_id)
33
+ ORDER BY created_at DESC
34
+ LIMIT @limit OFFSET @offset
35
+ `);
36
+ this.updateStatusStmt = db.prepare('UPDATE backlog_items SET status = @status, updated_at = @ts WHERE id = @id');
37
+ this.updateBodyStmt = db.prepare('UPDATE backlog_items SET body_md = @body, updated_at = @ts WHERE id = @id');
38
+ this.deleteStmt = db.prepare('DELETE FROM backlog_items WHERE id = ?');
39
+ this.countStmt = db.prepare('SELECT COUNT(*) as n FROM backlog_items WHERE (@status IS NULL OR status = @status)');
40
+ }
41
+ create(input) {
42
+ const parsed = BacklogItemInsertSchema.parse(input);
43
+ const ts = Date.now();
44
+ this.insertStmt.run({
45
+ id: parsed.id,
46
+ type: parsed.type,
47
+ title: parsed.title,
48
+ status: parsed.status,
49
+ owner: parsed.owner,
50
+ parent_id: parsed.parent_id,
51
+ version: parsed.version,
52
+ frontmatter: packJson(parsed.frontmatter),
53
+ body_md: parsed.body_md,
54
+ ts,
55
+ });
56
+ return this.get(parsed.id);
57
+ }
58
+ get(id) {
59
+ const row = this.selectByIdStmt.get(id);
60
+ return row ? rowToItem(row) : null;
61
+ }
62
+ list(filter = {}) {
63
+ const rows = this.listStmt.all({
64
+ type: filter.type ?? null,
65
+ status: filter.status ?? null,
66
+ owner: filter.owner ?? null,
67
+ parent_id: filter.parent_id ?? null,
68
+ limit: filter.limit ?? 100,
69
+ offset: filter.offset ?? 0,
70
+ });
71
+ return rows.map(rowToItem);
72
+ }
73
+ transitionStatus(id, status) {
74
+ BacklogStatusSchema.parse(status);
75
+ const ts = Date.now();
76
+ const result = this.updateStatusStmt.run({ id, status, ts });
77
+ if (result.changes === 0) {
78
+ throw new Error(`backlog item not found: ${id}`);
79
+ }
80
+ return this.get(id);
81
+ }
82
+ updateBody(id, body) {
83
+ const ts = Date.now();
84
+ this.updateBodyStmt.run({ id, body, ts });
85
+ return this.get(id);
86
+ }
87
+ delete(id) {
88
+ const result = this.deleteStmt.run(id);
89
+ return result.changes > 0;
90
+ }
91
+ countByStatus(status = null) {
92
+ const row = this.countStmt.get({ status });
93
+ return row.n;
94
+ }
95
+ }
96
+ //# sourceMappingURL=backlog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backlog.js","sourceRoot":"","sources":["../../../../server/db/repositories/backlog.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,GAKpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgBlD,SAAS,SAAS,CAAC,GAAQ;IACzB,OAAO,iBAAiB,CAAC,KAAK,CAAC;QAC7B,GAAG,GAAG;QACN,WAAW,EAAE,UAAU,CAA0B,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;KACtE,CAAC,CAAC;AACL,CAAC;AAED,MAAM,OAAO,iBAAiB;IASC;IARZ,UAAU,CAAC;IACX,cAAc,CAAC;IACf,QAAQ,CAAC;IACT,gBAAgB,CAAC;IACjB,cAAc,CAAC;IACf,UAAU,CAAC;IACX,SAAS,CAAC;IAE3B,YAA6B,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;QAChD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;KAK5B,CAAC,CAAC;QACH,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,OAAO,CAAC,0CAA0C,CAAC,CAAC;QAC7E,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;;KAQ1B,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,GAAG,EAAE,CAAC,OAAO,CAChC,4EAA4E,CAC7E,CAAC;QACF,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,OAAO,CAC9B,2EAA2E,CAC5E,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QACvE,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,OAAO,CACzB,qFAAqF,CACtF,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAwB;QAC7B,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACpD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAClB,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC;YACzC,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,EAAE;SACH,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAE,CAAC;IAC9B,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,CAAoB,CAAC;QAC3D,OAAO,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACrC,CAAC;IAED,IAAI,CACF,SAOI,EAAE;QAEN,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAC7B,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;YAC7B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;YAC3B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,IAAI;YACnC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG;YAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC;SAC3B,CAAU,CAAC;QACZ,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;IAED,gBAAgB,CAAC,EAAU,EAAE,MAAqB;QAChD,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7D,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;IACvB,CAAC;IAED,UAAU,CAAC,EAAU,EAAE,IAAY;QACjC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;IACvB,CAAC;IAED,MAAM,CAAC,EAAU;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvC,OAAO,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,aAAa,CAAC,SAA+B,IAAI;QAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAkB,CAAC;QAC5D,OAAO,GAAG,CAAC,CAAC,CAAC;IACf,CAAC;CACF"}
@@ -0,0 +1,54 @@
1
+ import { ContextSchema, ContextUpsertSchema, } from "../schemas.js";
2
+ import { packJson, unpackJson } from "../json.js";
3
+ function rowToContext(row) {
4
+ return ContextSchema.parse({
5
+ ...row,
6
+ payload: unpackJson(row.payload, {}),
7
+ });
8
+ }
9
+ export class ContextsRepository {
10
+ db;
11
+ upsertStmt;
12
+ selectByKeyStmt;
13
+ listByPersonaStmt;
14
+ deleteStmt;
15
+ constructor(db) {
16
+ this.db = db;
17
+ this.upsertStmt = db.prepare(`
18
+ INSERT INTO contexts (persona, item_id, session_id, payload, created_at, updated_at)
19
+ VALUES (@persona, @item_id, @session_id, @payload, @ts, @ts)
20
+ ON CONFLICT(persona, item_id) DO UPDATE SET
21
+ session_id = excluded.session_id,
22
+ payload = excluded.payload,
23
+ updated_at = excluded.updated_at
24
+ `);
25
+ this.selectByKeyStmt = db.prepare('SELECT * FROM contexts WHERE persona = @persona AND IFNULL(item_id, \'\') = IFNULL(@item_id, \'\')');
26
+ this.listByPersonaStmt = db.prepare('SELECT * FROM contexts WHERE persona = ? ORDER BY updated_at DESC');
27
+ this.deleteStmt = db.prepare('DELETE FROM contexts WHERE persona = @persona AND IFNULL(item_id, \'\') = IFNULL(@item_id, \'\')');
28
+ }
29
+ upsert(input) {
30
+ const parsed = ContextUpsertSchema.parse(input);
31
+ const ts = Date.now();
32
+ this.upsertStmt.run({
33
+ persona: parsed.persona,
34
+ item_id: parsed.item_id,
35
+ session_id: parsed.session_id,
36
+ payload: packJson(parsed.payload),
37
+ ts,
38
+ });
39
+ return this.get(parsed.persona, parsed.item_id);
40
+ }
41
+ get(persona, item_id) {
42
+ const row = this.selectByKeyStmt.get({ persona, item_id });
43
+ return row ? rowToContext(row) : null;
44
+ }
45
+ listByPersona(persona) {
46
+ const rows = this.listByPersonaStmt.all(persona);
47
+ return rows.map(rowToContext);
48
+ }
49
+ delete(persona, item_id) {
50
+ const result = this.deleteStmt.run({ persona, item_id });
51
+ return result.changes > 0;
52
+ }
53
+ }
54
+ //# sourceMappingURL=contexts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contexts.js","sourceRoot":"","sources":["../../../../server/db/repositories/contexts.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EACb,mBAAmB,GAGpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAYlD,SAAS,YAAY,CAAC,GAAQ;IAC5B,OAAO,aAAa,CAAC,KAAK,CAAC;QACzB,GAAG,GAAG;QACN,OAAO,EAAE,UAAU,CAA0B,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;KAC9D,CAAC,CAAC;AACL,CAAC;AAED,MAAM,OAAO,kBAAkB;IAMA;IALZ,UAAU,CAAC;IACX,eAAe,CAAC;IAChB,iBAAiB,CAAC;IAClB,UAAU,CAAC;IAE5B,YAA6B,EAAqB;QAArB,OAAE,GAAF,EAAE,CAAmB;QAChD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC;;;;;;;KAO5B,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,GAAG,EAAE,CAAC,OAAO,CAC/B,oGAAoG,CACrG,CAAC;QACF,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC,OAAO,CACjC,mEAAmE,CACpE,CAAC;QACF,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,OAAO,CAC1B,kGAAkG,CACnG,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAoB;QACzB,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAClB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC;YACjC,EAAE;SACH,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAE,CAAC;IACnD,CAAC;IAED,GAAG,CAAC,OAAe,EAAE,OAAsB;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAoB,CAAC;QAC9E,OAAO,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxC,CAAC;IAED,aAAa,CAAC,OAAe;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAU,CAAC;QAC1D,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,CAAC,OAAe,EAAE,OAAsB;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,OAAO,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;IAC5B,CAAC;CACF"}