@jigyasudham/veto 0.8.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +209 -52
  2. package/dist/agents/executor.js +36 -3
  3. package/dist/cli.js +246 -7
  4. package/dist/context/reader.js +113 -0
  5. package/dist/council/index.js +3 -1
  6. package/dist/plugins/loader.js +49 -0
  7. package/dist/router/index.js +2 -2
  8. package/dist/router/learning-updater.js +45 -1
  9. package/dist/server.js +478 -14
  10. package/dist/watcher/index.js +77 -0
  11. package/dist/workflow/pipeline.js +64 -0
  12. package/package.json +12 -3
  13. package/.claude/settings.local.json +0 -9
  14. package/src/adapters/claude.ts +0 -70
  15. package/src/adapters/codex.ts +0 -71
  16. package/src/adapters/gemini.ts +0 -71
  17. package/src/adapters/index.ts +0 -217
  18. package/src/agents/development/api.ts +0 -120
  19. package/src/agents/development/backend.ts +0 -85
  20. package/src/agents/development/coder.ts +0 -213
  21. package/src/agents/development/database.ts +0 -83
  22. package/src/agents/development/debugger.ts +0 -238
  23. package/src/agents/development/devops.ts +0 -86
  24. package/src/agents/development/frontend.ts +0 -85
  25. package/src/agents/development/migration.ts +0 -144
  26. package/src/agents/development/performance.ts +0 -144
  27. package/src/agents/development/refactor.ts +0 -86
  28. package/src/agents/development/reviewer.ts +0 -268
  29. package/src/agents/development/tester.ts +0 -151
  30. package/src/agents/executor.ts +0 -158
  31. package/src/agents/memory/context-manager.ts +0 -171
  32. package/src/agents/memory/decision-logger.ts +0 -160
  33. package/src/agents/memory/knowledge-base.ts +0 -124
  34. package/src/agents/memory/pattern-learner.ts +0 -143
  35. package/src/agents/memory/project-mapper.ts +0 -118
  36. package/src/agents/quality/accessibility.ts +0 -99
  37. package/src/agents/quality/code-quality.ts +0 -115
  38. package/src/agents/quality/compatibility.ts +0 -58
  39. package/src/agents/quality/documentation.ts +0 -105
  40. package/src/agents/quality/error-handling.ts +0 -96
  41. package/src/agents/research/competitor-analyzer.ts +0 -45
  42. package/src/agents/research/cost-analyzer.ts +0 -54
  43. package/src/agents/research/estimator.ts +0 -60
  44. package/src/agents/research/ethics-bias.ts +0 -113
  45. package/src/agents/research/researcher.ts +0 -114
  46. package/src/agents/research/risk-assessor.ts +0 -63
  47. package/src/agents/research/tech-advisor.ts +0 -55
  48. package/src/agents/security/auth.ts +0 -287
  49. package/src/agents/security/dependency-audit.ts +0 -337
  50. package/src/agents/security/penetration.ts +0 -262
  51. package/src/agents/security/privacy.ts +0 -285
  52. package/src/agents/security/scanner.ts +0 -322
  53. package/src/agents/security/secrets.ts +0 -249
  54. package/src/agents/types.ts +0 -66
  55. package/src/agents/workflow/automation.ts +0 -59
  56. package/src/agents/workflow/file-manager.ts +0 -52
  57. package/src/agents/workflow/git-agent.ts +0 -55
  58. package/src/agents/workflow/reporter.ts +0 -51
  59. package/src/agents/workflow/search-agent.ts +0 -40
  60. package/src/agents/workflow/task-coordinator.ts +0 -41
  61. package/src/agents/workflow/task-planner.ts +0 -47
  62. package/src/cli.ts +0 -204
  63. package/src/council/decision-engine.ts +0 -171
  64. package/src/council/devil-advocate.ts +0 -116
  65. package/src/council/index.ts +0 -44
  66. package/src/council/lead-developer.ts +0 -118
  67. package/src/council/legal-compliance.ts +0 -152
  68. package/src/council/product-manager.ts +0 -102
  69. package/src/council/security.ts +0 -172
  70. package/src/council/system-architect.ts +0 -132
  71. package/src/council/types.ts +0 -33
  72. package/src/council/ux-designer.ts +0 -121
  73. package/src/memory/local.ts +0 -305
  74. package/src/memory/schema.ts +0 -174
  75. package/src/memory/sync.ts +0 -274
  76. package/src/router/complexity-scorer.ts +0 -96
  77. package/src/router/context-compressor.ts +0 -74
  78. package/src/router/index.ts +0 -60
  79. package/src/router/learning-updater.ts +0 -271
  80. package/src/router/model-selector.ts +0 -83
  81. package/src/router/rate-monitor.ts +0 -103
  82. package/src/server.ts +0 -1038
  83. package/src/skills/development/skill-api-design.ts +0 -329
  84. package/src/skills/development/skill-auth.ts +0 -271
  85. package/src/skills/development/skill-ci-cd.ts +0 -0
  86. package/src/skills/development/skill-crud.ts +0 -209
  87. package/src/skills/development/skill-db-schema.ts +0 -0
  88. package/src/skills/development/skill-docker.ts +0 -0
  89. package/src/skills/development/skill-env-setup.ts +0 -0
  90. package/src/skills/development/skill-scaffold.ts +0 -323
  91. package/src/skills/intelligence/skill-complexity-score.ts +0 -69
  92. package/src/skills/intelligence/skill-cost-track.ts +0 -39
  93. package/src/skills/intelligence/skill-learning-loop.ts +0 -69
  94. package/src/skills/intelligence/skill-pattern-detect.ts +0 -38
  95. package/src/skills/intelligence/skill-rate-watch.ts +0 -61
  96. package/src/skills/memory/skill-context-compress.ts +0 -98
  97. package/src/skills/memory/skill-cross-sync.ts +0 -104
  98. package/src/skills/memory/skill-decision-log.ts +0 -119
  99. package/src/skills/memory/skill-session-restore.ts +0 -59
  100. package/src/skills/memory/skill-session-save.ts +0 -94
  101. package/src/skills/quality/skill-accessibility.ts +0 -0
  102. package/src/skills/quality/skill-code-review.ts +0 -84
  103. package/src/skills/quality/skill-docs-gen.ts +0 -0
  104. package/src/skills/quality/skill-perf-audit.ts +0 -0
  105. package/src/skills/quality/skill-security-scan.ts +0 -91
  106. package/src/skills/quality/skill-test-suite.ts +0 -290
  107. package/src/skills/workflow/skill-deploy.ts +0 -0
  108. package/src/skills/workflow/skill-git-workflow.ts +0 -0
  109. package/src/skills/workflow/skill-rollback.ts +0 -0
  110. package/src/skills/workflow/skill-task-breakdown.ts +0 -0
  111. package/tsconfig.json +0 -20
@@ -1,274 +0,0 @@
1
- // Memory export/import — file-based cross-machine continuity
2
- // No external services. Export to JSON, copy the file, import on another machine.
3
-
4
- import { readFileSync, writeFileSync, existsSync } from 'node:fs';
5
- import { join } from 'node:path';
6
- import { homedir } from 'node:os';
7
- import { getDb, getDbPath } from './local.js';
8
-
9
- const DEFAULT_EXPORT_PATH = join(homedir(), '.veto', 'veto-export.json');
10
-
11
- export type ExportResult = {
12
- success: boolean;
13
- export_path: string;
14
- exported: Record<string, number>;
15
- exported_at: string;
16
- error?: string;
17
- next_step: string;
18
- };
19
-
20
- export type ImportResult = {
21
- success: boolean;
22
- import_path: string;
23
- merged: Record<string, number>;
24
- skipped: Record<string, number>;
25
- imported_at: string;
26
- error?: string;
27
- };
28
-
29
- export type DbSizeResult = {
30
- db_path: string;
31
- tables: Record<string, number>;
32
- };
33
-
34
- export function exportMemory(outputPath?: string): ExportResult {
35
- const exportPath = outputPath ?? DEFAULT_EXPORT_PATH;
36
- const db = getDb();
37
-
38
- try {
39
- const sessions = db.prepare('SELECT * FROM sessions ORDER BY created_at DESC').all();
40
- const decisions = db.prepare('SELECT * FROM decisions ORDER BY made_at DESC').all();
41
- const knowledge = db.prepare('SELECT * FROM knowledge_base ORDER BY created_at DESC').all();
42
- const patterns = db.prepare('SELECT * FROM patterns ORDER BY confidence DESC').all();
43
- const projectMaps = db.prepare('SELECT * FROM project_map ORDER BY updated_at DESC').all();
44
- const councilOutcomes = db.prepare('SELECT * FROM council_outcomes ORDER BY debated_at DESC').all();
45
-
46
- const payload = {
47
- veto_export_version: 1,
48
- exported_at: new Date().toISOString(),
49
- db_path: getDbPath(),
50
- data: {
51
- sessions,
52
- decisions,
53
- knowledge_base: knowledge,
54
- patterns,
55
- project_map: projectMaps,
56
- council_outcomes: councilOutcomes,
57
- },
58
- };
59
-
60
- writeFileSync(exportPath, JSON.stringify(payload, null, 2), 'utf-8');
61
-
62
- const exported = {
63
- sessions: sessions.length,
64
- decisions: decisions.length,
65
- knowledge_base: knowledge.length,
66
- patterns: patterns.length,
67
- project_map: projectMaps.length,
68
- council_outcomes: councilOutcomes.length,
69
- };
70
-
71
- return {
72
- success: true,
73
- export_path: exportPath,
74
- exported,
75
- exported_at: payload.exported_at,
76
- next_step: `Copy ${exportPath} to your other machine, then call veto_memory_import with that file path.`,
77
- };
78
- } catch (err) {
79
- return {
80
- success: false,
81
- export_path: exportPath,
82
- exported: {},
83
- exported_at: new Date().toISOString(),
84
- error: err instanceof Error ? err.message : String(err),
85
- next_step: 'Fix the error above and retry.',
86
- };
87
- }
88
- }
89
-
90
- export function importMemory(inputPath?: string): ImportResult {
91
- const importPath = inputPath ?? DEFAULT_EXPORT_PATH;
92
-
93
- if (!existsSync(importPath)) {
94
- return {
95
- success: false,
96
- import_path: importPath,
97
- merged: {},
98
- skipped: {},
99
- imported_at: new Date().toISOString(),
100
- error: `File not found: ${importPath}. Run veto_memory_export on your other machine first, then copy the file here.`,
101
- };
102
- }
103
-
104
- const db = getDb();
105
- const merged: Record<string, number> = {};
106
- const skipped: Record<string, number> = {};
107
-
108
- try {
109
- const raw = readFileSync(importPath, 'utf-8');
110
- const payload = JSON.parse(raw) as {
111
- veto_export_version: number;
112
- data: Record<string, Record<string, unknown>[]>;
113
- };
114
-
115
- if (payload.veto_export_version !== 1) {
116
- throw new Error(`Unknown export version: ${payload.veto_export_version}`);
117
- }
118
-
119
- const { sessions = [], decisions = [], knowledge_base = [], patterns = [], project_map = [], council_outcomes = [] } = payload.data;
120
-
121
- merged['sessions'] = 0; skipped['sessions'] = 0;
122
- for (const s of sessions) {
123
- const r = db.prepare(`
124
- INSERT OR IGNORE INTO sessions
125
- (id, started_at, ended_at, platform, project_dir, summary, context, task_state, token_count, created_at)
126
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
127
- `).run(
128
- String(s['id'] ?? ''), String(s['started_at'] ?? ''),
129
- s['ended_at'] != null ? String(s['ended_at']) : null,
130
- String(s['platform'] ?? 'claude'),
131
- s['project_dir'] != null ? String(s['project_dir']) : null,
132
- s['summary'] != null ? String(s['summary']) : null,
133
- s['context'] != null ? String(s['context']) : null,
134
- s['task_state'] != null ? String(s['task_state']) : null,
135
- typeof s['token_count'] === 'number' ? s['token_count'] : 0,
136
- String(s['created_at'] ?? new Date().toISOString())
137
- ) as { changes: number };
138
- if (r.changes > 0) merged['sessions']++; else skipped['sessions']++;
139
- }
140
-
141
- merged['decisions'] = 0; skipped['decisions'] = 0;
142
- for (const d of decisions) {
143
- const r = db.prepare(`
144
- INSERT OR IGNORE INTO decisions
145
- (id, session_id, made_at, decision, rationale, council_verdict, files_affected, overridden)
146
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
147
- `).run(
148
- String(d['id'] ?? ''), String(d['session_id'] ?? ''),
149
- String(d['made_at'] ?? ''), String(d['decision'] ?? ''),
150
- d['rationale'] != null ? String(d['rationale']) : null,
151
- d['council_verdict'] != null ? String(d['council_verdict']) : null,
152
- d['files_affected'] != null ? String(d['files_affected']) : null,
153
- typeof d['overridden'] === 'number' ? d['overridden'] : 0
154
- ) as { changes: number };
155
- if (r.changes > 0) merged['decisions']++; else skipped['decisions']++;
156
- }
157
-
158
- merged['knowledge_base'] = 0; skipped['knowledge_base'] = 0;
159
- for (const k of knowledge_base) {
160
- const r = db.prepare(`
161
- INSERT OR IGNORE INTO knowledge_base
162
- (id, type, title, content, tags, project_dir, session_id, relevance, accessed_count, created_at, updated_at)
163
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
164
- `).run(
165
- String(k['id'] ?? ''),
166
- k['type'] != null ? String(k['type']) : 'solution',
167
- String(k['title'] ?? ''), String(k['content'] ?? ''),
168
- k['tags'] != null ? String(k['tags']) : null,
169
- k['project_dir'] != null ? String(k['project_dir']) : null,
170
- k['session_id'] != null ? String(k['session_id']) : null,
171
- typeof k['relevance'] === 'number' ? k['relevance'] : 1.0,
172
- typeof k['accessed_count'] === 'number' ? k['accessed_count'] : 0,
173
- String(k['created_at'] ?? new Date().toISOString()),
174
- String(k['updated_at'] ?? new Date().toISOString())
175
- ) as { changes: number };
176
- if (r.changes > 0) merged['knowledge_base']++; else skipped['knowledge_base']++;
177
- }
178
-
179
- merged['patterns'] = 0; skipped['patterns'] = 0;
180
- for (const p of patterns) {
181
- const existing = db.prepare('SELECT seen_count, confidence FROM patterns WHERE pattern_key = ?').get(String(p['pattern_key'] ?? '')) as { seen_count: number; confidence: number } | undefined;
182
- if (existing) {
183
- // Merge: take higher confidence, sum seen counts
184
- const mergedConf = Math.max(existing.confidence, typeof p['confidence'] === 'number' ? p['confidence'] : 1.0);
185
- const mergedCount = existing.seen_count + (typeof p['seen_count'] === 'number' ? p['seen_count'] : 1);
186
- db.prepare('UPDATE patterns SET confidence = ?, seen_count = ?, updated_at = ? WHERE pattern_key = ?')
187
- .run(mergedConf, mergedCount, new Date().toISOString(), String(p['pattern_key'] ?? ''));
188
- skipped['patterns']++;
189
- } else {
190
- db.prepare(`
191
- INSERT INTO patterns (id, pattern_key, pattern_val, confidence, seen_count, updated_at)
192
- VALUES (?, ?, ?, ?, ?, ?)
193
- `).run(
194
- String(p['id'] ?? ''), String(p['pattern_key'] ?? ''),
195
- String(p['pattern_val'] ?? ''),
196
- typeof p['confidence'] === 'number' ? p['confidence'] : 1.0,
197
- typeof p['seen_count'] === 'number' ? p['seen_count'] : 1,
198
- String(p['updated_at'] ?? new Date().toISOString())
199
- );
200
- merged['patterns']++;
201
- }
202
- }
203
-
204
- merged['project_map'] = 0; skipped['project_map'] = 0;
205
- for (const m of project_map) {
206
- const r = db.prepare(`
207
- INSERT OR IGNORE INTO project_map (id, project_dir, structure, key_modules, tech_stack, updated_at)
208
- VALUES (?, ?, ?, ?, ?, ?)
209
- `).run(
210
- String(m['id'] ?? ''), String(m['project_dir'] ?? ''),
211
- String(m['structure'] ?? '{}'),
212
- m['key_modules'] != null ? String(m['key_modules']) : null,
213
- m['tech_stack'] != null ? String(m['tech_stack']) : null,
214
- String(m['updated_at'] ?? new Date().toISOString())
215
- ) as { changes: number };
216
- if (r.changes > 0) merged['project_map']++; else skipped['project_map']++;
217
- }
218
-
219
- merged['council_outcomes'] = 0; skipped['council_outcomes'] = 0;
220
- for (const c of council_outcomes) {
221
- const r = db.prepare(`
222
- INSERT OR IGNORE INTO council_outcomes
223
- (id, session_id, task, verdict, lead_dev, pm, architect, ux, devil, legal, security, recommended, debated_at)
224
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
225
- `).run(
226
- String(c['id'] ?? ''),
227
- c['session_id'] != null ? String(c['session_id']) : null,
228
- String(c['task'] ?? ''), String(c['verdict'] ?? ''),
229
- c['lead_dev'] != null ? String(c['lead_dev']) : null,
230
- c['pm'] != null ? String(c['pm']) : null,
231
- c['architect'] != null ? String(c['architect']) : null,
232
- c['ux'] != null ? String(c['ux']) : null,
233
- c['devil'] != null ? String(c['devil']) : null,
234
- c['legal'] != null ? String(c['legal']) : null,
235
- c['security'] != null ? String(c['security']) : null,
236
- c['recommended'] != null ? String(c['recommended']) : null,
237
- String(c['debated_at'] ?? new Date().toISOString())
238
- ) as { changes: number };
239
- if (r.changes > 0) merged['council_outcomes']++; else skipped['council_outcomes']++;
240
- }
241
-
242
- return {
243
- success: true,
244
- import_path: importPath,
245
- merged,
246
- skipped,
247
- imported_at: new Date().toISOString(),
248
- };
249
- } catch (err) {
250
- return {
251
- success: false,
252
- import_path: importPath,
253
- merged,
254
- skipped,
255
- imported_at: new Date().toISOString(),
256
- error: err instanceof Error ? err.message : String(err),
257
- };
258
- }
259
- }
260
-
261
- export function getLocalDbSize(): DbSizeResult {
262
- const db = getDb();
263
- const tables = ['sessions', 'decisions', 'council_outcomes', 'knowledge_base', 'patterns', 'project_map', 'learning_data'];
264
- const counts: Record<string, number> = {};
265
- for (const table of tables) {
266
- try {
267
- const row = db.prepare(`SELECT COUNT(*) as c FROM ${table}`).get() as { c: number };
268
- counts[table] = row.c;
269
- } catch {
270
- counts[table] = 0;
271
- }
272
- }
273
- return { db_path: getDbPath(), tables: counts };
274
- }
@@ -1,96 +0,0 @@
1
- // Scores a task description 0-100 locally — zero tokens spent
2
-
3
- export type ComplexityFactors = {
4
- word_count_score: number;
5
- keyword_score: number;
6
- depth_score: number;
7
- files_score: number;
8
- council_bonus: number;
9
- };
10
-
11
- export type ComplexityResult = {
12
- score: number;
13
- tier: 1 | 2 | 3;
14
- factors: ComplexityFactors;
15
- council_required: boolean;
16
- };
17
-
18
- // 5 pts each — strong signal of high complexity
19
- const HIGH_KEYWORDS = [
20
- 'architecture', 'security', 'authenticat', 'authorizat', 'migrat',
21
- 'refactor', 'scalab', 'concurrent', 'distributed', 'oauth', 'jwt',
22
- 'rbac', 'encryption', 'cryptograph', 'penetration', 'vulnerabilit',
23
- 'infrastructure', 'compliance', 'performance',
24
- ];
25
-
26
- // 2 pts each — moderate complexity signal
27
- const MEDIUM_KEYWORDS = [
28
- 'component', 'function', 'test', 'api', 'database', 'query', 'schema',
29
- 'deploy', 'docker', 'implement', 'build', 'feature', 'module',
30
- 'service', 'endpoint', 'integration', 'configuration',
31
- ];
32
-
33
- // Council is always required for these topics
34
- const COUNCIL_TRIGGERS = [
35
- 'architecture', 'security', 'auth', 'migrat', 'vulnerabilit',
36
- 'encryption', 'infrastructure', 'breaking change', 'drop table',
37
- 'delete all', 'remove all',
38
- ];
39
-
40
- export function scoreComplexity(
41
- task: string,
42
- filesAffected = 1,
43
- forceCouncil = false,
44
- thresholds?: { tier1_max: number; tier2_max: number }
45
- ): ComplexityResult {
46
- const TIER1_MAX = thresholds?.tier1_max ?? 30;
47
- const TIER2_MAX = thresholds?.tier2_max ?? 70;
48
- const lower = task.toLowerCase();
49
- const words = lower.split(/\s+/).filter(Boolean);
50
-
51
- // Factor 1: word count → 0-20 pts (1 pt per 3 words, cap 20)
52
- const word_count_score = Math.min(20, Math.floor(words.length / 3));
53
-
54
- // Factor 2: technical keywords → 0-30 pts
55
- let keyword_score = 0;
56
- let council_required = forceCouncil;
57
-
58
- for (const word of words) {
59
- for (const kw of HIGH_KEYWORDS) {
60
- if (word.includes(kw)) { keyword_score += 5; break; }
61
- }
62
- for (const kw of MEDIUM_KEYWORDS) {
63
- if (word.includes(kw)) { keyword_score += 2; break; }
64
- }
65
- }
66
- for (const trigger of COUNCIL_TRIGGERS) {
67
- if (lower.includes(trigger)) { council_required = true; break; }
68
- }
69
- keyword_score = Math.min(30, keyword_score);
70
-
71
- // Factor 3: task depth → 0-20 pts (conjunctions, length, multi-step)
72
- let depth_score = 0;
73
- if (lower.includes(' and ') || lower.includes(' with ')) depth_score += 5;
74
- if (lower.includes(',') || lower.includes(' plus ')) depth_score += 5;
75
- if (words.length > 20) depth_score += 5;
76
- if (words.length > 40) depth_score += 5;
77
- depth_score = Math.min(20, depth_score);
78
-
79
- // Factor 4: files affected → 0-20 pts
80
- const files_score = Math.min(20, (filesAffected - 1) * 3);
81
-
82
- // Factor 5: council bonus — pushes score into Tier 3 territory
83
- const council_bonus = council_required ? 10 : 0;
84
-
85
- const raw = word_count_score + keyword_score + depth_score + files_score + council_bonus;
86
- // Council tasks always land in Tier 3 — floor at 71
87
- const score = Math.min(100, council_required ? Math.max(71, raw) : raw);
88
- const tier: 1 | 2 | 3 = score <= TIER1_MAX ? 1 : score <= TIER2_MAX ? 2 : 3;
89
-
90
- return {
91
- score,
92
- tier,
93
- factors: { word_count_score, keyword_score, depth_score, files_score, council_bonus },
94
- council_required,
95
- };
96
- }
@@ -1,74 +0,0 @@
1
- // Trims context before model calls to avoid wasting tokens
2
- // Thresholds from VETO_VISION_FINAL.md:
3
- // < 2k tokens → passthrough
4
- // 2k-8k tokens → compress (drop irrelevant sections)
5
- // > 8k tokens → hard-compress (tail + file references only)
6
-
7
- export type CompressionStrategy = 'passthrough' | 'compress' | 'hard-compress';
8
-
9
- export type CompressionResult = {
10
- original_tokens: number;
11
- compressed_tokens: number;
12
- compression_ratio: number;
13
- content: string;
14
- strategy: CompressionStrategy;
15
- };
16
-
17
- // Rough 4-chars-per-token estimate — good enough for routing decisions
18
- export function estimateTokens(text: string): number {
19
- return Math.ceil(text.length / 4);
20
- }
21
-
22
- function extractRelevantSections(context: string, relevantFiles: string[]): string {
23
- if (relevantFiles.length === 0) return context;
24
-
25
- const lines = context.split('\n');
26
- const kept: string[] = [];
27
- let inRelevant = false;
28
-
29
- for (const line of lines) {
30
- const isHeader = /^(---|===|##|#)/.test(line.trim());
31
- if (isHeader) {
32
- inRelevant = relevantFiles.some((f) => line.includes(f));
33
- }
34
- if (inRelevant || relevantFiles.some((f) => line.includes(f))) {
35
- kept.push(line);
36
- }
37
- }
38
-
39
- return kept.length > 0 ? kept.join('\n') : context;
40
- }
41
-
42
- function hardCompress(context: string, relevantFiles: string[]): string {
43
- const lines = context.split('\n');
44
- const fileRefs = relevantFiles.length > 0
45
- ? lines.filter((l) => relevantFiles.some((f) => l.includes(f)))
46
- : [];
47
- const tail = lines.slice(-50);
48
- const combined = [...new Set([...fileRefs, ...tail])];
49
- return combined.join('\n');
50
- }
51
-
52
- export function compressContext(context: string, relevantFiles: string[] = []): CompressionResult {
53
- const original_tokens = estimateTokens(context);
54
- let strategy: CompressionStrategy;
55
- let content: string;
56
-
57
- if (original_tokens < 2000) {
58
- strategy = 'passthrough';
59
- content = context;
60
- } else if (original_tokens < 8000) {
61
- strategy = 'compress';
62
- content = extractRelevantSections(context, relevantFiles);
63
- } else {
64
- strategy = 'hard-compress';
65
- content = hardCompress(context, relevantFiles);
66
- }
67
-
68
- const compressed_tokens = estimateTokens(content);
69
- const compression_ratio = original_tokens > 0
70
- ? Math.round((1 - compressed_tokens / original_tokens) * 100) / 100
71
- : 0;
72
-
73
- return { original_tokens, compressed_tokens, compression_ratio, content, strategy };
74
- }
@@ -1,60 +0,0 @@
1
- // Router entry point — composes all sub-modules into a single routeTask() call
2
-
3
- import { scoreComplexity } from './complexity-scorer.js';
4
- import { selectModel } from './model-selector.js';
5
- import { getRateStatus, trackRequest, getRoutingAdvice } from './rate-monitor.js';
6
- import { compressContext, estimateTokens } from './context-compressor.js';
7
- import { recordOutcome, getLearningStats, getLearnedThresholds, applyLearnedThresholds, getAgentPerformanceStats, getTaskTypeBreakdown, getCouncilInsights } from './learning-updater.js';
8
-
9
- export type { ComplexityResult, ComplexityFactors } from './complexity-scorer.js';
10
- export type { AgentType, Tier, ModelRecommendation } from './model-selector.js';
11
- export type { Platform, RateLimitEntry, RateStatus } from './rate-monitor.js';
12
- export type { CompressionStrategy, CompressionResult } from './context-compressor.js';
13
- export type { LearningStats, LearnedThresholds, AgentPerformanceStat, TaskTypeBreakdown, CouncilInsight } from './learning-updater.js';
14
- export { estimateTokens, getRateStatus, trackRequest, recordOutcome, getLearningStats, getLearnedThresholds, applyLearnedThresholds, getAgentPerformanceStats, getTaskTypeBreakdown, getCouncilInsights };
15
-
16
- export type RouteOptions = {
17
- agentType?: import('./model-selector.js').AgentType;
18
- filesAffected?: number;
19
- forceCouncil?: boolean;
20
- context?: string;
21
- relevantFiles?: string[];
22
- preferredPlatform?: import('./rate-monitor.js').Platform;
23
- };
24
-
25
- export type RouteResult = {
26
- complexity: import('./complexity-scorer.js').ComplexityResult;
27
- model: import('./model-selector.js').ModelRecommendation;
28
- rate_status: import('./rate-monitor.js').RateStatus;
29
- context_plan?: import('./context-compressor.js').CompressionResult;
30
- effective_platform: import('./rate-monitor.js').Platform;
31
- routed_at: string;
32
- };
33
-
34
- export function routeTask(task: string, options: RouteOptions = {}): RouteResult {
35
- const learned = getLearnedThresholds();
36
- const complexity = scoreComplexity(task, options.filesAffected, options.forceCouncil, learned.source === 'learned' ? learned : undefined);
37
- const model = selectModel(complexity.score, options.agentType ?? 'dynamic');
38
-
39
- const preferred = options.preferredPlatform ?? 'claude';
40
- // Only shift Tier 1/2 away from Claude on warning; Tier 3 always stays on best model
41
- const effective_platform =
42
- model.tier === 3 ? preferred : getRoutingAdvice(preferred);
43
-
44
- trackRequest(effective_platform);
45
-
46
- const rate_status = getRateStatus();
47
-
48
- const context_plan = options.context
49
- ? compressContext(options.context, options.relevantFiles ?? [])
50
- : undefined;
51
-
52
- return {
53
- complexity,
54
- model,
55
- rate_status,
56
- context_plan,
57
- effective_platform,
58
- routed_at: new Date().toISOString(),
59
- };
60
- }