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.
- package/AGENTS.md +0 -4
- package/CHANGELOG.md +81 -0
- package/LICENSE +21 -0
- package/README.md +145 -55
- package/USER-GUIDE.md +505 -0
- package/bin/kortext.js +23 -0
- package/bin/kortext.ts +377 -0
- package/dist/bin/kortext.js +346 -0
- package/dist/bin/kortext.js.map +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.js +553 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/sse.js +38 -0
- package/dist/mcp/sse.js.map +1 -0
- package/dist/mcp/stdio.js +44 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/server/cli/cleanup.js +73 -0
- package/dist/server/cli/cleanup.js.map +1 -0
- package/dist/server/cli/commands.js +73 -0
- package/dist/server/cli/commands.js.map +1 -0
- package/dist/server/cli/doctor.js +118 -0
- package/dist/server/cli/doctor.js.map +1 -0
- package/dist/server/cli/executor-factory.js +39 -0
- package/dist/server/cli/executor-factory.js.map +1 -0
- package/dist/server/cli/init.js +121 -0
- package/dist/server/cli/init.js.map +1 -0
- package/dist/server/cli/logs.js +28 -0
- package/dist/server/cli/logs.js.map +1 -0
- package/dist/server/cli/serve.js +72 -0
- package/dist/server/cli/serve.js.map +1 -0
- package/dist/server/config/env.js +12 -0
- package/dist/server/config/env.js.map +1 -0
- package/dist/server/db/client.js +32 -0
- package/dist/server/db/client.js.map +1 -0
- package/dist/server/db/json.js +21 -0
- package/dist/server/db/json.js.map +1 -0
- package/dist/server/db/migrate.js +70 -0
- package/dist/server/db/migrate.js.map +1 -0
- package/dist/server/db/migrations/001_init.sql +243 -0
- package/dist/server/db/repositories/audit-log.js +58 -0
- package/dist/server/db/repositories/audit-log.js.map +1 -0
- package/dist/server/db/repositories/backlog.js +96 -0
- package/dist/server/db/repositories/backlog.js.map +1 -0
- package/dist/server/db/repositories/contexts.js +54 -0
- package/dist/server/db/repositories/contexts.js.map +1 -0
- package/dist/server/db/repositories/decisions.js +71 -0
- package/dist/server/db/repositories/decisions.js.map +1 -0
- package/dist/server/db/repositories/handovers.js +53 -0
- package/dist/server/db/repositories/handovers.js.map +1 -0
- package/dist/server/db/repositories/index.js +30 -0
- package/dist/server/db/repositories/index.js.map +1 -0
- package/dist/server/db/repositories/locks.js +59 -0
- package/dist/server/db/repositories/locks.js.map +1 -0
- package/dist/server/db/repositories/notifications.js +63 -0
- package/dist/server/db/repositories/notifications.js.map +1 -0
- package/dist/server/db/repositories/pending-questions.js +63 -0
- package/dist/server/db/repositories/pending-questions.js.map +1 -0
- package/dist/server/db/repositories/runs.js +138 -0
- package/dist/server/db/repositories/runs.js.map +1 -0
- package/dist/server/db/repositories/runtime-artifacts.js +39 -0
- package/dist/server/db/repositories/runtime-artifacts.js.map +1 -0
- package/dist/server/db/repositories/secrets.js +65 -0
- package/dist/server/db/repositories/secrets.js.map +1 -0
- package/dist/server/db/repositories/sessions.js +48 -0
- package/dist/server/db/repositories/sessions.js.map +1 -0
- package/dist/server/db/schemas.js +308 -0
- package/dist/server/db/schemas.js.map +1 -0
- package/dist/server/engine/consistency.js +25 -0
- package/dist/server/engine/consistency.js.map +1 -0
- package/dist/server/engine/dag.js +86 -0
- package/dist/server/engine/dag.js.map +1 -0
- package/dist/server/engine/executor.js +2 -0
- package/dist/server/engine/executor.js.map +1 -0
- package/dist/server/engine/executors/claude-cli-executor.js +83 -0
- package/dist/server/engine/executors/claude-cli-executor.js.map +1 -0
- package/dist/server/engine/executors/cli-spawn.js +127 -0
- package/dist/server/engine/executors/cli-spawn.js.map +1 -0
- package/dist/server/engine/executors/codex-cli-executor.js +69 -0
- package/dist/server/engine/executors/codex-cli-executor.js.map +1 -0
- package/dist/server/engine/executors/gemini-cli-executor.js +69 -0
- package/dist/server/engine/executors/gemini-cli-executor.js.map +1 -0
- package/dist/server/engine/executors/mock-executor.js +52 -0
- package/dist/server/engine/executors/mock-executor.js.map +1 -0
- package/dist/server/engine/executors/persona-routed-executor.js +17 -0
- package/dist/server/engine/executors/persona-routed-executor.js.map +1 -0
- package/dist/server/engine/gate-enforcer.js +75 -0
- package/dist/server/engine/gate-enforcer.js.map +1 -0
- package/dist/server/engine/git-commit.js +42 -0
- package/dist/server/engine/git-commit.js.map +1 -0
- package/dist/server/engine/handover.js +120 -0
- package/dist/server/engine/handover.js.map +1 -0
- package/dist/server/engine/item-lifecycle.js +74 -0
- package/dist/server/engine/item-lifecycle.js.map +1 -0
- package/dist/server/engine/persona-registry.js +108 -0
- package/dist/server/engine/persona-registry.js.map +1 -0
- package/dist/server/engine/worker-pool.js +324 -0
- package/dist/server/engine/worker-pool.js.map +1 -0
- package/dist/server/engine/workflow-loader.js +55 -0
- package/dist/server/engine/workflow-loader.js.map +1 -0
- package/dist/server/engine/workflow-parser.js +158 -0
- package/dist/server/engine/workflow-parser.js.map +1 -0
- package/dist/server/engine/worktree.js +176 -0
- package/dist/server/engine/worktree.js.map +1 -0
- package/dist/server/index.js +99 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/notifications/dispatcher.js +60 -0
- package/dist/server/notifications/dispatcher.js.map +1 -0
- package/dist/server/notifications/slack.js +37 -0
- package/dist/server/notifications/slack.js.map +1 -0
- package/dist/server/notifications/telegram.js +33 -0
- package/dist/server/notifications/telegram.js.map +1 -0
- package/dist/server/orchestrator/approval-queue.js +83 -0
- package/dist/server/orchestrator/approval-queue.js.map +1 -0
- package/dist/server/orchestrator/blueprint-watcher.js +94 -0
- package/dist/server/orchestrator/blueprint-watcher.js.map +1 -0
- package/dist/server/orchestrator/orchestrator.js +283 -0
- package/dist/server/orchestrator/orchestrator.js.map +1 -0
- package/dist/server/orchestrator/pipeline-chainer.js +96 -0
- package/dist/server/orchestrator/pipeline-chainer.js.map +1 -0
- package/dist/server/orchestrator/resume.js +36 -0
- package/dist/server/orchestrator/resume.js.map +1 -0
- package/dist/server/routes/approvals.js +52 -0
- package/dist/server/routes/approvals.js.map +1 -0
- package/dist/server/routes/backlog.js +44 -0
- package/dist/server/routes/backlog.js.map +1 -0
- package/dist/server/routes/db-info.js +21 -0
- package/dist/server/routes/db-info.js.map +1 -0
- package/dist/server/routes/docs.js +70 -0
- package/dist/server/routes/docs.js.map +1 -0
- package/dist/server/routes/doctor.js +19 -0
- package/dist/server/routes/doctor.js.map +1 -0
- package/dist/server/routes/handovers.js +25 -0
- package/dist/server/routes/handovers.js.map +1 -0
- package/dist/server/routes/health.js +11 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/personas.js +96 -0
- package/dist/server/routes/personas.js.map +1 -0
- package/dist/server/routes/runs.js +41 -0
- package/dist/server/routes/runs.js.map +1 -0
- package/dist/server/routes/workflows.js +38 -0
- package/dist/server/routes/workflows.js.map +1 -0
- package/dist/server/safety/harmful-output-filter.js +40 -0
- package/dist/server/safety/harmful-output-filter.js.map +1 -0
- package/dist/server/safety/secret-scanner.js +169 -0
- package/dist/server/safety/secret-scanner.js.map +1 -0
- package/dist/server/services/markdown-sync.js +101 -0
- package/dist/server/services/markdown-sync.js.map +1 -0
- package/dist/web/assets/index-B80d5ZPZ.js +75 -0
- package/dist/web/assets/index-B80d5ZPZ.js.map +1 -0
- package/dist/web/assets/index-Bge5Gzqv.css +1 -0
- package/dist/web/index.html +13 -0
- package/docs/architecture.md +413 -0
- package/package.json +83 -11
- package/scripts/copy-migrations.mjs +29 -0
- package/workspace/.locks/workspace_handover.md.lock +3 -0
- package/hooks/audit-logger.sh +0 -25
- package/hooks/auto-locker.sh +0 -74
- package/hooks/auto-unlocker.sh +0 -17
- package/hooks/backlog-sync-guard.sh +0 -12
- package/hooks/branch-guard.sh +0 -32
- package/hooks/commit-msg-guard.sh +0 -43
- package/hooks/git-pre-commit.sh +0 -76
- package/hooks/git-pre-push.sh +0 -17
- package/hooks/handover-guard.sh +0 -33
- package/hooks/kortext-init.sh +0 -194
- package/hooks/kortext-lib.sh +0 -151
- package/hooks/lint-guard.sh +0 -50
- package/hooks/secret-scanner.sh +0 -89
- package/hooks/size-guard.sh +0 -48
- package/hooks/snapshot-guard.sh +0 -39
- package/hooks/write-guard.sh +0 -77
- package/scripts/kortext-backlog-add.py +0 -123
- package/scripts/kortext-backlog-health.py +0 -112
- package/scripts/kortext-backlog-sync.py +0 -117
- package/scripts/kortext-bulk-plan.py +0 -63
- package/scripts/kortext-cli.py +0 -376
- package/scripts/kortext-consistency-check.py +0 -74
- package/scripts/kortext-context-check.py +0 -146
- package/scripts/kortext-handover.py +0 -107
- package/scripts/kortext-item-check.py +0 -61
- package/scripts/kortext-item-start.py +0 -70
- package/scripts/kortext-item-transition.py +0 -78
- package/scripts/kortext-lock.py +0 -174
- package/scripts/kortext-session-start.py +0 -127
- package/scripts/lock_kortext.sh +0 -34
- package/settings/.claude-settings.template.json +0 -48
- package/settings/CHANGELOG.md +0 -176
- package/settings/INTEGRATION-MAP.md +0 -276
- package/settings/README.md +0 -255
- package/settings/USER-GUIDE.md +0 -502
- package/settings/VERSION +0 -1
- package/settings/config.md +0 -8
- package/settings/runtime-adapters.md +0 -104
- package/skills/backend-developer/.gitkeep +0 -0
- package/skills/compliance-expert/.gitkeep +0 -0
- package/skills/copywriter/.gitkeep +0 -0
- package/skills/db-admin/.gitkeep +0 -0
- package/skills/delivery-manager/.gitkeep +0 -0
- package/skills/designer/.gitkeep +0 -0
- package/skills/devops-engineer/.gitkeep +0 -0
- package/skills/engineering-manager/.gitkeep +0 -0
- package/skills/frontend-developer/.gitkeep +0 -0
- package/skills/growth-expert/.gitkeep +0 -0
- package/skills/operation-manager/.gitkeep +0 -0
- package/skills/product-manager/.gitkeep +0 -0
- package/skills/qa-engineer/.gitkeep +0 -0
- 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":"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"}
|
|
@@ -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"}
|