@jigyasudham/veto 3.1.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +630 -627
  3. package/dist/agents/llm-runner.js +57 -57
  4. package/dist/cli/statusline.js +2 -2
  5. package/dist/cli.js +26 -26
  6. package/dist/memory/decisions.js +1 -1
  7. package/dist/memory/local.js +144 -144
  8. package/dist/memory/schema.js +228 -228
  9. package/dist/memory/sync.js +27 -27
  10. package/dist/memory/sync.js.map +1 -1
  11. package/dist/router/implicit-outcomes.js +4 -4
  12. package/dist/router/learning-updater.js +45 -45
  13. package/dist/server.js +1 -1
  14. package/dist/tools/compact.js +3 -3
  15. package/dist/transcripts/archive.js +5 -5
  16. package/dist/transcripts/ingest.js +6 -6
  17. package/dist/transcripts/mapping.js +5 -5
  18. package/dist/transcripts/pyramid.js +2 -2
  19. package/dist/transcripts/schema.js +104 -104
  20. package/dist/transcripts/search.js +3 -3
  21. package/dist/transcripts/vectors.js +2 -2
  22. package/package.json +70 -62
  23. package/server.json +23 -23
  24. package/dist/skills/development/skill-api-design.d.ts +0 -15
  25. package/dist/skills/development/skill-api-design.d.ts.map +0 -1
  26. package/dist/skills/development/skill-api-design.js +0 -313
  27. package/dist/skills/development/skill-api-design.js.map +0 -1
  28. package/dist/skills/development/skill-auth.d.ts +0 -15
  29. package/dist/skills/development/skill-auth.d.ts.map +0 -1
  30. package/dist/skills/development/skill-auth.js +0 -255
  31. package/dist/skills/development/skill-auth.js.map +0 -1
  32. package/dist/skills/development/skill-ci-cd.d.ts +0 -2
  33. package/dist/skills/development/skill-ci-cd.d.ts.map +0 -1
  34. package/dist/skills/development/skill-ci-cd.js +0 -2
  35. package/dist/skills/development/skill-ci-cd.js.map +0 -1
  36. package/dist/skills/development/skill-crud.d.ts +0 -15
  37. package/dist/skills/development/skill-crud.d.ts.map +0 -1
  38. package/dist/skills/development/skill-crud.js +0 -193
  39. package/dist/skills/development/skill-crud.js.map +0 -1
  40. package/dist/skills/development/skill-db-schema.d.ts +0 -2
  41. package/dist/skills/development/skill-db-schema.d.ts.map +0 -1
  42. package/dist/skills/development/skill-db-schema.js +0 -2
  43. package/dist/skills/development/skill-db-schema.js.map +0 -1
  44. package/dist/skills/development/skill-docker.d.ts +0 -2
  45. package/dist/skills/development/skill-docker.d.ts.map +0 -1
  46. package/dist/skills/development/skill-docker.js +0 -2
  47. package/dist/skills/development/skill-docker.js.map +0 -1
  48. package/dist/skills/development/skill-env-setup.d.ts +0 -2
  49. package/dist/skills/development/skill-env-setup.d.ts.map +0 -1
  50. package/dist/skills/development/skill-env-setup.js +0 -2
  51. package/dist/skills/development/skill-env-setup.js.map +0 -1
  52. package/dist/skills/development/skill-scaffold.d.ts +0 -15
  53. package/dist/skills/development/skill-scaffold.d.ts.map +0 -1
  54. package/dist/skills/development/skill-scaffold.js +0 -299
  55. package/dist/skills/development/skill-scaffold.js.map +0 -1
  56. package/dist/skills/intelligence/skill-complexity-score.d.ts +0 -15
  57. package/dist/skills/intelligence/skill-complexity-score.d.ts.map +0 -1
  58. package/dist/skills/intelligence/skill-complexity-score.js +0 -66
  59. package/dist/skills/intelligence/skill-complexity-score.js.map +0 -1
  60. package/dist/skills/intelligence/skill-cost-track.d.ts +0 -14
  61. package/dist/skills/intelligence/skill-cost-track.d.ts.map +0 -1
  62. package/dist/skills/intelligence/skill-cost-track.js +0 -36
  63. package/dist/skills/intelligence/skill-cost-track.js.map +0 -1
  64. package/dist/skills/intelligence/skill-learning-loop.d.ts +0 -15
  65. package/dist/skills/intelligence/skill-learning-loop.d.ts.map +0 -1
  66. package/dist/skills/intelligence/skill-learning-loop.js +0 -66
  67. package/dist/skills/intelligence/skill-learning-loop.js.map +0 -1
  68. package/dist/skills/intelligence/skill-pattern-detect.d.ts +0 -14
  69. package/dist/skills/intelligence/skill-pattern-detect.d.ts.map +0 -1
  70. package/dist/skills/intelligence/skill-pattern-detect.js +0 -35
  71. package/dist/skills/intelligence/skill-pattern-detect.js.map +0 -1
  72. package/dist/skills/intelligence/skill-rate-watch.d.ts +0 -15
  73. package/dist/skills/intelligence/skill-rate-watch.d.ts.map +0 -1
  74. package/dist/skills/intelligence/skill-rate-watch.js +0 -58
  75. package/dist/skills/intelligence/skill-rate-watch.js.map +0 -1
  76. package/dist/skills/memory/skill-context-compress.d.ts +0 -15
  77. package/dist/skills/memory/skill-context-compress.d.ts.map +0 -1
  78. package/dist/skills/memory/skill-context-compress.js +0 -82
  79. package/dist/skills/memory/skill-context-compress.js.map +0 -1
  80. package/dist/skills/memory/skill-cross-sync.d.ts +0 -15
  81. package/dist/skills/memory/skill-cross-sync.d.ts.map +0 -1
  82. package/dist/skills/memory/skill-cross-sync.js +0 -88
  83. package/dist/skills/memory/skill-cross-sync.js.map +0 -1
  84. package/dist/skills/memory/skill-decision-log.d.ts +0 -15
  85. package/dist/skills/memory/skill-decision-log.d.ts.map +0 -1
  86. package/dist/skills/memory/skill-decision-log.js +0 -103
  87. package/dist/skills/memory/skill-decision-log.js.map +0 -1
  88. package/dist/skills/memory/skill-session-restore.d.ts +0 -15
  89. package/dist/skills/memory/skill-session-restore.d.ts.map +0 -1
  90. package/dist/skills/memory/skill-session-restore.js +0 -39
  91. package/dist/skills/memory/skill-session-restore.js.map +0 -1
  92. package/dist/skills/memory/skill-session-save.d.ts +0 -15
  93. package/dist/skills/memory/skill-session-save.d.ts.map +0 -1
  94. package/dist/skills/memory/skill-session-save.js +0 -74
  95. package/dist/skills/memory/skill-session-save.js.map +0 -1
  96. package/dist/skills/quality/skill-accessibility.d.ts +0 -2
  97. package/dist/skills/quality/skill-accessibility.d.ts.map +0 -1
  98. package/dist/skills/quality/skill-accessibility.js +0 -2
  99. package/dist/skills/quality/skill-accessibility.js.map +0 -1
  100. package/dist/skills/quality/skill-code-review.d.ts +0 -15
  101. package/dist/skills/quality/skill-code-review.d.ts.map +0 -1
  102. package/dist/skills/quality/skill-code-review.js +0 -60
  103. package/dist/skills/quality/skill-code-review.js.map +0 -1
  104. package/dist/skills/quality/skill-docs-gen.d.ts +0 -2
  105. package/dist/skills/quality/skill-docs-gen.d.ts.map +0 -1
  106. package/dist/skills/quality/skill-docs-gen.js +0 -2
  107. package/dist/skills/quality/skill-docs-gen.js.map +0 -1
  108. package/dist/skills/quality/skill-perf-audit.d.ts +0 -2
  109. package/dist/skills/quality/skill-perf-audit.d.ts.map +0 -1
  110. package/dist/skills/quality/skill-perf-audit.js +0 -2
  111. package/dist/skills/quality/skill-perf-audit.js.map +0 -1
  112. package/dist/skills/quality/skill-security-scan.d.ts +0 -15
  113. package/dist/skills/quality/skill-security-scan.d.ts.map +0 -1
  114. package/dist/skills/quality/skill-security-scan.js +0 -67
  115. package/dist/skills/quality/skill-security-scan.js.map +0 -1
  116. package/dist/skills/quality/skill-test-suite.d.ts +0 -15
  117. package/dist/skills/quality/skill-test-suite.d.ts.map +0 -1
  118. package/dist/skills/quality/skill-test-suite.js +0 -274
  119. package/dist/skills/quality/skill-test-suite.js.map +0 -1
  120. package/dist/skills/workflow/skill-deploy.d.ts +0 -2
  121. package/dist/skills/workflow/skill-deploy.d.ts.map +0 -1
  122. package/dist/skills/workflow/skill-deploy.js +0 -2
  123. package/dist/skills/workflow/skill-deploy.js.map +0 -1
  124. package/dist/skills/workflow/skill-git-workflow.d.ts +0 -2
  125. package/dist/skills/workflow/skill-git-workflow.d.ts.map +0 -1
  126. package/dist/skills/workflow/skill-git-workflow.js +0 -2
  127. package/dist/skills/workflow/skill-git-workflow.js.map +0 -1
  128. package/dist/skills/workflow/skill-rollback.d.ts +0 -2
  129. package/dist/skills/workflow/skill-rollback.d.ts.map +0 -1
  130. package/dist/skills/workflow/skill-rollback.js +0 -2
  131. package/dist/skills/workflow/skill-rollback.js.map +0 -1
  132. package/dist/skills/workflow/skill-task-breakdown.d.ts +0 -2
  133. package/dist/skills/workflow/skill-task-breakdown.d.ts.map +0 -1
  134. package/dist/skills/workflow/skill-task-breakdown.js +0 -2
  135. package/dist/skills/workflow/skill-task-breakdown.js.map +0 -1
@@ -6,66 +6,66 @@ import { validateAgentPlan, validateAgentAnalysis } from './validate.js';
6
6
  import { log, errMsg } from '../log.js';
7
7
  // ─── System prompt builders ───────────────────────────────────────────────────
8
8
  function buildPlanPrompt(agent, role) {
9
- return `You are the ${agent} specialist in an AI-assisted software engineering system.
10
-
11
- ROLE: ${role}
12
-
13
- Your job: given a task description and optional code/context, produce a concrete implementation plan.
14
-
15
- Return ONLY valid JSON (no markdown, no prose):
16
- {
17
- "agent": "${agent}",
18
- "task": "<task echoed back>",
19
- "tier": 1|2|3,
20
- "approach": "<2-3 sentence strategy — the WHY and HOW, not step list>",
21
- "steps": ["<ordered action step>", ...],
22
- "checklist": ["[ ] <verification item>", ...],
23
- "pitfalls": ["<gotcha or common mistake>", ...],
24
- "patterns": ["<design pattern or principle to apply>", ...],
25
- "duration_estimate": "<e.g. 1-2 hours>"
26
- }
27
-
28
- Rules:
29
- - tier: 1 = simple (<1h), 2 = medium (1-4h), 3 = complex (>4h)
30
- - steps: 6-12 concrete, ordered actions
31
- - checklist: 6-10 testable done-criteria prefixed with "[ ] "
32
- - pitfalls: 3-5 non-obvious mistakes specific to this task
33
- - patterns: 3-5 relevant design patterns or engineering principles
9
+ return `You are the ${agent} specialist in an AI-assisted software engineering system.
10
+
11
+ ROLE: ${role}
12
+
13
+ Your job: given a task description and optional code/context, produce a concrete implementation plan.
14
+
15
+ Return ONLY valid JSON (no markdown, no prose):
16
+ {
17
+ "agent": "${agent}",
18
+ "task": "<task echoed back>",
19
+ "tier": 1|2|3,
20
+ "approach": "<2-3 sentence strategy — the WHY and HOW, not step list>",
21
+ "steps": ["<ordered action step>", ...],
22
+ "checklist": ["[ ] <verification item>", ...],
23
+ "pitfalls": ["<gotcha or common mistake>", ...],
24
+ "patterns": ["<design pattern or principle to apply>", ...],
25
+ "duration_estimate": "<e.g. 1-2 hours>"
26
+ }
27
+
28
+ Rules:
29
+ - tier: 1 = simple (<1h), 2 = medium (1-4h), 3 = complex (>4h)
30
+ - steps: 6-12 concrete, ordered actions
31
+ - checklist: 6-10 testable done-criteria prefixed with "[ ] "
32
+ - pitfalls: 3-5 non-obvious mistakes specific to this task
33
+ - patterns: 3-5 relevant design patterns or engineering principles
34
34
  - Keep total JSON under 800 tokens`;
35
35
  }
36
36
  function buildAnalysisPrompt(agent, role) {
37
- return `You are the ${agent} specialist in an AI-assisted software engineering system.
38
-
39
- ROLE: ${role}
40
-
41
- Your job: given code and optional context, produce a scored analysis with actionable findings.
42
-
43
- Return ONLY valid JSON (no markdown, no prose):
44
- {
45
- "agent": "${agent}",
46
- "subject": "<one-line description of what was analyzed>",
47
- "findings": [
48
- {
49
- "severity": "critical|high|medium|low|info",
50
- "category": "<category name>",
51
- "description": "<what is wrong and why it matters>",
52
- "fix": "<specific, actionable remediation>",
53
- "location": "<file:line if applicable>",
54
- "cwe": "<CWE-NNN if applicable>"
55
- }
56
- ],
57
- "score": <0-100, 100 = perfect>,
58
- "verdict": "approved|approved_with_warnings|needs_revision|rejected",
59
- "summary": "<one sentence overall assessment>",
60
- "critical_count": <integer>,
61
- "high_count": <integer>
62
- }
63
-
64
- Rules:
65
- - findings: list ALL issues found; empty array is valid for clean code
66
- - score: 90-100 = clean, 70-89 = minor issues, 50-69 = needs work, <50 = reject
67
- - verdict: approved (score≥90), approved_with_warnings (score 70-89), needs_revision (50-69), rejected (<50)
68
- - critical_count and high_count MUST match findings array
37
+ return `You are the ${agent} specialist in an AI-assisted software engineering system.
38
+
39
+ ROLE: ${role}
40
+
41
+ Your job: given code and optional context, produce a scored analysis with actionable findings.
42
+
43
+ Return ONLY valid JSON (no markdown, no prose):
44
+ {
45
+ "agent": "${agent}",
46
+ "subject": "<one-line description of what was analyzed>",
47
+ "findings": [
48
+ {
49
+ "severity": "critical|high|medium|low|info",
50
+ "category": "<category name>",
51
+ "description": "<what is wrong and why it matters>",
52
+ "fix": "<specific, actionable remediation>",
53
+ "location": "<file:line if applicable>",
54
+ "cwe": "<CWE-NNN if applicable>"
55
+ }
56
+ ],
57
+ "score": <0-100, 100 = perfect>,
58
+ "verdict": "approved|approved_with_warnings|needs_revision|rejected",
59
+ "summary": "<one sentence overall assessment>",
60
+ "critical_count": <integer>,
61
+ "high_count": <integer>
62
+ }
63
+
64
+ Rules:
65
+ - findings: list ALL issues found; empty array is valid for clean code
66
+ - score: 90-100 = clean, 70-89 = minor issues, 50-69 = needs work, <50 = reject
67
+ - verdict: approved (score≥90), approved_with_warnings (score 70-89), needs_revision (50-69), rejected (<50)
68
+ - critical_count and high_count MUST match findings array
69
69
  - Keep total JSON under 1000 tokens`;
70
70
  }
71
71
  // ─── Response parsers ─────────────────────────────────────────────────────────
@@ -97,8 +97,8 @@ function queryStatusline(db, projectDir) {
97
97
  try {
98
98
  // Top confidence among learned patterns. Exclude router.* threshold rows and
99
99
  // composed_agent:* definitions — those carry config/JSON, not a learning score.
100
- const row = db.prepare(`SELECT confidence FROM patterns
101
- WHERE pattern_key NOT LIKE 'router.%' AND pattern_key NOT LIKE 'composed_agent:%'
100
+ const row = db.prepare(`SELECT confidence FROM patterns
101
+ WHERE pattern_key NOT LIKE 'router.%' AND pattern_key NOT LIKE 'composed_agent:%'
102
102
  ORDER BY confidence DESC, seen_count DESC LIMIT 1`).get();
103
103
  if (typeof row?.confidence === 'number') {
104
104
  data.routerPct = Math.max(0, Math.min(100, Math.round(row.confidence * 100)));
package/dist/cli.js CHANGED
@@ -315,32 +315,32 @@ async function initCommand() {
315
315
  // These are read at session start by each AI client — zero tool calls needed.
316
316
  console.log(' Writing context guidance files...');
317
317
  console.log('');
318
- const VETO_GUIDE = `# Veto MCP Server
319
-
320
- Veto is active. 93 tools across 6 categories:
321
-
322
- **Session & Context** — veto_status · veto_session_save · veto_continue · veto_handoff
323
- Save work at 60–70% context capacity. veto_status triggers auto-save above 70%.
324
-
325
- **Code Intelligence** — veto_diff_review · veto_code_review · veto_security_scan · veto_secrets_scan · veto_ci_gate
326
- Run veto_diff_review before any merge — it runs all three scans in parallel.
327
-
328
- **Council & Routing** — veto_council_debate · veto_route_task · veto_execute_parallel
329
- Council = 7 specialist agents (Lead Dev, PM, Architect, UX, Devil's Advocate, Legal, Security).
330
- Verdicts: GREEN (proceed) · YELLOW (warnings) · RED (blocked) · DEADLOCK (human decision needed).
331
- Two-phase LLM-backed flow: call with { task } → get debate_prompt → reason as all 7 agents → call again with { task, agent_responses }.
332
-
333
- **Memory & Discovery** — veto_discover · veto_summarize · veto_memory_store · veto_memory_search
334
- Run veto_discover on any unfamiliar repo before touching files.
335
-
336
- **Observability** — veto_usage_status · veto_health · veto_audit_log · veto_learning_stats
337
-
338
- Recommended start sequence:
339
- 1. veto_status — confirm running
340
- 2. veto_discover — map the project
341
- 3. veto_route_task — pick the right agent
342
- 4. veto_diff_review — validate before shipping
343
- 5. veto_session_save — checkpoint before context fills
318
+ const VETO_GUIDE = `# Veto MCP Server
319
+
320
+ Veto is active. 93 tools across 6 categories:
321
+
322
+ **Session & Context** — veto_status · veto_session_save · veto_continue · veto_handoff
323
+ Save work at 60–70% context capacity. veto_status triggers auto-save above 70%.
324
+
325
+ **Code Intelligence** — veto_diff_review · veto_code_review · veto_security_scan · veto_secrets_scan · veto_ci_gate
326
+ Run veto_diff_review before any merge — it runs all three scans in parallel.
327
+
328
+ **Council & Routing** — veto_council_debate · veto_route_task · veto_execute_parallel
329
+ Council = 7 specialist agents (Lead Dev, PM, Architect, UX, Devil's Advocate, Legal, Security).
330
+ Verdicts: GREEN (proceed) · YELLOW (warnings) · RED (blocked) · DEADLOCK (human decision needed).
331
+ Two-phase LLM-backed flow: call with { task } → get debate_prompt → reason as all 7 agents → call again with { task, agent_responses }.
332
+
333
+ **Memory & Discovery** — veto_discover · veto_summarize · veto_memory_store · veto_memory_search
334
+ Run veto_discover on any unfamiliar repo before touching files.
335
+
336
+ **Observability** — veto_usage_status · veto_health · veto_audit_log · veto_learning_stats
337
+
338
+ Recommended start sequence:
339
+ 1. veto_status — confirm running
340
+ 2. veto_discover — map the project
341
+ 3. veto_route_task — pick the right agent
342
+ 4. veto_diff_review — validate before shipping
343
+ 5. veto_session_save — checkpoint before context fills
344
344
  `;
345
345
  let ctxWritten = 0;
346
346
  // Gemini & Antigravity CLI: ~/.gemini/GEMINI.md
@@ -33,7 +33,7 @@ export function addConstraint(input) {
33
33
  const db = getDb();
34
34
  const id = randomUUID();
35
35
  const created_at = new Date().toISOString();
36
- db.prepare(`INSERT INTO decision_constraints (id, project_dir, rule, why, forbidden_patterns, file_scope, severity, active, created_at)
36
+ db.prepare(`INSERT INTO decision_constraints (id, project_dir, rule, why, forbidden_patterns, file_scope, severity, active, created_at)
37
37
  VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?)`).run(id, normalizeDir(input.project_dir), input.rule, input.why ?? null, JSON.stringify(input.forbidden_patterns), input.file_scope ?? null, input.severity === 'warn' ? 'warn' : 'block', created_at);
38
38
  return listConstraints().find(c => c.id === id);
39
39
  }
@@ -143,18 +143,18 @@ function migrateProjectDirCase(db) {
143
143
  }
144
144
  // Creates tool_call_trace_log table for auditing and session replay (v1.8.0 migration)
145
145
  function migrateToolTraceLog(db) {
146
- db.exec(`
147
- CREATE TABLE IF NOT EXISTS tool_call_trace_log (
148
- id TEXT PRIMARY KEY,
149
- session_id TEXT,
150
- tool_name TEXT NOT NULL,
151
- args_json TEXT,
152
- result_status TEXT NOT NULL DEFAULT 'success',
153
- error_message TEXT,
154
- duration_ms INTEGER NOT NULL,
155
- tokens_used INTEGER,
156
- recorded_at TEXT NOT NULL DEFAULT (datetime('now'))
157
- )
146
+ db.exec(`
147
+ CREATE TABLE IF NOT EXISTS tool_call_trace_log (
148
+ id TEXT PRIMARY KEY,
149
+ session_id TEXT,
150
+ tool_name TEXT NOT NULL,
151
+ args_json TEXT,
152
+ result_status TEXT NOT NULL DEFAULT 'success',
153
+ error_message TEXT,
154
+ duration_ms INTEGER NOT NULL,
155
+ tokens_used INTEGER,
156
+ recorded_at TEXT NOT NULL DEFAULT (datetime('now'))
157
+ )
158
158
  `);
159
159
  db.exec(`CREATE INDEX IF NOT EXISTS idx_tool_trace_session ON tool_call_trace_log(session_id)`);
160
160
  db.exec(`CREATE INDEX IF NOT EXISTS idx_tool_trace_name ON tool_call_trace_log(tool_name)`);
@@ -167,44 +167,44 @@ export function getSessionReplay(sessionId) {
167
167
  export function recordToolCall(opts) {
168
168
  const db = getDb();
169
169
  const id = randomUUID();
170
- db.prepare(`
171
- INSERT INTO tool_call_trace_log (id, session_id, tool_name, args_json, result_status, error_message, duration_ms, tokens_used)
172
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
170
+ db.prepare(`
171
+ INSERT INTO tool_call_trace_log (id, session_id, tool_name, args_json, result_status, error_message, duration_ms, tokens_used)
172
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
173
173
  `).run(id, opts.session_id ?? null, opts.tool_name, opts.args ? JSON.stringify(opts.args) : null, opts.result_status, opts.error_message ?? null, opts.duration_ms, opts.tokens_used ?? null);
174
174
  return id;
175
175
  }
176
176
  // Creates routing_feedback table for opt-in routing signal storage (v1.4.8 migration)
177
177
  function migrateRoutingFeedback(db) {
178
- db.exec(`
179
- CREATE TABLE IF NOT EXISTS routing_feedback (
180
- id TEXT PRIMARY KEY,
181
- task_hash TEXT NOT NULL,
182
- task_snippet TEXT NOT NULL,
183
- complexity INTEGER NOT NULL,
184
- model_tier INTEGER NOT NULL,
185
- agent TEXT,
186
- outcome TEXT NOT NULL DEFAULT 'pending',
187
- quality INTEGER,
188
- session_id TEXT,
189
- recorded_at TEXT NOT NULL DEFAULT (datetime('now')),
190
- expires_at TEXT NOT NULL
191
- )
178
+ db.exec(`
179
+ CREATE TABLE IF NOT EXISTS routing_feedback (
180
+ id TEXT PRIMARY KEY,
181
+ task_hash TEXT NOT NULL,
182
+ task_snippet TEXT NOT NULL,
183
+ complexity INTEGER NOT NULL,
184
+ model_tier INTEGER NOT NULL,
185
+ agent TEXT,
186
+ outcome TEXT NOT NULL DEFAULT 'pending',
187
+ quality INTEGER,
188
+ session_id TEXT,
189
+ recorded_at TEXT NOT NULL DEFAULT (datetime('now')),
190
+ expires_at TEXT NOT NULL
191
+ )
192
192
  `);
193
193
  db.exec(`CREATE INDEX IF NOT EXISTS idx_routing_fb_hash ON routing_feedback(task_hash)`);
194
194
  db.exec(`CREATE INDEX IF NOT EXISTS idx_routing_fb_exp ON routing_feedback(expires_at)`);
195
195
  }
196
196
  // Creates context_usage table for live VS Code extension polling (v1.4.4 migration)
197
197
  function migrateContextUsage(db) {
198
- db.exec(`
199
- CREATE TABLE IF NOT EXISTS context_usage (
200
- platform TEXT PRIMARY KEY,
201
- model TEXT,
202
- token_count INTEGER NOT NULL DEFAULT 0,
203
- context_window INTEGER NOT NULL DEFAULT 200000,
204
- usage_pct REAL NOT NULL DEFAULT 0,
205
- session_id TEXT,
206
- updated_at TEXT NOT NULL DEFAULT (datetime('now'))
207
- )
198
+ db.exec(`
199
+ CREATE TABLE IF NOT EXISTS context_usage (
200
+ platform TEXT PRIMARY KEY,
201
+ model TEXT,
202
+ token_count INTEGER NOT NULL DEFAULT 0,
203
+ context_window INTEGER NOT NULL DEFAULT 200000,
204
+ usage_pct REAL NOT NULL DEFAULT 0,
205
+ session_id TEXT,
206
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
207
+ )
208
208
  `);
209
209
  }
210
210
  // Adds tags column to sessions (v1.3.1 migration)
@@ -216,17 +216,17 @@ function migrateSessionTags(db) {
216
216
  }
217
217
  // Creates scan_diagnostics table if it doesn't exist (v1.2.18 migration)
218
218
  function migrateScanDiagnostics(db) {
219
- db.exec(`
220
- CREATE TABLE IF NOT EXISTS scan_diagnostics (
221
- id TEXT PRIMARY KEY,
222
- file_path TEXT NOT NULL,
223
- line INTEGER NOT NULL DEFAULT 0,
224
- col_start INTEGER NOT NULL DEFAULT 0,
225
- message TEXT NOT NULL,
226
- severity TEXT NOT NULL DEFAULT 'warning',
227
- source TEXT NOT NULL DEFAULT 'veto',
228
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
229
- )
219
+ db.exec(`
220
+ CREATE TABLE IF NOT EXISTS scan_diagnostics (
221
+ id TEXT PRIMARY KEY,
222
+ file_path TEXT NOT NULL,
223
+ line INTEGER NOT NULL DEFAULT 0,
224
+ col_start INTEGER NOT NULL DEFAULT 0,
225
+ message TEXT NOT NULL,
226
+ severity TEXT NOT NULL DEFAULT 'warning',
227
+ source TEXT NOT NULL DEFAULT 'veto',
228
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
229
+ )
230
230
  `);
231
231
  db.exec(`CREATE INDEX IF NOT EXISTS idx_scan_diag_file ON scan_diagnostics(file_path)`);
232
232
  }
@@ -248,16 +248,16 @@ function migrateRateUsageTokens(db) {
248
248
  }
249
249
  // Creates usage_log table if it doesn't exist (v1.2.14 migration)
250
250
  function migrateUsageLog(db) {
251
- db.exec(`
252
- CREATE TABLE IF NOT EXISTS usage_log (
253
- id TEXT PRIMARY KEY,
254
- tool_name TEXT NOT NULL,
255
- session_id TEXT,
256
- max_tokens INTEGER NOT NULL,
257
- estimated_tokens INTEGER NOT NULL,
258
- exceeded INTEGER NOT NULL DEFAULT 0,
259
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
260
- )
251
+ db.exec(`
252
+ CREATE TABLE IF NOT EXISTS usage_log (
253
+ id TEXT PRIMARY KEY,
254
+ tool_name TEXT NOT NULL,
255
+ session_id TEXT,
256
+ max_tokens INTEGER NOT NULL,
257
+ estimated_tokens INTEGER NOT NULL,
258
+ exceeded INTEGER NOT NULL DEFAULT 0,
259
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
260
+ )
261
261
  `);
262
262
  }
263
263
  // Adds duration_ms column to council_outcomes if it doesn't exist (v1.2.3 migration)
@@ -277,12 +277,12 @@ function migrateCouncilProjectDir(db) {
277
277
  const names = new Set(cols.map(c => c.name));
278
278
  if (!names.has('project_dir'))
279
279
  db.exec('ALTER TABLE council_outcomes ADD COLUMN project_dir TEXT');
280
- db.exec(`
281
- UPDATE council_outcomes
282
- SET project_dir = (SELECT s.project_dir FROM sessions s WHERE s.id = council_outcomes.session_id)
283
- WHERE project_dir IS NULL
284
- AND session_id IS NOT NULL
285
- AND EXISTS (SELECT 1 FROM sessions s WHERE s.id = council_outcomes.session_id AND s.project_dir IS NOT NULL)
280
+ db.exec(`
281
+ UPDATE council_outcomes
282
+ SET project_dir = (SELECT s.project_dir FROM sessions s WHERE s.id = council_outcomes.session_id)
283
+ WHERE project_dir IS NULL
284
+ AND session_id IS NOT NULL
285
+ AND EXISTS (SELECT 1 FROM sessions s WHERE s.id = council_outcomes.session_id AND s.project_dir IS NOT NULL)
286
286
  `);
287
287
  }
288
288
  // Adds active_client, last_resumed_at, and connection_type columns if they don't exist
@@ -311,15 +311,15 @@ function migrateCouncilOutcomes(db) {
311
311
  const col = cols.find(c => c.name === 'session_id');
312
312
  if (!col || col.notnull !== 1)
313
313
  return;
314
- db.exec(`
315
- CREATE TABLE IF NOT EXISTS _council_outcomes_new (
316
- id TEXT PRIMARY KEY, session_id TEXT, task TEXT NOT NULL,
317
- verdict TEXT NOT NULL, lead_dev TEXT, pm TEXT, architect TEXT,
318
- ux TEXT, devil TEXT, recommended TEXT, debated_at TEXT NOT NULL
319
- );
320
- INSERT OR IGNORE INTO _council_outcomes_new SELECT * FROM council_outcomes;
321
- DROP TABLE council_outcomes;
322
- ALTER TABLE _council_outcomes_new RENAME TO council_outcomes;
314
+ db.exec(`
315
+ CREATE TABLE IF NOT EXISTS _council_outcomes_new (
316
+ id TEXT PRIMARY KEY, session_id TEXT, task TEXT NOT NULL,
317
+ verdict TEXT NOT NULL, lead_dev TEXT, pm TEXT, architect TEXT,
318
+ ux TEXT, devil TEXT, recommended TEXT, debated_at TEXT NOT NULL
319
+ );
320
+ INSERT OR IGNORE INTO _council_outcomes_new SELECT * FROM council_outcomes;
321
+ DROP TABLE council_outcomes;
322
+ ALTER TABLE _council_outcomes_new RENAME TO council_outcomes;
323
323
  `);
324
324
  }
325
325
  // Canonicalize a project directory so writes and reads agree regardless of
@@ -342,14 +342,14 @@ export function saveSession(input) {
342
342
  const connection_type = input.connection_type ?? 'subscription';
343
343
  const token_count = input.token_count ?? 0;
344
344
  const save_type = input.save_type ?? 'manual';
345
- db.prepare(`
346
- INSERT INTO sessions (id, started_at, platform, connection_type, project_dir, summary, context, task_state, token_count, save_type, tags)
347
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
345
+ db.prepare(`
346
+ INSERT INTO sessions (id, started_at, platform, connection_type, project_dir, summary, context, task_state, token_count, save_type, tags)
347
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
348
348
  `).run(id, now, platform, connection_type, normalizeProjectDir(input.project_dir) ?? null, input.summary ?? null, input.context ? JSON.stringify(input.context) : null, input.task_state ? JSON.stringify(input.task_state) : null, token_count, save_type, input.tags ? JSON.stringify(input.tags) : null);
349
349
  // Record usage event
350
- db.prepare(`
351
- INSERT INTO usage_events (id, session_id, platform, connection_type, tokens, event_type, recorded_at)
352
- VALUES (?, ?, ?, ?, ?, 'session_save', ?)
350
+ db.prepare(`
351
+ INSERT INTO usage_events (id, session_id, platform, connection_type, tokens, event_type, recorded_at)
352
+ VALUES (?, ?, ?, ?, ?, 'session_save', ?)
353
353
  `).run(randomUUID(), id, platform, connection_type, token_count, now);
354
354
  // Context window guard — use model-specific window when available (Gemini 1M vs Claude 200k)
355
355
  const window_size = resolveContextWindow(platform, input.model);
@@ -366,16 +366,16 @@ export function updateSession(session_id, input) {
366
366
  if (!existing)
367
367
  return null;
368
368
  const now = new Date().toISOString();
369
- db.prepare(`
370
- UPDATE sessions SET
371
- summary = ?,
372
- context = ?,
373
- task_state = ?,
374
- token_count = ?,
375
- save_type = 'manual',
376
- tags = COALESCE(?, tags),
377
- created_at = ?
378
- WHERE id = ?
369
+ db.prepare(`
370
+ UPDATE sessions SET
371
+ summary = ?,
372
+ context = ?,
373
+ task_state = ?,
374
+ token_count = ?,
375
+ save_type = 'manual',
376
+ tags = COALESCE(?, tags),
377
+ created_at = ?
378
+ WHERE id = ?
379
379
  `).run(input.summary ?? null, input.context ? JSON.stringify(input.context) : null, input.task_state ? JSON.stringify(input.task_state) : null, input.token_count ?? 0,
380
380
  // Only overwrite tags when the caller supplies them; otherwise keep existing
381
381
  // (COALESCE(NULL, tags) = tags). saveSession serializes tags the same way.
@@ -431,10 +431,10 @@ export function saveCouncilOutcome(input) {
431
431
  const db = getDb();
432
432
  const id = randomUUID();
433
433
  const now = new Date().toISOString();
434
- db.prepare(`
435
- INSERT INTO council_outcomes
436
- (id, session_id, task, verdict, lead_dev, pm, architect, ux, devil, legal, security, recommended, debated_at, duration_ms, project_dir)
437
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
434
+ db.prepare(`
435
+ INSERT INTO council_outcomes
436
+ (id, session_id, task, verdict, lead_dev, pm, architect, ux, devil, legal, security, recommended, debated_at, duration_ms, project_dir)
437
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
438
438
  `).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, input.duration_ms ?? 0, normalizeProjectDir(input.project_dir) ?? null);
439
439
  return id;
440
440
  }
@@ -442,9 +442,9 @@ export function storeKnowledge(input) {
442
442
  const db = getDb();
443
443
  const id = randomUUID();
444
444
  const now = new Date().toISOString();
445
- db.prepare(`
446
- INSERT INTO knowledge_base (id, type, title, content, tags, project_dir, session_id, relevance, created_at, updated_at)
447
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
445
+ db.prepare(`
446
+ INSERT INTO knowledge_base (id, type, title, content, tags, project_dir, session_id, relevance, created_at, updated_at)
447
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
448
448
  `).run(id, input.type ?? 'solution', input.title, input.content, input.tags ? JSON.stringify(input.tags) : null, normalizeProjectDir(input.project_dir) ?? null, input.session_id ?? null, input.relevance ?? 1.0, now, now);
449
449
  return id;
450
450
  }
@@ -489,16 +489,16 @@ export function updateProjectMap(input) {
489
489
  const key_modules = input.key_modules ? JSON.stringify(input.key_modules) : null;
490
490
  const tech_stack = input.tech_stack ? JSON.stringify(input.tech_stack) : null;
491
491
  if (existing) {
492
- db.prepare(`
493
- UPDATE project_map SET structure = ?, key_modules = ?, tech_stack = ?, updated_at = ?
494
- WHERE project_dir = ?
492
+ db.prepare(`
493
+ UPDATE project_map SET structure = ?, key_modules = ?, tech_stack = ?, updated_at = ?
494
+ WHERE project_dir = ?
495
495
  `).run(structure, key_modules, tech_stack, now, project_dir);
496
496
  return existing.id;
497
497
  }
498
498
  const id = randomUUID();
499
- db.prepare(`
500
- INSERT INTO project_map (id, project_dir, structure, key_modules, tech_stack, updated_at)
501
- VALUES (?, ?, ?, ?, ?, ?)
499
+ db.prepare(`
500
+ INSERT INTO project_map (id, project_dir, structure, key_modules, tech_stack, updated_at)
501
+ VALUES (?, ?, ?, ?, ?, ?)
502
502
  `).run(id, project_dir, structure, key_modules, tech_stack, now);
503
503
  return id;
504
504
  }
@@ -512,15 +512,15 @@ export function upsertPattern(input) {
512
512
  const existing = db.prepare('SELECT id, seen_count, confidence FROM patterns WHERE pattern_key = ?').get(input.pattern_key);
513
513
  if (existing) {
514
514
  const newConfidence = Math.min(1.0, (existing.confidence + (input.confidence ?? 1.0)) / 2);
515
- db.prepare(`
516
- UPDATE patterns SET pattern_val = ?, confidence = ?, seen_count = seen_count + 1, updated_at = ?
517
- WHERE pattern_key = ?
515
+ db.prepare(`
516
+ UPDATE patterns SET pattern_val = ?, confidence = ?, seen_count = seen_count + 1, updated_at = ?
517
+ WHERE pattern_key = ?
518
518
  `).run(input.pattern_val, newConfidence, now, input.pattern_key);
519
519
  }
520
520
  else {
521
- db.prepare(`
522
- INSERT INTO patterns (id, pattern_key, pattern_val, confidence, seen_count, updated_at)
523
- VALUES (?, ?, ?, ?, 1, ?)
521
+ db.prepare(`
522
+ INSERT INTO patterns (id, pattern_key, pattern_val, confidence, seen_count, updated_at)
523
+ VALUES (?, ?, ?, ?, 1, ?)
524
524
  `).run(randomUUID(), input.pattern_key, input.pattern_val, input.confidence ?? 1.0, now);
525
525
  }
526
526
  }
@@ -589,9 +589,9 @@ export async function fetchAndCacheDocs(package_name, ecosystem, version, max_ch
589
589
  content = `# ${package_name}@${resolved_version}\n${json.crate.description}\nDocs: ${json.crate.documentation}`;
590
590
  }
591
591
  const now = new Date().toISOString();
592
- db.prepare(`
593
- INSERT OR REPLACE INTO docs_cache (id, package_name, ecosystem, version, content, fetched_at)
594
- VALUES (?, ?, ?, ?, ?, ?)
592
+ db.prepare(`
593
+ INSERT OR REPLACE INTO docs_cache (id, package_name, ecosystem, version, content, fetched_at)
594
+ VALUES (?, ?, ?, ?, ?, ?)
595
595
  `).run(randomUUID(), package_name, ecosystem, resolved_version, content, now);
596
596
  return { package_name, version: resolved_version, ecosystem, content: content.slice(0, max_chars), cached: false, fetched_at: now };
597
597
  }
@@ -606,20 +606,20 @@ export async function fetchAndCacheDocs(package_name, ecosystem, version, max_ch
606
606
  export function saveTaskPlan(plan_json, description_hash, project_dir) {
607
607
  const db = getDb();
608
608
  const id = randomUUID();
609
- db.prepare(`
610
- INSERT INTO task_plans (id, description_hash, plan_json, project_dir, created_at)
611
- VALUES (?, ?, ?, ?, datetime('now'))
609
+ db.prepare(`
610
+ INSERT INTO task_plans (id, description_hash, plan_json, project_dir, created_at)
611
+ VALUES (?, ?, ?, ?, datetime('now'))
612
612
  `).run(id, description_hash, plan_json, project_dir ?? null);
613
613
  return id;
614
614
  }
615
615
  export function getTaskPlan(description_hash) {
616
616
  const db = getDb();
617
- const row = db.prepare(`
618
- SELECT id, plan_json FROM task_plans
619
- WHERE description_hash = ?
620
- AND created_at > datetime('now', '-7 days')
621
- ORDER BY created_at DESC
622
- LIMIT 1
617
+ const row = db.prepare(`
618
+ SELECT id, plan_json FROM task_plans
619
+ WHERE description_hash = ?
620
+ AND created_at > datetime('now', '-7 days')
621
+ ORDER BY created_at DESC
622
+ LIMIT 1
623
623
  `).get(description_hash);
624
624
  return row ?? null;
625
625
  }
@@ -660,11 +660,11 @@ export function getUsageStatus() {
660
660
  // Today's requests from rate_usage
661
661
  const rateRows = db.prepare('SELECT platform, request_count FROM rate_usage WHERE date_key = ?').all(today);
662
662
  // Today's tokens + connection_type breakdown from usage_events
663
- const eventRows = db.prepare(`
664
- SELECT platform, connection_type, SUM(tokens) as total_tokens, COUNT(*) as cnt
665
- FROM usage_events
666
- WHERE DATE(recorded_at) = ?
667
- GROUP BY platform, connection_type
663
+ const eventRows = db.prepare(`
664
+ SELECT platform, connection_type, SUM(tokens) as total_tokens, COUNT(*) as cnt
665
+ FROM usage_events
666
+ WHERE DATE(recorded_at) = ?
667
+ GROUP BY platform, connection_type
668
668
  `).all(today);
669
669
  const platforms = ['claude', 'gemini', 'codex'];
670
670
  const by_platform = platforms.map(p => {
@@ -683,12 +683,12 @@ export function getUsageStatus() {
683
683
  };
684
684
  });
685
685
  // Last 7 days history
686
- const history = db.prepare(`
687
- SELECT DATE(recorded_at) as date, COUNT(*) as total_requests, SUM(tokens) as total_tokens
688
- FROM usage_events
689
- WHERE recorded_at >= date('now', '-7 days')
690
- GROUP BY DATE(recorded_at)
691
- ORDER BY date DESC
686
+ const history = db.prepare(`
687
+ SELECT DATE(recorded_at) as date, COUNT(*) as total_requests, SUM(tokens) as total_tokens
688
+ FROM usage_events
689
+ WHERE recorded_at >= date('now', '-7 days')
690
+ GROUP BY DATE(recorded_at)
691
+ ORDER BY date DESC
692
692
  `).all();
693
693
  // Warnings
694
694
  const warnings = [];
@@ -796,7 +796,7 @@ export function logUsage(entry) {
796
796
  const db = getDb();
797
797
  const estimated_tokens = Math.ceil(entry.output.length / 4);
798
798
  const exceeded = estimated_tokens > entry.max_tokens ? 1 : 0;
799
- db.prepare(`INSERT INTO usage_log (id, tool_name, session_id, max_tokens, estimated_tokens, exceeded, created_at)
799
+ db.prepare(`INSERT INTO usage_log (id, tool_name, session_id, max_tokens, estimated_tokens, exceeded, created_at)
800
800
  VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`).run(randomUUID(), entry.tool_name, entry.session_id ?? null, entry.max_tokens, estimated_tokens, exceeded);
801
801
  return { exceeded: exceeded === 1, estimated_tokens };
802
802
  }
@@ -814,16 +814,16 @@ export function upsertContextUsage(opts) {
814
814
  const db = getDb();
815
815
  const usage_pct = Math.round((opts.token_count / opts.context_window) * 100 * 10) / 10;
816
816
  const now = new Date().toISOString();
817
- db.prepare(`
818
- INSERT INTO context_usage (platform, model, token_count, context_window, usage_pct, session_id, updated_at)
819
- VALUES (?, ?, ?, ?, ?, ?, ?)
820
- ON CONFLICT(platform) DO UPDATE SET
821
- model = excluded.model,
822
- token_count = excluded.token_count,
823
- context_window = excluded.context_window,
824
- usage_pct = excluded.usage_pct,
825
- session_id = excluded.session_id,
826
- updated_at = excluded.updated_at
817
+ db.prepare(`
818
+ INSERT INTO context_usage (platform, model, token_count, context_window, usage_pct, session_id, updated_at)
819
+ VALUES (?, ?, ?, ?, ?, ?, ?)
820
+ ON CONFLICT(platform) DO UPDATE SET
821
+ model = excluded.model,
822
+ token_count = excluded.token_count,
823
+ context_window = excluded.context_window,
824
+ usage_pct = excluded.usage_pct,
825
+ session_id = excluded.session_id,
826
+ updated_at = excluded.updated_at
827
827
  `).run(opts.platform, opts.model ?? null, opts.token_count, opts.context_window, usage_pct, opts.session_id ?? null, now);
828
828
  }
829
829
  export function getContextUsage(platform) {