@jigyasudham/veto 0.8.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/.claude/settings.local.json +9 -0
- package/README.md +190 -0
- package/dist/adapters/claude.js +57 -0
- package/dist/adapters/codex.js +58 -0
- package/dist/adapters/gemini.js +58 -0
- package/dist/adapters/index.js +156 -0
- package/dist/agents/development/api.js +116 -0
- package/dist/agents/development/backend.js +82 -0
- package/dist/agents/development/coder.js +207 -0
- package/dist/agents/development/database.js +81 -0
- package/dist/agents/development/debugger.js +234 -0
- package/dist/agents/development/devops.js +84 -0
- package/dist/agents/development/frontend.js +83 -0
- package/dist/agents/development/migration.js +141 -0
- package/dist/agents/development/performance.js +142 -0
- package/dist/agents/development/refactor.js +85 -0
- package/dist/agents/development/reviewer.js +260 -0
- package/dist/agents/development/tester.js +143 -0
- package/dist/agents/executor.js +144 -0
- package/dist/agents/memory/context-manager.js +167 -0
- package/dist/agents/memory/decision-logger.js +157 -0
- package/dist/agents/memory/knowledge-base.js +120 -0
- package/dist/agents/memory/pattern-learner.js +140 -0
- package/dist/agents/memory/project-mapper.js +114 -0
- package/dist/agents/quality/accessibility.js +89 -0
- package/dist/agents/quality/code-quality.js +109 -0
- package/dist/agents/quality/compatibility.js +55 -0
- package/dist/agents/quality/documentation.js +95 -0
- package/dist/agents/quality/error-handling.js +87 -0
- package/dist/agents/research/competitor-analyzer.js +44 -0
- package/dist/agents/research/cost-analyzer.js +51 -0
- package/dist/agents/research/estimator.js +57 -0
- package/dist/agents/research/ethics-bias.js +111 -0
- package/dist/agents/research/researcher.js +112 -0
- package/dist/agents/research/risk-assessor.js +61 -0
- package/dist/agents/research/tech-advisor.js +52 -0
- package/dist/agents/security/auth.js +269 -0
- package/dist/agents/security/dependency-audit.js +273 -0
- package/dist/agents/security/penetration.js +245 -0
- package/dist/agents/security/privacy.js +259 -0
- package/dist/agents/security/scanner.js +288 -0
- package/dist/agents/security/secrets.js +212 -0
- package/dist/agents/types.js +2 -0
- package/dist/agents/workflow/automation.js +56 -0
- package/dist/agents/workflow/file-manager.js +49 -0
- package/dist/agents/workflow/git-agent.js +52 -0
- package/dist/agents/workflow/reporter.js +48 -0
- package/dist/agents/workflow/search-agent.js +39 -0
- package/dist/agents/workflow/task-coordinator.js +40 -0
- package/dist/agents/workflow/task-planner.js +46 -0
- package/dist/cli.js +132 -0
- package/dist/council/decision-engine.js +136 -0
- package/dist/council/devil-advocate.js +106 -0
- package/dist/council/index.js +37 -0
- package/dist/council/lead-developer.js +108 -0
- package/dist/council/legal-compliance.js +142 -0
- package/dist/council/product-manager.js +92 -0
- package/dist/council/security.js +162 -0
- package/dist/council/system-architect.js +122 -0
- package/dist/council/types.js +2 -0
- package/dist/council/ux-designer.js +109 -0
- package/dist/memory/local.js +182 -0
- package/dist/memory/schema.js +116 -0
- package/dist/memory/sync.js +199 -0
- package/dist/router/complexity-scorer.js +78 -0
- package/dist/router/context-compressor.js +58 -0
- package/dist/router/index.js +29 -0
- package/dist/router/learning-updater.js +186 -0
- package/dist/router/model-selector.js +51 -0
- package/dist/router/rate-monitor.js +73 -0
- package/dist/server.js +949 -0
- package/dist/skills/development/skill-api-design.js +313 -0
- package/dist/skills/development/skill-auth.js +255 -0
- package/dist/skills/development/skill-ci-cd.js +2 -0
- package/dist/skills/development/skill-crud.js +193 -0
- package/dist/skills/development/skill-db-schema.js +2 -0
- package/dist/skills/development/skill-docker.js +2 -0
- package/dist/skills/development/skill-env-setup.js +2 -0
- package/dist/skills/development/skill-scaffold.js +299 -0
- package/dist/skills/intelligence/skill-complexity-score.js +66 -0
- package/dist/skills/intelligence/skill-cost-track.js +36 -0
- package/dist/skills/intelligence/skill-learning-loop.js +66 -0
- package/dist/skills/intelligence/skill-pattern-detect.js +35 -0
- package/dist/skills/intelligence/skill-rate-watch.js +58 -0
- package/dist/skills/memory/skill-context-compress.js +82 -0
- package/dist/skills/memory/skill-cross-sync.js +88 -0
- package/dist/skills/memory/skill-decision-log.js +103 -0
- package/dist/skills/memory/skill-session-restore.js +44 -0
- package/dist/skills/memory/skill-session-save.js +78 -0
- package/dist/skills/quality/skill-accessibility.js +2 -0
- package/dist/skills/quality/skill-code-review.js +60 -0
- package/dist/skills/quality/skill-docs-gen.js +2 -0
- package/dist/skills/quality/skill-perf-audit.js +2 -0
- package/dist/skills/quality/skill-security-scan.js +67 -0
- package/dist/skills/quality/skill-test-suite.js +274 -0
- package/dist/skills/workflow/skill-deploy.js +2 -0
- package/dist/skills/workflow/skill-git-workflow.js +2 -0
- package/dist/skills/workflow/skill-rollback.js +2 -0
- package/dist/skills/workflow/skill-task-breakdown.js +2 -0
- package/package.json +30 -0
- package/src/adapters/claude.ts +70 -0
- package/src/adapters/codex.ts +71 -0
- package/src/adapters/gemini.ts +71 -0
- package/src/adapters/index.ts +217 -0
- package/src/agents/development/api.ts +120 -0
- package/src/agents/development/backend.ts +85 -0
- package/src/agents/development/coder.ts +213 -0
- package/src/agents/development/database.ts +83 -0
- package/src/agents/development/debugger.ts +238 -0
- package/src/agents/development/devops.ts +86 -0
- package/src/agents/development/frontend.ts +85 -0
- package/src/agents/development/migration.ts +144 -0
- package/src/agents/development/performance.ts +144 -0
- package/src/agents/development/refactor.ts +86 -0
- package/src/agents/development/reviewer.ts +268 -0
- package/src/agents/development/tester.ts +151 -0
- package/src/agents/executor.ts +158 -0
- package/src/agents/memory/context-manager.ts +171 -0
- package/src/agents/memory/decision-logger.ts +160 -0
- package/src/agents/memory/knowledge-base.ts +124 -0
- package/src/agents/memory/pattern-learner.ts +143 -0
- package/src/agents/memory/project-mapper.ts +118 -0
- package/src/agents/quality/accessibility.ts +99 -0
- package/src/agents/quality/code-quality.ts +115 -0
- package/src/agents/quality/compatibility.ts +58 -0
- package/src/agents/quality/documentation.ts +105 -0
- package/src/agents/quality/error-handling.ts +96 -0
- package/src/agents/research/competitor-analyzer.ts +45 -0
- package/src/agents/research/cost-analyzer.ts +54 -0
- package/src/agents/research/estimator.ts +60 -0
- package/src/agents/research/ethics-bias.ts +113 -0
- package/src/agents/research/researcher.ts +114 -0
- package/src/agents/research/risk-assessor.ts +63 -0
- package/src/agents/research/tech-advisor.ts +55 -0
- package/src/agents/security/auth.ts +287 -0
- package/src/agents/security/dependency-audit.ts +337 -0
- package/src/agents/security/penetration.ts +262 -0
- package/src/agents/security/privacy.ts +285 -0
- package/src/agents/security/scanner.ts +322 -0
- package/src/agents/security/secrets.ts +249 -0
- package/src/agents/types.ts +66 -0
- package/src/agents/workflow/automation.ts +59 -0
- package/src/agents/workflow/file-manager.ts +52 -0
- package/src/agents/workflow/git-agent.ts +55 -0
- package/src/agents/workflow/reporter.ts +51 -0
- package/src/agents/workflow/search-agent.ts +40 -0
- package/src/agents/workflow/task-coordinator.ts +41 -0
- package/src/agents/workflow/task-planner.ts +47 -0
- package/src/cli.ts +143 -0
- package/src/council/decision-engine.ts +171 -0
- package/src/council/devil-advocate.ts +116 -0
- package/src/council/index.ts +44 -0
- package/src/council/lead-developer.ts +118 -0
- package/src/council/legal-compliance.ts +152 -0
- package/src/council/product-manager.ts +102 -0
- package/src/council/security.ts +172 -0
- package/src/council/system-architect.ts +132 -0
- package/src/council/types.ts +33 -0
- package/src/council/ux-designer.ts +121 -0
- package/src/memory/local.ts +305 -0
- package/src/memory/schema.ts +174 -0
- package/src/memory/sync.ts +274 -0
- package/src/router/complexity-scorer.ts +96 -0
- package/src/router/context-compressor.ts +74 -0
- package/src/router/index.ts +60 -0
- package/src/router/learning-updater.ts +271 -0
- package/src/router/model-selector.ts +83 -0
- package/src/router/rate-monitor.ts +103 -0
- package/src/server.ts +1038 -0
- package/src/skills/development/skill-api-design.ts +329 -0
- package/src/skills/development/skill-auth.ts +271 -0
- package/src/skills/development/skill-ci-cd.ts +0 -0
- package/src/skills/development/skill-crud.ts +209 -0
- package/src/skills/development/skill-db-schema.ts +0 -0
- package/src/skills/development/skill-docker.ts +0 -0
- package/src/skills/development/skill-env-setup.ts +0 -0
- package/src/skills/development/skill-scaffold.ts +323 -0
- package/src/skills/intelligence/skill-complexity-score.ts +69 -0
- package/src/skills/intelligence/skill-cost-track.ts +39 -0
- package/src/skills/intelligence/skill-learning-loop.ts +69 -0
- package/src/skills/intelligence/skill-pattern-detect.ts +38 -0
- package/src/skills/intelligence/skill-rate-watch.ts +61 -0
- package/src/skills/memory/skill-context-compress.ts +98 -0
- package/src/skills/memory/skill-cross-sync.ts +104 -0
- package/src/skills/memory/skill-decision-log.ts +119 -0
- package/src/skills/memory/skill-session-restore.ts +59 -0
- package/src/skills/memory/skill-session-save.ts +94 -0
- package/src/skills/quality/skill-accessibility.ts +0 -0
- package/src/skills/quality/skill-code-review.ts +84 -0
- package/src/skills/quality/skill-docs-gen.ts +0 -0
- package/src/skills/quality/skill-perf-audit.ts +0 -0
- package/src/skills/quality/skill-security-scan.ts +91 -0
- package/src/skills/quality/skill-test-suite.ts +290 -0
- package/src/skills/workflow/skill-deploy.ts +0 -0
- package/src/skills/workflow/skill-git-workflow.ts +0 -0
- package/src/skills/workflow/skill-rollback.ts +0 -0
- package/src/skills/workflow/skill-task-breakdown.ts +0 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Backend-only tasks: UX approves without friction
|
|
2
|
+
const BACKEND_ONLY = /\b(api|backend|server|database|db|query|schema|migration|auth.*middleware|jwt|oauth|cron|cli|script|worker|queue|cache|redis|sql|index|trigger|webhook)\b/i;
|
|
3
|
+
const FRONTEND_SIGNALS = /\b(ui|ux|form|button|modal|page|screen|component|view|layout|menu|nav|input|field|label|error.?message|loading|user.?interface|frontend|react|vue|svelte|html|css)\b/i;
|
|
4
|
+
const BLOCK_RULES = [
|
|
5
|
+
{
|
|
6
|
+
pattern: /window\.alert\s*\(|window\.confirm\s*\(/i,
|
|
7
|
+
reason: 'window.alert/confirm blocks the page and cannot be styled. Users hate it.',
|
|
8
|
+
recommendation: 'Replace with toast notifications (react-hot-toast) or inline dialogs.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
pattern: /no.{0,20}error.{0,20}(message|state|feedback).{0,30}(form|submit|input)/i,
|
|
12
|
+
reason: 'Forms without error feedback leave users confused and drive support tickets.',
|
|
13
|
+
recommendation: 'Add inline validation messages for every field that can fail.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
pattern: /(?:7|8|9|10|eleven|twelve).{0,15}step/i,
|
|
17
|
+
reason: 'More than 6 steps in a flow loses 70%+ of users before completion.',
|
|
18
|
+
recommendation: 'Break into smaller flows or use progressive disclosure.',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
const WARN_RULES = [
|
|
22
|
+
{
|
|
23
|
+
pattern: /no.{0,15}(mobile|responsive|viewport)/i,
|
|
24
|
+
concern: '60%+ of users are on mobile. Responsive is baseline, not a bonus.',
|
|
25
|
+
recommendation: 'Mobile-first CSS. Test breakpoints: 375px, 768px, 1280px.',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
pattern: /no.{0,15}(loading|spinner|progress|skeleton)/i,
|
|
29
|
+
concern: 'Missing loading state — users cannot tell if their action registered.',
|
|
30
|
+
recommendation: 'Show loading indicator for any operation that takes >300ms.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
pattern: /\bmodal\b|\bpopup\b|\bdialog\b/i,
|
|
34
|
+
concern: 'Modals interrupt flow and fail on small screens. Use sparingly.',
|
|
35
|
+
recommendation: 'Reserve modals for destructive confirmations only. Use inline for everything else.',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
pattern: /no.{0,15}(accessib|aria|a11y|wcag)/i,
|
|
39
|
+
concern: 'Missing accessibility — 15% of users cannot use the product.',
|
|
40
|
+
recommendation: 'Add aria-labels, keyboard nav, focus management. Test with VoiceOver.',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
pattern: /color.{0,20}only|rely.{0,15}on.{0,15}color/i,
|
|
44
|
+
concern: '8% of users are colorblind — color-only signals are invisible to them.',
|
|
45
|
+
recommendation: 'Add icons, patterns, or text alongside color to convey meaning.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pattern: /no.{0,15}(empty.?state|zero.?state|first.?time)/i,
|
|
49
|
+
concern: 'No empty state — first-time users see a blank screen that looks broken.',
|
|
50
|
+
recommendation: 'Design empty state that explains what goes here and how to start.',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
pattern: /no.{0,15}(confirm|confirmation|undo|undo.?redo)/i,
|
|
54
|
+
concern: 'Destructive action without confirmation leads to user data loss.',
|
|
55
|
+
recommendation: 'Add confirmation dialog for destructive actions. Provide undo where possible.',
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
pattern: /auto.?submit|submit.{0,10}without.{0,10}(confirm|review)/i,
|
|
59
|
+
concern: 'Auto-submitting without user review removes user agency.',
|
|
60
|
+
recommendation: 'Always let users review before final submission.',
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
const TRIVIAL = /^(rename|fix typo|reorder|reformat|format|update comment|add comment)\b/i;
|
|
64
|
+
export function analyze(task) {
|
|
65
|
+
if (TRIVIAL.test(task.trim())) {
|
|
66
|
+
return { verdict: 'approve', reason: 'Trivial change — no UX concerns.', concerns: [] };
|
|
67
|
+
}
|
|
68
|
+
// Pure backend tasks get a light pass
|
|
69
|
+
const isBackend = BACKEND_ONLY.test(task) && !FRONTEND_SIGNALS.test(task);
|
|
70
|
+
if (isBackend) {
|
|
71
|
+
return {
|
|
72
|
+
verdict: 'approve',
|
|
73
|
+
reason: 'Backend task — no direct UX concerns. Ensure API errors surface clearly to users.',
|
|
74
|
+
concerns: [],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const blocks = [];
|
|
78
|
+
const concerns = [];
|
|
79
|
+
const recommendations = [];
|
|
80
|
+
for (const rule of BLOCK_RULES) {
|
|
81
|
+
if (rule.pattern.test(task)) {
|
|
82
|
+
blocks.push({ reason: rule.reason, recommendation: rule.recommendation });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
for (const rule of WARN_RULES) {
|
|
86
|
+
if (rule.pattern.test(task)) {
|
|
87
|
+
concerns.push(rule.concern);
|
|
88
|
+
recommendations.push(rule.recommendation);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (blocks.length > 0) {
|
|
92
|
+
return {
|
|
93
|
+
verdict: 'block',
|
|
94
|
+
reason: blocks[0].reason,
|
|
95
|
+
concerns: blocks.slice(1).map(b => b.reason),
|
|
96
|
+
recommendation: blocks.map(b => b.recommendation).join(' | '),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
if (concerns.length > 0) {
|
|
100
|
+
return {
|
|
101
|
+
verdict: 'warn',
|
|
102
|
+
reason: `${concerns.length} UX concern${concerns.length > 1 ? 's' : ''} — real users will notice this.`,
|
|
103
|
+
concerns,
|
|
104
|
+
recommendation: recommendations[0],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return { verdict: 'approve', reason: 'UX looks solid. No user experience concerns.', concerns: [] };
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=ux-designer.js.map
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// Local SQLite memory — all operations for session save/restore
|
|
2
|
+
// Uses Node.js built-in node:sqlite (Node 22.5+, no native compilation needed)
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
import { mkdirSync } from 'node:fs';
|
|
8
|
+
import { CREATE_TABLES } from './schema.js';
|
|
9
|
+
const VETO_DIR = join(homedir(), '.veto');
|
|
10
|
+
const DB_PATH = join(VETO_DIR, 'veto.db');
|
|
11
|
+
let _db = null;
|
|
12
|
+
export function getDb() {
|
|
13
|
+
if (_db)
|
|
14
|
+
return _db;
|
|
15
|
+
mkdirSync(VETO_DIR, { recursive: true });
|
|
16
|
+
_db = new DatabaseSync(DB_PATH);
|
|
17
|
+
_db.exec('PRAGMA journal_mode = WAL');
|
|
18
|
+
_db.exec('PRAGMA foreign_keys = ON');
|
|
19
|
+
_db.exec(CREATE_TABLES);
|
|
20
|
+
migrateCouncilOutcomes(_db);
|
|
21
|
+
migrateCouncilColumns(_db);
|
|
22
|
+
return _db;
|
|
23
|
+
}
|
|
24
|
+
// Adds legal and security columns if they don't exist (Phase 3 → Phase 3.1 migration)
|
|
25
|
+
function migrateCouncilColumns(db) {
|
|
26
|
+
const cols = db.prepare('PRAGMA table_info(council_outcomes)').all();
|
|
27
|
+
const names = new Set(cols.map(c => c.name));
|
|
28
|
+
if (!names.has('legal'))
|
|
29
|
+
db.exec('ALTER TABLE council_outcomes ADD COLUMN legal TEXT');
|
|
30
|
+
if (!names.has('security'))
|
|
31
|
+
db.exec('ALTER TABLE council_outcomes ADD COLUMN security TEXT');
|
|
32
|
+
}
|
|
33
|
+
// Migrates council_outcomes if it was created with NOT NULL session_id (Phase 1/2 schema)
|
|
34
|
+
function migrateCouncilOutcomes(db) {
|
|
35
|
+
const cols = db.prepare('PRAGMA table_info(council_outcomes)').all();
|
|
36
|
+
const col = cols.find(c => c.name === 'session_id');
|
|
37
|
+
if (!col || col.notnull !== 1)
|
|
38
|
+
return;
|
|
39
|
+
db.exec(`
|
|
40
|
+
CREATE TABLE IF NOT EXISTS _council_outcomes_new (
|
|
41
|
+
id TEXT PRIMARY KEY, session_id TEXT, task TEXT NOT NULL,
|
|
42
|
+
verdict TEXT NOT NULL, lead_dev TEXT, pm TEXT, architect TEXT,
|
|
43
|
+
ux TEXT, devil TEXT, recommended TEXT, debated_at TEXT NOT NULL
|
|
44
|
+
);
|
|
45
|
+
INSERT OR IGNORE INTO _council_outcomes_new SELECT * FROM council_outcomes;
|
|
46
|
+
DROP TABLE council_outcomes;
|
|
47
|
+
ALTER TABLE _council_outcomes_new RENAME TO council_outcomes;
|
|
48
|
+
`);
|
|
49
|
+
}
|
|
50
|
+
export function saveSession(input) {
|
|
51
|
+
const db = getDb();
|
|
52
|
+
const id = randomUUID();
|
|
53
|
+
const now = new Date().toISOString();
|
|
54
|
+
const stmt = db.prepare(`
|
|
55
|
+
INSERT INTO sessions (id, started_at, platform, project_dir, summary, context, task_state, token_count)
|
|
56
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
57
|
+
`);
|
|
58
|
+
stmt.run(id, now, input.platform ?? 'claude', input.project_dir ?? null, input.summary ?? null, input.context ? JSON.stringify(input.context) : null, input.task_state ? JSON.stringify(input.task_state) : null, input.token_count ?? 0);
|
|
59
|
+
return { session_id: id, saved_at: now };
|
|
60
|
+
}
|
|
61
|
+
export function restoreSession(session_id) {
|
|
62
|
+
const db = getDb();
|
|
63
|
+
const row = db.prepare('SELECT * FROM sessions WHERE id = ?').get(session_id);
|
|
64
|
+
if (!row)
|
|
65
|
+
return { found: false };
|
|
66
|
+
return { found: true, session: row };
|
|
67
|
+
}
|
|
68
|
+
export function listSessions(limit = 10) {
|
|
69
|
+
const db = getDb();
|
|
70
|
+
return db.prepare('SELECT * FROM sessions ORDER BY created_at DESC LIMIT ?').all(limit);
|
|
71
|
+
}
|
|
72
|
+
export function closeSession(session_id) {
|
|
73
|
+
const db = getDb();
|
|
74
|
+
db.prepare('UPDATE sessions SET ended_at = ? WHERE id = ?')
|
|
75
|
+
.run(new Date().toISOString(), session_id);
|
|
76
|
+
}
|
|
77
|
+
export function getDbPath() {
|
|
78
|
+
return DB_PATH;
|
|
79
|
+
}
|
|
80
|
+
export function saveCouncilOutcome(input) {
|
|
81
|
+
const db = getDb();
|
|
82
|
+
const id = randomUUID();
|
|
83
|
+
const now = new Date().toISOString();
|
|
84
|
+
db.prepare(`
|
|
85
|
+
INSERT INTO council_outcomes
|
|
86
|
+
(id, session_id, task, verdict, lead_dev, pm, architect, ux, devil, legal, security, recommended, debated_at)
|
|
87
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
88
|
+
`).run(id, input.session_id ?? null, input.task, input.verdict, input.lead_dev, input.pm, input.architect, input.ux, input.devil, input.legal, input.security, input.recommended, now);
|
|
89
|
+
return id;
|
|
90
|
+
}
|
|
91
|
+
export function storeKnowledge(input) {
|
|
92
|
+
const db = getDb();
|
|
93
|
+
const id = randomUUID();
|
|
94
|
+
const now = new Date().toISOString();
|
|
95
|
+
db.prepare(`
|
|
96
|
+
INSERT INTO knowledge_base (id, type, title, content, tags, project_dir, session_id, relevance, created_at, updated_at)
|
|
97
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
98
|
+
`).run(id, input.type ?? 'solution', input.title, input.content, input.tags ? JSON.stringify(input.tags) : null, input.project_dir ?? null, input.session_id ?? null, input.relevance ?? 1.0, now, now);
|
|
99
|
+
return id;
|
|
100
|
+
}
|
|
101
|
+
export function searchKnowledge(opts) {
|
|
102
|
+
const db = getDb();
|
|
103
|
+
const limit = Math.min(opts.limit ?? 10, 50);
|
|
104
|
+
const conditions = [];
|
|
105
|
+
const params = [];
|
|
106
|
+
if (opts.query) {
|
|
107
|
+
conditions.push('(title LIKE ? OR content LIKE ?)');
|
|
108
|
+
const q = `%${opts.query}%`;
|
|
109
|
+
params.push(q, q);
|
|
110
|
+
}
|
|
111
|
+
if (opts.type) {
|
|
112
|
+
conditions.push('type = ?');
|
|
113
|
+
params.push(opts.type);
|
|
114
|
+
}
|
|
115
|
+
if (opts.project_dir) {
|
|
116
|
+
conditions.push('project_dir = ?');
|
|
117
|
+
params.push(opts.project_dir);
|
|
118
|
+
}
|
|
119
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
120
|
+
const rows = db.prepare(`SELECT * FROM knowledge_base ${where} ORDER BY relevance DESC, accessed_count DESC, created_at DESC LIMIT ?`).all(...params, limit);
|
|
121
|
+
if (rows.length > 0 && opts.query) {
|
|
122
|
+
const ids = rows.map(r => `'${r.id}'`).join(',');
|
|
123
|
+
db.exec(`UPDATE knowledge_base SET accessed_count = accessed_count + 1 WHERE id IN (${ids})`);
|
|
124
|
+
}
|
|
125
|
+
return rows;
|
|
126
|
+
}
|
|
127
|
+
export function deleteKnowledge(id) {
|
|
128
|
+
const db = getDb();
|
|
129
|
+
const result = db.prepare('DELETE FROM knowledge_base WHERE id = ?').run(id);
|
|
130
|
+
return result.changes > 0;
|
|
131
|
+
}
|
|
132
|
+
export function updateProjectMap(input) {
|
|
133
|
+
const db = getDb();
|
|
134
|
+
const now = new Date().toISOString();
|
|
135
|
+
const existing = db.prepare('SELECT id FROM project_map WHERE project_dir = ?').get(input.project_dir);
|
|
136
|
+
const structure = typeof input.structure === 'string' ? input.structure : JSON.stringify(input.structure);
|
|
137
|
+
const key_modules = input.key_modules ? JSON.stringify(input.key_modules) : null;
|
|
138
|
+
const tech_stack = input.tech_stack ? JSON.stringify(input.tech_stack) : null;
|
|
139
|
+
if (existing) {
|
|
140
|
+
db.prepare(`
|
|
141
|
+
UPDATE project_map SET structure = ?, key_modules = ?, tech_stack = ?, updated_at = ?
|
|
142
|
+
WHERE project_dir = ?
|
|
143
|
+
`).run(structure, key_modules, tech_stack, now, input.project_dir);
|
|
144
|
+
return existing.id;
|
|
145
|
+
}
|
|
146
|
+
const id = randomUUID();
|
|
147
|
+
db.prepare(`
|
|
148
|
+
INSERT INTO project_map (id, project_dir, structure, key_modules, tech_stack, updated_at)
|
|
149
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
150
|
+
`).run(id, input.project_dir, structure, key_modules, tech_stack, now);
|
|
151
|
+
return id;
|
|
152
|
+
}
|
|
153
|
+
export function getProjectMap(project_dir) {
|
|
154
|
+
const db = getDb();
|
|
155
|
+
return db.prepare('SELECT * FROM project_map WHERE project_dir = ?').get(project_dir);
|
|
156
|
+
}
|
|
157
|
+
export function upsertPattern(input) {
|
|
158
|
+
const db = getDb();
|
|
159
|
+
const now = new Date().toISOString();
|
|
160
|
+
const existing = db.prepare('SELECT id, seen_count, confidence FROM patterns WHERE pattern_key = ?').get(input.pattern_key);
|
|
161
|
+
if (existing) {
|
|
162
|
+
const newConfidence = Math.min(1.0, (existing.confidence + (input.confidence ?? 1.0)) / 2);
|
|
163
|
+
db.prepare(`
|
|
164
|
+
UPDATE patterns SET pattern_val = ?, confidence = ?, seen_count = seen_count + 1, updated_at = ?
|
|
165
|
+
WHERE pattern_key = ?
|
|
166
|
+
`).run(input.pattern_val, newConfidence, now, input.pattern_key);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
db.prepare(`
|
|
170
|
+
INSERT INTO patterns (id, pattern_key, pattern_val, confidence, seen_count, updated_at)
|
|
171
|
+
VALUES (?, ?, ?, ?, 1, ?)
|
|
172
|
+
`).run(randomUUID(), input.pattern_key, input.pattern_val, input.confidence ?? 1.0, now);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export function getPatterns(prefix, limit = 20) {
|
|
176
|
+
const db = getDb();
|
|
177
|
+
if (prefix) {
|
|
178
|
+
return db.prepare('SELECT * FROM patterns WHERE pattern_key LIKE ? ORDER BY confidence DESC, seen_count DESC LIMIT ?').all(`${prefix}%`, limit);
|
|
179
|
+
}
|
|
180
|
+
return db.prepare('SELECT * FROM patterns ORDER BY confidence DESC, seen_count DESC LIMIT ?').all(limit);
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Database schema definitions for veto.db
|
|
2
|
+
// All tables created on first run — zero setup required
|
|
3
|
+
export const CREATE_TABLES = `
|
|
4
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
5
|
+
id TEXT PRIMARY KEY,
|
|
6
|
+
started_at TEXT NOT NULL,
|
|
7
|
+
ended_at TEXT,
|
|
8
|
+
platform TEXT NOT NULL DEFAULT 'claude',
|
|
9
|
+
project_dir TEXT,
|
|
10
|
+
summary TEXT,
|
|
11
|
+
context TEXT,
|
|
12
|
+
task_state TEXT,
|
|
13
|
+
token_count INTEGER DEFAULT 0,
|
|
14
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
CREATE TABLE IF NOT EXISTS decisions (
|
|
18
|
+
id TEXT PRIMARY KEY,
|
|
19
|
+
session_id TEXT NOT NULL,
|
|
20
|
+
made_at TEXT NOT NULL,
|
|
21
|
+
decision TEXT NOT NULL,
|
|
22
|
+
rationale TEXT,
|
|
23
|
+
council_verdict TEXT,
|
|
24
|
+
files_affected TEXT,
|
|
25
|
+
overridden INTEGER DEFAULT 0,
|
|
26
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id)
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS files_modified (
|
|
30
|
+
id TEXT PRIMARY KEY,
|
|
31
|
+
session_id TEXT NOT NULL,
|
|
32
|
+
file_path TEXT NOT NULL,
|
|
33
|
+
operation TEXT NOT NULL,
|
|
34
|
+
modified_at TEXT NOT NULL,
|
|
35
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE TABLE IF NOT EXISTS council_outcomes (
|
|
39
|
+
id TEXT PRIMARY KEY,
|
|
40
|
+
session_id TEXT,
|
|
41
|
+
task TEXT NOT NULL,
|
|
42
|
+
verdict TEXT NOT NULL,
|
|
43
|
+
lead_dev TEXT,
|
|
44
|
+
pm TEXT,
|
|
45
|
+
architect TEXT,
|
|
46
|
+
ux TEXT,
|
|
47
|
+
devil TEXT,
|
|
48
|
+
legal TEXT,
|
|
49
|
+
security TEXT,
|
|
50
|
+
recommended TEXT,
|
|
51
|
+
debated_at TEXT NOT NULL
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
CREATE TABLE IF NOT EXISTS learning_data (
|
|
55
|
+
id TEXT PRIMARY KEY,
|
|
56
|
+
task_type TEXT NOT NULL,
|
|
57
|
+
complexity INTEGER NOT NULL,
|
|
58
|
+
model_tier INTEGER NOT NULL,
|
|
59
|
+
output_quality INTEGER,
|
|
60
|
+
tokens_used INTEGER,
|
|
61
|
+
agent TEXT,
|
|
62
|
+
recorded_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
CREATE TABLE IF NOT EXISTS patterns (
|
|
66
|
+
id TEXT PRIMARY KEY,
|
|
67
|
+
pattern_key TEXT NOT NULL UNIQUE,
|
|
68
|
+
pattern_val TEXT NOT NULL,
|
|
69
|
+
confidence REAL DEFAULT 1.0,
|
|
70
|
+
seen_count INTEGER DEFAULT 1,
|
|
71
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
CREATE TABLE IF NOT EXISTS rate_usage (
|
|
75
|
+
id TEXT PRIMARY KEY,
|
|
76
|
+
platform TEXT NOT NULL,
|
|
77
|
+
date_key TEXT NOT NULL,
|
|
78
|
+
request_count INTEGER DEFAULT 0,
|
|
79
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
80
|
+
UNIQUE(platform, date_key)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
CREATE TABLE IF NOT EXISTS knowledge_base (
|
|
84
|
+
id TEXT PRIMARY KEY,
|
|
85
|
+
type TEXT NOT NULL DEFAULT 'solution',
|
|
86
|
+
title TEXT NOT NULL,
|
|
87
|
+
content TEXT NOT NULL,
|
|
88
|
+
tags TEXT,
|
|
89
|
+
project_dir TEXT,
|
|
90
|
+
session_id TEXT,
|
|
91
|
+
relevance REAL DEFAULT 1.0,
|
|
92
|
+
accessed_count INTEGER DEFAULT 0,
|
|
93
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
94
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
CREATE TABLE IF NOT EXISTS project_map (
|
|
98
|
+
id TEXT PRIMARY KEY,
|
|
99
|
+
project_dir TEXT NOT NULL UNIQUE,
|
|
100
|
+
structure TEXT NOT NULL,
|
|
101
|
+
key_modules TEXT,
|
|
102
|
+
tech_stack TEXT,
|
|
103
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_platform ON sessions(platform);
|
|
107
|
+
CREATE INDEX IF NOT EXISTS idx_decisions_session ON decisions(session_id);
|
|
108
|
+
CREATE INDEX IF NOT EXISTS idx_files_session ON files_modified(session_id);
|
|
109
|
+
CREATE INDEX IF NOT EXISTS idx_learning_task_type ON learning_data(task_type);
|
|
110
|
+
CREATE INDEX IF NOT EXISTS idx_patterns_key ON patterns(pattern_key);
|
|
111
|
+
CREATE INDEX IF NOT EXISTS idx_rate_usage_platform ON rate_usage(platform, date_key);
|
|
112
|
+
CREATE INDEX IF NOT EXISTS idx_knowledge_type ON knowledge_base(type);
|
|
113
|
+
CREATE INDEX IF NOT EXISTS idx_knowledge_project ON knowledge_base(project_dir);
|
|
114
|
+
CREATE INDEX IF NOT EXISTS idx_project_map_dir ON project_map(project_dir);
|
|
115
|
+
`;
|
|
116
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// Memory export/import — file-based cross-machine continuity
|
|
2
|
+
// No external services. Export to JSON, copy the file, import on another machine.
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
import { getDb, getDbPath } from './local.js';
|
|
7
|
+
const DEFAULT_EXPORT_PATH = join(homedir(), '.veto', 'veto-export.json');
|
|
8
|
+
export function exportMemory(outputPath) {
|
|
9
|
+
const exportPath = outputPath ?? DEFAULT_EXPORT_PATH;
|
|
10
|
+
const db = getDb();
|
|
11
|
+
try {
|
|
12
|
+
const sessions = db.prepare('SELECT * FROM sessions ORDER BY created_at DESC').all();
|
|
13
|
+
const decisions = db.prepare('SELECT * FROM decisions ORDER BY made_at DESC').all();
|
|
14
|
+
const knowledge = db.prepare('SELECT * FROM knowledge_base ORDER BY created_at DESC').all();
|
|
15
|
+
const patterns = db.prepare('SELECT * FROM patterns ORDER BY confidence DESC').all();
|
|
16
|
+
const projectMaps = db.prepare('SELECT * FROM project_map ORDER BY updated_at DESC').all();
|
|
17
|
+
const councilOutcomes = db.prepare('SELECT * FROM council_outcomes ORDER BY debated_at DESC').all();
|
|
18
|
+
const payload = {
|
|
19
|
+
veto_export_version: 1,
|
|
20
|
+
exported_at: new Date().toISOString(),
|
|
21
|
+
db_path: getDbPath(),
|
|
22
|
+
data: {
|
|
23
|
+
sessions,
|
|
24
|
+
decisions,
|
|
25
|
+
knowledge_base: knowledge,
|
|
26
|
+
patterns,
|
|
27
|
+
project_map: projectMaps,
|
|
28
|
+
council_outcomes: councilOutcomes,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
writeFileSync(exportPath, JSON.stringify(payload, null, 2), 'utf-8');
|
|
32
|
+
const exported = {
|
|
33
|
+
sessions: sessions.length,
|
|
34
|
+
decisions: decisions.length,
|
|
35
|
+
knowledge_base: knowledge.length,
|
|
36
|
+
patterns: patterns.length,
|
|
37
|
+
project_map: projectMaps.length,
|
|
38
|
+
council_outcomes: councilOutcomes.length,
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
export_path: exportPath,
|
|
43
|
+
exported,
|
|
44
|
+
exported_at: payload.exported_at,
|
|
45
|
+
next_step: `Copy ${exportPath} to your other machine, then call veto_memory_import with that file path.`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
export_path: exportPath,
|
|
52
|
+
exported: {},
|
|
53
|
+
exported_at: new Date().toISOString(),
|
|
54
|
+
error: err instanceof Error ? err.message : String(err),
|
|
55
|
+
next_step: 'Fix the error above and retry.',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export function importMemory(inputPath) {
|
|
60
|
+
const importPath = inputPath ?? DEFAULT_EXPORT_PATH;
|
|
61
|
+
if (!existsSync(importPath)) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
import_path: importPath,
|
|
65
|
+
merged: {},
|
|
66
|
+
skipped: {},
|
|
67
|
+
imported_at: new Date().toISOString(),
|
|
68
|
+
error: `File not found: ${importPath}. Run veto_memory_export on your other machine first, then copy the file here.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
const db = getDb();
|
|
72
|
+
const merged = {};
|
|
73
|
+
const skipped = {};
|
|
74
|
+
try {
|
|
75
|
+
const raw = readFileSync(importPath, 'utf-8');
|
|
76
|
+
const payload = JSON.parse(raw);
|
|
77
|
+
if (payload.veto_export_version !== 1) {
|
|
78
|
+
throw new Error(`Unknown export version: ${payload.veto_export_version}`);
|
|
79
|
+
}
|
|
80
|
+
const { sessions = [], decisions = [], knowledge_base = [], patterns = [], project_map = [], council_outcomes = [] } = payload.data;
|
|
81
|
+
merged['sessions'] = 0;
|
|
82
|
+
skipped['sessions'] = 0;
|
|
83
|
+
for (const s of sessions) {
|
|
84
|
+
const r = db.prepare(`
|
|
85
|
+
INSERT OR IGNORE INTO sessions
|
|
86
|
+
(id, started_at, ended_at, platform, project_dir, summary, context, task_state, token_count, created_at)
|
|
87
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
88
|
+
`).run(String(s['id'] ?? ''), String(s['started_at'] ?? ''), s['ended_at'] != null ? String(s['ended_at']) : null, String(s['platform'] ?? 'claude'), s['project_dir'] != null ? String(s['project_dir']) : null, s['summary'] != null ? String(s['summary']) : null, s['context'] != null ? String(s['context']) : null, s['task_state'] != null ? String(s['task_state']) : null, typeof s['token_count'] === 'number' ? s['token_count'] : 0, String(s['created_at'] ?? new Date().toISOString()));
|
|
89
|
+
if (r.changes > 0)
|
|
90
|
+
merged['sessions']++;
|
|
91
|
+
else
|
|
92
|
+
skipped['sessions']++;
|
|
93
|
+
}
|
|
94
|
+
merged['decisions'] = 0;
|
|
95
|
+
skipped['decisions'] = 0;
|
|
96
|
+
for (const d of decisions) {
|
|
97
|
+
const r = db.prepare(`
|
|
98
|
+
INSERT OR IGNORE INTO decisions
|
|
99
|
+
(id, session_id, made_at, decision, rationale, council_verdict, files_affected, overridden)
|
|
100
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
101
|
+
`).run(String(d['id'] ?? ''), String(d['session_id'] ?? ''), String(d['made_at'] ?? ''), String(d['decision'] ?? ''), d['rationale'] != null ? String(d['rationale']) : null, d['council_verdict'] != null ? String(d['council_verdict']) : null, d['files_affected'] != null ? String(d['files_affected']) : null, typeof d['overridden'] === 'number' ? d['overridden'] : 0);
|
|
102
|
+
if (r.changes > 0)
|
|
103
|
+
merged['decisions']++;
|
|
104
|
+
else
|
|
105
|
+
skipped['decisions']++;
|
|
106
|
+
}
|
|
107
|
+
merged['knowledge_base'] = 0;
|
|
108
|
+
skipped['knowledge_base'] = 0;
|
|
109
|
+
for (const k of knowledge_base) {
|
|
110
|
+
const r = db.prepare(`
|
|
111
|
+
INSERT OR IGNORE INTO knowledge_base
|
|
112
|
+
(id, type, title, content, tags, project_dir, session_id, relevance, accessed_count, created_at, updated_at)
|
|
113
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
114
|
+
`).run(String(k['id'] ?? ''), k['type'] != null ? String(k['type']) : 'solution', String(k['title'] ?? ''), String(k['content'] ?? ''), k['tags'] != null ? String(k['tags']) : null, k['project_dir'] != null ? String(k['project_dir']) : null, k['session_id'] != null ? String(k['session_id']) : null, typeof k['relevance'] === 'number' ? k['relevance'] : 1.0, typeof k['accessed_count'] === 'number' ? k['accessed_count'] : 0, String(k['created_at'] ?? new Date().toISOString()), String(k['updated_at'] ?? new Date().toISOString()));
|
|
115
|
+
if (r.changes > 0)
|
|
116
|
+
merged['knowledge_base']++;
|
|
117
|
+
else
|
|
118
|
+
skipped['knowledge_base']++;
|
|
119
|
+
}
|
|
120
|
+
merged['patterns'] = 0;
|
|
121
|
+
skipped['patterns'] = 0;
|
|
122
|
+
for (const p of patterns) {
|
|
123
|
+
const existing = db.prepare('SELECT seen_count, confidence FROM patterns WHERE pattern_key = ?').get(String(p['pattern_key'] ?? ''));
|
|
124
|
+
if (existing) {
|
|
125
|
+
// Merge: take higher confidence, sum seen counts
|
|
126
|
+
const mergedConf = Math.max(existing.confidence, typeof p['confidence'] === 'number' ? p['confidence'] : 1.0);
|
|
127
|
+
const mergedCount = existing.seen_count + (typeof p['seen_count'] === 'number' ? p['seen_count'] : 1);
|
|
128
|
+
db.prepare('UPDATE patterns SET confidence = ?, seen_count = ?, updated_at = ? WHERE pattern_key = ?')
|
|
129
|
+
.run(mergedConf, mergedCount, new Date().toISOString(), String(p['pattern_key'] ?? ''));
|
|
130
|
+
skipped['patterns']++;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
db.prepare(`
|
|
134
|
+
INSERT INTO patterns (id, pattern_key, pattern_val, confidence, seen_count, updated_at)
|
|
135
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
136
|
+
`).run(String(p['id'] ?? ''), String(p['pattern_key'] ?? ''), String(p['pattern_val'] ?? ''), typeof p['confidence'] === 'number' ? p['confidence'] : 1.0, typeof p['seen_count'] === 'number' ? p['seen_count'] : 1, String(p['updated_at'] ?? new Date().toISOString()));
|
|
137
|
+
merged['patterns']++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
merged['project_map'] = 0;
|
|
141
|
+
skipped['project_map'] = 0;
|
|
142
|
+
for (const m of project_map) {
|
|
143
|
+
const r = db.prepare(`
|
|
144
|
+
INSERT OR IGNORE INTO project_map (id, project_dir, structure, key_modules, tech_stack, updated_at)
|
|
145
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
146
|
+
`).run(String(m['id'] ?? ''), String(m['project_dir'] ?? ''), String(m['structure'] ?? '{}'), m['key_modules'] != null ? String(m['key_modules']) : null, m['tech_stack'] != null ? String(m['tech_stack']) : null, String(m['updated_at'] ?? new Date().toISOString()));
|
|
147
|
+
if (r.changes > 0)
|
|
148
|
+
merged['project_map']++;
|
|
149
|
+
else
|
|
150
|
+
skipped['project_map']++;
|
|
151
|
+
}
|
|
152
|
+
merged['council_outcomes'] = 0;
|
|
153
|
+
skipped['council_outcomes'] = 0;
|
|
154
|
+
for (const c of council_outcomes) {
|
|
155
|
+
const r = db.prepare(`
|
|
156
|
+
INSERT OR IGNORE INTO council_outcomes
|
|
157
|
+
(id, session_id, task, verdict, lead_dev, pm, architect, ux, devil, legal, security, recommended, debated_at)
|
|
158
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
159
|
+
`).run(String(c['id'] ?? ''), c['session_id'] != null ? String(c['session_id']) : null, String(c['task'] ?? ''), String(c['verdict'] ?? ''), c['lead_dev'] != null ? String(c['lead_dev']) : null, c['pm'] != null ? String(c['pm']) : null, c['architect'] != null ? String(c['architect']) : null, c['ux'] != null ? String(c['ux']) : null, c['devil'] != null ? String(c['devil']) : null, c['legal'] != null ? String(c['legal']) : null, c['security'] != null ? String(c['security']) : null, c['recommended'] != null ? String(c['recommended']) : null, String(c['debated_at'] ?? new Date().toISOString()));
|
|
160
|
+
if (r.changes > 0)
|
|
161
|
+
merged['council_outcomes']++;
|
|
162
|
+
else
|
|
163
|
+
skipped['council_outcomes']++;
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
success: true,
|
|
167
|
+
import_path: importPath,
|
|
168
|
+
merged,
|
|
169
|
+
skipped,
|
|
170
|
+
imported_at: new Date().toISOString(),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
import_path: importPath,
|
|
177
|
+
merged,
|
|
178
|
+
skipped,
|
|
179
|
+
imported_at: new Date().toISOString(),
|
|
180
|
+
error: err instanceof Error ? err.message : String(err),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
export function getLocalDbSize() {
|
|
185
|
+
const db = getDb();
|
|
186
|
+
const tables = ['sessions', 'decisions', 'council_outcomes', 'knowledge_base', 'patterns', 'project_map', 'learning_data'];
|
|
187
|
+
const counts = {};
|
|
188
|
+
for (const table of tables) {
|
|
189
|
+
try {
|
|
190
|
+
const row = db.prepare(`SELECT COUNT(*) as c FROM ${table}`).get();
|
|
191
|
+
counts[table] = row.c;
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
counts[table] = 0;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return { db_path: getDbPath(), tables: counts };
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=sync.js.map
|