konsilio 0.3.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 (80) hide show
  1. package/LICENSE.md +24 -0
  2. package/README.md +170 -0
  3. package/build/cli/history.d.ts +2 -0
  4. package/build/cli/history.js +179 -0
  5. package/build/cli/history.js.map +1 -0
  6. package/build/config.d.ts +38 -0
  7. package/build/config.js +118 -0
  8. package/build/config.js.map +1 -0
  9. package/build/container.d.ts +32 -0
  10. package/build/container.js +102 -0
  11. package/build/container.js.map +1 -0
  12. package/build/db/schema.d.ts +1 -0
  13. package/build/db/schema.js +67 -0
  14. package/build/db/schema.js.map +1 -0
  15. package/build/index.d.ts +2 -0
  16. package/build/index.js +140 -0
  17. package/build/index.js.map +1 -0
  18. package/build/konsilio.json +25 -0
  19. package/build/konsilio.schema.json +140 -0
  20. package/build/logger.d.ts +84 -0
  21. package/build/logger.js +121 -0
  22. package/build/logger.js.map +1 -0
  23. package/build/personas/expert.d.ts +33 -0
  24. package/build/personas/expert.js +46 -0
  25. package/build/personas/expert.js.map +1 -0
  26. package/build/personas/index.d.ts +9 -0
  27. package/build/personas/index.js +11 -0
  28. package/build/personas/index.js.map +1 -0
  29. package/build/personas/lead.d.ts +33 -0
  30. package/build/personas/lead.js +51 -0
  31. package/build/personas/lead.js.map +1 -0
  32. package/build/personas/schemas.d.ts +313 -0
  33. package/build/personas/schemas.js +97 -0
  34. package/build/personas/schemas.js.map +1 -0
  35. package/build/prompts/consolidation/critique.md +59 -0
  36. package/build/prompts/consolidation/decision.md +51 -0
  37. package/build/prompts/consolidation/extraction.md +46 -0
  38. package/build/prompts/consolidation/synthesis.md +42 -0
  39. package/build/prompts/expert-rules.md +50 -0
  40. package/build/prompts/personas/dev-tooling.md +27 -0
  41. package/build/prompts/personas/devops.md +26 -0
  42. package/build/prompts/personas/distributed-systems.md +28 -0
  43. package/build/prompts/personas/graph-dba.md +27 -0
  44. package/build/prompts/personas/node-fullstack.md +27 -0
  45. package/build/prompts/personas/performance.md +26 -0
  46. package/build/prompts/personas/security.md +26 -0
  47. package/build/prompts/personas/test-architect.md +29 -0
  48. package/build/prompts/personas/test-quoted.md +14 -0
  49. package/build/prompts/personas/typescript.md +26 -0
  50. package/build/prompts/personas/ux-dx.md +29 -0
  51. package/build/prompts/workflow-rules.md +3 -0
  52. package/build/server.d.ts +24 -0
  53. package/build/server.js +181 -0
  54. package/build/server.js.map +1 -0
  55. package/build/services/cache.service.d.ts +49 -0
  56. package/build/services/cache.service.js +85 -0
  57. package/build/services/cache.service.js.map +1 -0
  58. package/build/services/council.service.d.ts +111 -0
  59. package/build/services/council.service.js +361 -0
  60. package/build/services/council.service.js.map +1 -0
  61. package/build/services/database.service.d.ts +70 -0
  62. package/build/services/database.service.js +221 -0
  63. package/build/services/database.service.js.map +1 -0
  64. package/build/services/formatter.service.d.ts +52 -0
  65. package/build/services/formatter.service.js +133 -0
  66. package/build/services/formatter.service.js.map +1 -0
  67. package/build/services/index.d.ts +18 -0
  68. package/build/services/index.js +13 -0
  69. package/build/services/index.js.map +1 -0
  70. package/build/services/openrouter.service.d.ts +58 -0
  71. package/build/services/openrouter.service.js +128 -0
  72. package/build/services/openrouter.service.js.map +1 -0
  73. package/build/services/persona.service.d.ts +43 -0
  74. package/build/services/persona.service.js +93 -0
  75. package/build/services/persona.service.js.map +1 -0
  76. package/build/services/prompt.service.d.ts +59 -0
  77. package/build/services/prompt.service.js +209 -0
  78. package/build/services/prompt.service.js.map +1 -0
  79. package/konsilio.schema.json +140 -0
  80. package/package.json +68 -0
package/LICENSE.md ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
package/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # Konsilio
2
+
3
+ **Council of Experts** — an MCP server that runs draft plans through a multi-persona architectural review before you write a single line of code.
4
+
5
+ ## TL;DR
6
+
7
+ Konsilio lets you run a draft plan through a panel of AI experts (security, performance, DevOps, etc.) before writing code.
8
+
9
+ It returns a structured blueprint so your coding model can implement it cleanly in one pass.
10
+
11
+ ## The Problem
12
+
13
+ You're mid-task and realize you need a plan: *"Why is this code not working? We need more logs → logging should be added → let me write a proposal for logging."*
14
+
15
+ You could feed that plan directly into a coding model and hope it gets it right. Or you could catch blind spots early by having specialists review it first.
16
+
17
+ ## The Solution
18
+
19
+ Konsilio implements a **multi-stage consulting pipeline**:
20
+
21
+ 1. **Write a proposal** — a short document describing what you want to build or change
22
+ 2. **Feed it to the Council** — multiple expert personas (security, performance, DevOps, testing, etc.) review the plan in parallel, each from their own angle
23
+ 3. **4-phase consolidation** — a lead agent extracts claims, critiques contradictions, makes accept/reject decisions, and synthesizes a final blueprint
24
+ 4. **Implement with a clean slate** — hand the blueprint to a coding-focused model. It starts with empty context and executes the plan in one pass
25
+
26
+ **Rinse. Repeat. Rewind Selectah!**
27
+
28
+ ## Usage
29
+
30
+ ```bash
31
+ # Install
32
+ npm install -g konsilio
33
+
34
+ # Configure (edit konsilio.json with your personas and models)
35
+ # Set OPENROUTER_API_KEY in your environment
36
+
37
+ # Use via MCP in your AI coding tool
38
+ # Tool: consult_council
39
+ # Params: draft_plan, tech_stack (optional), context_constraints (optional)
40
+ ```
41
+
42
+ ### Example
43
+
44
+ ```json
45
+ {
46
+ "draft_plan": "Add structured logging to all API endpoints with correlation IDs",
47
+ "tech_stack": "Node.js, Express, Pino, PostgreSQL",
48
+ "context_constraints": "Must run on Proxmox LXC, no external dependencies"
49
+ }
50
+ ```
51
+
52
+ Returns a blueprint with architecture directives, edge cases, constraints, and numbered next steps.
53
+
54
+ ## Configuration
55
+
56
+ ```json
57
+ {
58
+ "personas": {
59
+ "enabled": ["security", "performance", "devops", "test-architect"]
60
+ },
61
+ "models": {
62
+ "experts": "google/gemini-2.5-flash-lite",
63
+ "lead": "google/gemini-2.5-pro"
64
+ }
65
+ }
66
+ ```
67
+
68
+ Default personas: `security`, `performance`, `ux-dx`, `devops`, `typescript`, `graph-dba`, `node-fullstack`, `dev-tooling`, `distributed-systems`, `test-architect`
69
+
70
+ ```mermaid
71
+ flowchart TD
72
+ A[Identify Need During Development] --> B[Write Proposal Document]
73
+ B --> C[Submit to Konsilio Council]
74
+
75
+ subgraph Council["Council Review (Parallel)"]
76
+ C --> E1[🔒 Security Expert]
77
+ C --> E2[⚡ Performance Expert]
78
+ C --> E3[🚀 DevOps Expert]
79
+ C --> E4[🧪 Test Architect]
80
+ C --> E5[🎨 UX/DX Expert]
81
+ C --> E6[🛠️ Dev Tooling Expert]
82
+ end
83
+
84
+ E1 --> F[Prose Reports]
85
+ E2 --> F
86
+ E3 --> F
87
+ E4 --> F
88
+ E5 --> F
89
+ E6 --> F
90
+
91
+ F --> G[Formatter: prose → structured JSON]
92
+
93
+ subgraph Consolidation["4-Phase Consolidation"]
94
+ G --> H1[📋 Extraction Lead<br/>Extract all claims]
95
+ H1 --> H2[🔍 Critique Lead<br/>Find contradictions]
96
+ H2 --> H3[⚖️ Decision Lead<br/>Accept/Reject findings]
97
+ H3 --> H4[📝 Synthesis Lead<br/>Assemble blueprint]
98
+ end
99
+
100
+ H4 --> I[Final Blueprint<br/>with edge cases, constraints, next steps]
101
+ I --> J[Hand to Coding Model<br/>Clean slate, empty context]
102
+ J --> K[Implement in One Pass]
103
+
104
+ style Council fill:#f0f4ff,stroke:#4a6cf7,stroke-width:2px
105
+ style Consolidation fill:#fff8f0,stroke:#f7a44a,stroke-width:2px
106
+ style I fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
107
+ ```
108
+
109
+ ## Architecture
110
+
111
+ ### Expert Personas
112
+
113
+ Each expert is a focused agent with a specific lens:
114
+
115
+ | Persona | Focus |
116
+ |---------|-------|
117
+ | 🔒 Security | Auth, injection, rate limiting, data exposure |
118
+ | ⚡ Performance | Bottlenecks, caching, query patterns, scaling |
119
+ | 🚀 DevOps | Deployment, observability, infrastructure |
120
+ | 🧪 Test Architect | Coverage, edge cases, testability |
121
+ | 🎨 UX/DX | API design, developer experience, ergonomics |
122
+ | 🛠️ Dev Tooling | Build pipeline, linting, CI/CD |
123
+
124
+ Experts output **prose** — free-form analysis without JSON constraints.
125
+ **Note:** User-defined experts can be created by adding an `expert.md` file to `/data/personas/`
126
+
127
+ ### The Lead
128
+
129
+ The lead agent runs a 4-phase consolidation pipeline:
130
+
131
+ 1. **Extraction** — pulls all claims from expert reports into a unified list
132
+ 2. **Critique** — identifies contradictions, unsupported claims, and gaps
133
+ 3. **Decision** — explicitly accepts or rejects each finding
134
+ 4. **Synthesis** — assembles accepted findings into a coherent blueprint
135
+
136
+ ### The Formatter
137
+
138
+ A dedicated `gpt-4o-mini` instance converts expert prose to structured JSON using OpenAI's `response_format` feature. This keeps experts focused on analysis, not syntax.
139
+
140
+ ## Why This Works
141
+
142
+ ### 1. Specialized Experts Outperform Generalists
143
+
144
+ A council of focused expert agents, each primed with a specific role, surfaces more issues at lower cost than a single frontier model:
145
+
146
+ - **Chan et al. (2023)** — *"ChatEval: Towards Better LLM-based Evaluators through Multi-Agent Debate"* — showed that multiple role-conditioned agents debating produces more accurate evaluations than a single powerful model. [arXiv:2308.07201](https://arxiv.org/abs/2308.07201)
147
+
148
+ - **Du et al. (2023)** — *"Improving Factuality and Reasoning in Language Models through Multiagent Debate"* — demonstrated that multi-agent debate significantly improves accuracy over single-model inference, with agents catching each other's errors. [arXiv:2305.14325](https://arxiv.org/abs/2305.14325)
149
+
150
+ - **Liang et al. (2023)** — *"Ensemble Learning for Large Language Models"* — found that combining multiple specialized models outperforms a single large model on complex tasks while using fewer total tokens. [arXiv:2305.07881](https://arxiv.org/abs/2305.07881)
151
+
152
+ ### 2. Separation of Analysis and Formatting
153
+
154
+ When a model is asked to return structured data directly, its reasoning quality degrades. Konsilio solves this by having experts write **prose first**, then using a dedicated formatter:
155
+
156
+ - **Dhuliawala et al. (2023)** — *"Chain-of-Verification Reduces Hallucination in Large Language Models"* — demonstrates that separating generation from verification significantly reduces errors. This is the core principle behind Konsilio's two-stage design. [arXiv:2309.11495](https://arxiv.org/abs/2309.11495)
157
+
158
+ - **Willison et al. (2023)** — *"Jsonformer: A Bulletproof Way to Generate Structured JSON from Language Models"* — documents how JSON schema constraints during generation interfere with reasoning quality, recommending a two-stage approach: generate content freely, then format. [arXiv:2305.15087](https://arxiv.org/abs/2305.15087)
159
+
160
+ - **Su et al. (2024)** — *"The Impact of Reasoning Step Length on Large Language Models"* — shows that adding structural constraints (like JSON output requirements) during reasoning reduces the model's ability to explore solution spaces, increasing error rates. [arXiv:2401.04991](https://arxiv.org/abs/2401.04991)
161
+
162
+ This is why Konsilio uses `gpt-4o-mini` as a **dedicated formatter** — it converts prose to JSON without the expert models having to juggle both reasoning and formatting simultaneously.
163
+
164
+ ### 3. Clean-Slate Implementation
165
+
166
+ By separating planning from execution, the coding model starts with **zero context overhead**. It receives a complete blueprint and executes — no need to re-derive the plan or carry forward the reasoning history. This reduces token costs and avoids context-window pollution.
167
+
168
+ # License
169
+
170
+ This software is released under the Unlicense: do whatever you want with it.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+ import initSqlJs from "sql.js";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ const DB_PATH = resolve(process.cwd(), "data/konsilio.db");
6
+ async function getDatabase() {
7
+ if (!existsSync(DB_PATH))
8
+ return null;
9
+ const SQL = await initSqlJs({
10
+ locateFile: (file) => `https://sql.js.org/dist/${file}`
11
+ });
12
+ const buffer = readFileSync(DB_PATH);
13
+ return new SQL.Database(buffer);
14
+ }
15
+ function mapRow(columns, values) {
16
+ const row = {};
17
+ for (let i = 0; i < columns.length; i++) {
18
+ row[columns[i]] = values[i];
19
+ }
20
+ return row;
21
+ }
22
+ function listSessions(db, limit = 10) {
23
+ const result = db.exec(`
24
+ SELECT id, created_at, draft_plan_summary, tech_stack
25
+ FROM sessions
26
+ ORDER BY created_at DESC
27
+ LIMIT ${limit}
28
+ `);
29
+ if (result.length === 0 || result[0].values.length === 0) {
30
+ console.log("No sessions found.");
31
+ return;
32
+ }
33
+ const sessions = result[0].values.map(v => mapRow(result[0].columns, v));
34
+ console.log("\n╭──────────────────────────────────────────────────────────────╮");
35
+ console.log("│ 📋 Council Sessions │");
36
+ console.log("├──────────────────────────────────────────────────────────────┤");
37
+ for (const s of sessions) {
38
+ const id = s.id.slice(0, 8);
39
+ const date = new Date(s.created_at).toLocaleString();
40
+ const summary = s.draft_plan_summary?.slice(0, 50) ?? "No summary";
41
+ // Get expert count and total time
42
+ const statsResult = db.exec(`
43
+ SELECT COUNT(*) as count, SUM(duration_ms) as total_ms
44
+ FROM expert_findings
45
+ WHERE session_id = '${s.id.replace(/'/g, "''")}'
46
+ `);
47
+ let stats = { count: 0, total_ms: null };
48
+ if (statsResult.length > 0 && statsResult[0].values.length > 0) {
49
+ const row = mapRow(statsResult[0].columns, statsResult[0].values[0]);
50
+ stats = { count: Number(row.count), total_ms: row.total_ms };
51
+ }
52
+ const totalSec = stats.total_ms ? (stats.total_ms / 1000).toFixed(1) : "?";
53
+ console.log(`│ ${id}… | ${date} | ${stats.count} experts | ${totalSec}s`);
54
+ console.log(`│ Plan: ${summary}…`);
55
+ if (s.tech_stack) {
56
+ console.log(`│ Stack: ${s.tech_stack}`);
57
+ }
58
+ console.log("│");
59
+ }
60
+ console.log("├──────────────────────────────────────────────────────────────┤");
61
+ console.log("│ Run `npm run history <session-id>` for full details │");
62
+ console.log("╰──────────────────────────────────────────────────────────────╯\n");
63
+ }
64
+ function showSession(db, sessionId) {
65
+ const escapedId = sessionId.replace(/'/g, "''");
66
+ // Get session
67
+ const sessionResult = db.exec(`
68
+ SELECT * FROM sessions WHERE id = '${escapedId}' OR id LIKE '${escapedId}%'
69
+ `);
70
+ if (sessionResult.length === 0 || sessionResult[0].values.length === 0) {
71
+ console.log(`❌ Session not found: ${sessionId}`);
72
+ return;
73
+ }
74
+ const session = mapRow(sessionResult[0].columns, sessionResult[0].values[0]);
75
+ const fullId = session.id;
76
+ const date = new Date(session.created_at).toLocaleString();
77
+ console.log("\n╭──────────────────────────────────────────────────────────────╮");
78
+ console.log(`│ 📋 Session: ${session.id} │`);
79
+ console.log("├──────────────────────────────────────────────────────────────┤");
80
+ console.log(`│ 📅 ${date}`);
81
+ if (session.tech_stack) {
82
+ console.log(`│ 🔧 Stack: ${session.tech_stack}`);
83
+ }
84
+ if (session.constraints) {
85
+ console.log(`│ ⚠️ Constraints: ${session.constraints}`);
86
+ }
87
+ console.log("├──────────────────────────────────────────────────────────────┤");
88
+ console.log("│ 📝 Draft Plan:");
89
+ console.log("│");
90
+ // Get user message (draft plan)
91
+ const userMsgResult = db.exec(`
92
+ SELECT content FROM messages
93
+ WHERE session_id = '${escapedId}' AND role = 'user'
94
+ ORDER BY created_at ASC LIMIT 1
95
+ `);
96
+ if (userMsgResult.length > 0 && userMsgResult[0].values.length > 0) {
97
+ const userMsg = userMsgResult[0].values[0][0];
98
+ for (const line of userMsg.split("\n")) {
99
+ console.log(`│ ${line}`);
100
+ }
101
+ }
102
+ // Get expert findings grouped by persona
103
+ const findingsResult = db.exec(`
104
+ SELECT * FROM expert_findings
105
+ WHERE session_id = '${escapedId}'
106
+ ORDER BY persona_id, severity
107
+ `);
108
+ const findings = [];
109
+ if (findingsResult.length > 0) {
110
+ for (const values of findingsResult[0].values) {
111
+ findings.push(mapRow(findingsResult[0].columns, values));
112
+ }
113
+ }
114
+ console.log("├──────────────────────────────────────────────────────────────┤");
115
+ console.log("│ 🧠 Expert Findings:");
116
+ console.log("│");
117
+ // Group by persona
118
+ const byPersona = new Map();
119
+ for (const f of findings) {
120
+ const existing = byPersona.get(f.persona_id) ?? [];
121
+ existing.push(f);
122
+ byPersona.set(f.persona_id, existing);
123
+ }
124
+ for (const [personaId, personaFindings] of byPersona) {
125
+ const emoji = personaFindings[0]?.persona_emoji ?? "👤";
126
+ const name = personaFindings[0]?.persona_name ?? personaId;
127
+ console.log(`│ ${emoji} ${name}`);
128
+ console.log("│ ───────────────────────────────────────────");
129
+ for (const f of personaFindings) {
130
+ const status = f.accepted ? "✅" : "❌";
131
+ console.log(`│ ${status} [${f.severity}] ${f.component}`);
132
+ console.log(`│ Issue: ${f.issue.slice(0, 60)}${f.issue.length > 60 ? "…" : ""}`);
133
+ console.log(`│ Fix: ${f.mitigation.slice(0, 60)}${f.mitigation.length > 60 ? "…" : ""}`);
134
+ }
135
+ console.log("│");
136
+ }
137
+ // Final blueprint (from consolidation phase)
138
+ const blueprintResult = db.exec(`
139
+ SELECT content FROM messages
140
+ WHERE session_id = '${escapedId}' AND role = 'assistant' AND persona_id = 'consolidation'
141
+ ORDER BY created_at DESC LIMIT 1
142
+ `);
143
+ if (blueprintResult.length > 0 && blueprintResult[0].values.length > 0) {
144
+ const blueprint = blueprintResult[0].values[0][0];
145
+ console.log("├──────────────────────────────────────────────────────────────┤");
146
+ console.log("│ 👑 Council Blueprint:");
147
+ console.log("│");
148
+ for (const line of blueprint.split("\n")) {
149
+ console.log(`│ ${line}`);
150
+ }
151
+ }
152
+ console.log("╰──────────────────────────────────────────────────────────────╯\n");
153
+ }
154
+ // Main
155
+ async function main() {
156
+ const args = process.argv.slice(2);
157
+ const db = await getDatabase();
158
+ if (!db) {
159
+ console.log("❌ No database found at ./data/konsilio.db");
160
+ console.log(" Run a council session first to create data.");
161
+ process.exit(1);
162
+ }
163
+ try {
164
+ if (args.length === 0) {
165
+ listSessions(db);
166
+ }
167
+ else {
168
+ showSession(db, args[0]);
169
+ }
170
+ }
171
+ finally {
172
+ db.close();
173
+ }
174
+ }
175
+ main().catch((err) => {
176
+ console.error("Fatal error:", err);
177
+ process.exit(1);
178
+ });
179
+ //# sourceMappingURL=history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/cli/history.ts"],"names":[],"mappings":";AAEA,OAAO,SAA4B,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,kBAAkB,CAAC,CAAC;AAmC3D,KAAK,UAAU,WAAW;IACxB,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC;QAC1B,UAAU,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,2BAA2B,IAAI,EAAE;KAChE,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,MAAM,CAAC,OAAiB,EAAE,MAAiB;IAClD,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,YAAY,CAAC,EAAY,EAAE,QAAgB,EAAE;IACpD,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC;;;;YAIb,KAAK;GACd,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAyB,CAAC;IAEjG,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;IACjF,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAEhF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,cAAc,EAAE,CAAC;QACrD,MAAM,OAAO,GAAG,CAAC,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC;QAEnE,kCAAkC;QAClC,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC;;;4BAGJ,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC;KAC/C,CAAC,CAAC;QAEH,IAAI,KAAK,GAA+C,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACrF,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACrE,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAyB,EAAE,CAAC;QAChF,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAE3E,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,MAAM,KAAK,CAAC,KAAK,cAAc,QAAQ,GAAG,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,GAAG,CAAC,CAAC;QACrC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QAC5C,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,iEAAiE,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,WAAW,CAAC,EAAY,EAAE,SAAiB;IAClD,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAEhD,cAAc;IACd,MAAM,aAAa,GAAG,EAAE,CAAC,IAAI,CAAC;yCACS,SAAS,iBAAiB,SAAS;GACzE,CAAC,CAAC;IAEH,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,wBAAwB,SAAS,EAAE,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAuB,CAAC;IACnG,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,cAAc,EAAE,CAAC;IAE3D,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,iBAAiB,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;IAC5B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,eAAe,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEjB,gCAAgC;IAChC,MAAM,aAAa,GAAG,EAAE,CAAC,IAAI,CAAC;;0BAEN,SAAS;;GAEhC,CAAC,CAAC;IAEH,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnE,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;QACxD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,MAAM,cAAc,GAAG,EAAE,CAAC,IAAI,CAAC;;0BAEP,SAAS;;GAEhC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,MAAM,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YAC9C,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAA6B,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAEjB,mBAAmB;IACnB,MAAM,SAAS,GAAG,IAAI,GAAG,EAA2B,CAAC;IACrD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;QACnD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,IAAI,SAAS,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,aAAa,IAAI,IAAI,CAAC;QACxD,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,YAAY,IAAI,SAAS,CAAC;QAE3D,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,+CAA+C,CAAC,CAAC;QAE7D,KAAK,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;YAChC,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;YAC5D,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtF,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChG,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,6CAA6C;IAC7C,MAAM,eAAe,GAAG,EAAE,CAAC,IAAI,CAAC;;0BAER,SAAS;;GAEhC,CAAC,CAAC;IAEH,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvE,MAAM,SAAS,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC;QAChF,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEjB,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,oEAAoE,CAAC,CAAC;AACpF,CAAC;AAED,OAAO;AACP,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;IAE/B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,YAAY,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error";
2
+ export type NodeEnv = "development" | "production" | "test";
3
+ export declare const config: {
4
+ readonly port: number;
5
+ readonly openrouterApiKey: string;
6
+ readonly openrouterBaseUrl: "https://openrouter.ai/api/v1";
7
+ readonly nodeEnv: NodeEnv;
8
+ readonly logLevel: LogLevel;
9
+ readonly isProduction: boolean;
10
+ readonly isDevelopment: boolean;
11
+ readonly enabledPersonas: string[] | undefined;
12
+ readonly models: {
13
+ readonly experts: string;
14
+ readonly lead: string;
15
+ readonly formatter: string;
16
+ };
17
+ readonly personaModels: Record<string, string>;
18
+ readonly timeouts: {
19
+ readonly expertMs: number;
20
+ readonly leadMs: number;
21
+ readonly formatterMs: number;
22
+ };
23
+ readonly formatterMaxRetries: number;
24
+ readonly maxTokens: {
25
+ readonly experts: number;
26
+ readonly lead: number;
27
+ };
28
+ readonly maxDraftPlanLength: number;
29
+ readonly maxHistorySessions: number;
30
+ readonly maxParallelExperts: 4;
31
+ readonly databasePath: string;
32
+ readonly cacheTtlSeconds: number;
33
+ };
34
+ /**
35
+ * Validates that required configuration is present.
36
+ * Throws an error if required config is missing.
37
+ */
38
+ export declare function validateConfig(): void;
@@ -0,0 +1,118 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { resolve, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ // ─── CLI Args Parsing ───
6
+ // Parse CLI args: --api-key=xxx
7
+ function parseCliArgs() {
8
+ const args = {};
9
+ for (const arg of process.argv.slice(2)) {
10
+ if (arg.startsWith("--api-key=")) {
11
+ args.OPENROUTER_API_KEY = arg.slice("--api-key=".length);
12
+ }
13
+ }
14
+ return args;
15
+ }
16
+ const cliArgs = parseCliArgs();
17
+ // Priority: CLI args > process.env > fallback
18
+ function env(key, fallback) {
19
+ return cliArgs[key] ?? process.env[key] ?? fallback;
20
+ }
21
+ // ─── Validators ───
22
+ function parseLogLevel(value) {
23
+ const validLevels = ["debug", "info", "warn", "error"];
24
+ const level = (value ?? "info").toLowerCase();
25
+ return validLevels.includes(level) ? level : "info";
26
+ }
27
+ function parseNodeEnv(value) {
28
+ const validEnvs = ["development", "production", "test"];
29
+ const envValue = (value ?? "development").toLowerCase();
30
+ return validEnvs.includes(envValue) ? envValue : "development";
31
+ }
32
+ function parsePositiveInt(value, defaultValue) {
33
+ if (!value)
34
+ return defaultValue;
35
+ const parsed = parseInt(value, 10);
36
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : defaultValue;
37
+ }
38
+ function loadKonsilioConfig() {
39
+ // Search order: project root first, then package directory
40
+ // This allows consuming projects to override package defaults
41
+ const candidates = [
42
+ resolve(process.cwd(), "konsilio.json"), // Project root (consuming project)
43
+ resolve(__dirname, "..", "konsilio.json"), // Package directory (defaults)
44
+ ];
45
+ for (const configPath of candidates) {
46
+ if (!existsSync(configPath))
47
+ continue;
48
+ try {
49
+ const content = readFileSync(configPath, "utf-8");
50
+ return JSON.parse(content);
51
+ }
52
+ catch {
53
+ // Invalid JSON, continue to next candidate
54
+ }
55
+ }
56
+ return {};
57
+ }
58
+ const konsilioConfig = loadKonsilioConfig();
59
+ // ─── Exported Config ───
60
+ export const config = {
61
+ // Server Configuration
62
+ port: parsePositiveInt(env("PORT"), 3000),
63
+ // API Configuration
64
+ openrouterApiKey: env("OPENROUTER_API_KEY") ?? "",
65
+ openrouterBaseUrl: "https://openrouter.ai/api/v1",
66
+ // Environment & Logging
67
+ nodeEnv: parseNodeEnv(env("NODE_ENV")),
68
+ logLevel: parseLogLevel(env("LOG_LEVEL")),
69
+ isProduction: parseNodeEnv(env("NODE_ENV")) === "production",
70
+ isDevelopment: parseNodeEnv(env("NODE_ENV")) === "development",
71
+ // Enabled persona IDs from config file (defaults to all if not specified)
72
+ enabledPersonas: konsilioConfig.personas?.enabled,
73
+ // Model Configuration
74
+ models: {
75
+ experts: konsilioConfig.models?.experts ?? "google/gemini-2.5-flash-lite",
76
+ lead: konsilioConfig.models?.lead ?? "google/gemini-2.5-pro",
77
+ formatter: konsilioConfig.models?.formatter ?? "openai/gpt-4o-mini",
78
+ },
79
+ // Persona-level model defaults (personaId -> model)
80
+ personaModels: konsilioConfig.personaModels ?? {},
81
+ // Timeout Configuration
82
+ timeouts: {
83
+ expertMs: konsilioConfig.timeouts?.expertMs ?? 90_000,
84
+ leadMs: konsilioConfig.timeouts?.leadMs ?? 120_000,
85
+ formatterMs: konsilioConfig.timeouts?.formatterMs ?? 30_000,
86
+ },
87
+ // Formatter retries
88
+ formatterMaxRetries: konsilioConfig.formatter?.maxRetries ?? 3,
89
+ // Token limits
90
+ maxTokens: {
91
+ experts: konsilioConfig.maxTokens?.experts ?? 4096,
92
+ lead: konsilioConfig.maxTokens?.lead ?? 16384,
93
+ },
94
+ // Limits
95
+ maxDraftPlanLength: konsilioConfig.maxDraftPlanLength ?? 12000,
96
+ maxHistorySessions: konsilioConfig.maxHistorySessions ?? 10,
97
+ maxParallelExperts: 4,
98
+ // Database & Caching
99
+ databasePath: konsilioConfig.databasePath ?? "./data/konsilio.db",
100
+ cacheTtlSeconds: konsilioConfig.cacheTtlSeconds ?? 3600,
101
+ };
102
+ // ─── Validation ───
103
+ /**
104
+ * Validates that required configuration is present.
105
+ * Throws an error if required config is missing.
106
+ */
107
+ export function validateConfig() {
108
+ if (!config.openrouterApiKey) {
109
+ throw new Error("Missing OPENROUTER_API_KEY. Set it via OPENROUTER_API_KEY environment variable.\n" +
110
+ "Get your key at https://openrouter.ai/keys");
111
+ }
112
+ if (!config.enabledPersonas || config.enabledPersonas.length === 0) {
113
+ throw new Error("Missing enabled personas in konsilio.json. " +
114
+ "Add a 'personas.enabled' array with valid persona IDs. " +
115
+ "Available: security, performance, ux-dx, devops, typescript, graph-dba, node-fullstack, dev-tooling, distributed-systems, test-architect");
116
+ }
117
+ }
118
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Dependency Injection Container
3
+ *
4
+ * Composition root that wires up all services with their dependencies.
5
+ * This is the single place where all dependencies are created and connected.
6
+ */
7
+ import { OpenRouterService } from './services/openrouter.service.js';
8
+ import { DatabaseService } from './services/database.service.js';
9
+ import { CacheService } from './services/cache.service.js';
10
+ import { PromptService } from './services/prompt.service.js';
11
+ import { PersonaService } from './services/persona.service.js';
12
+ import { CouncilService } from './services/council.service.js';
13
+ export interface AppServices {
14
+ openRouterService: OpenRouterService;
15
+ databaseService: DatabaseService;
16
+ cacheService: CacheService;
17
+ promptService: PromptService;
18
+ personaService: PersonaService;
19
+ councilService: CouncilService;
20
+ }
21
+ /**
22
+ * Create and wire up all application services (async)
23
+ */
24
+ export declare function createServices(): Promise<AppServices>;
25
+ /**
26
+ * Get the singleton services instance (returns a Promise)
27
+ */
28
+ export declare function getServices(): Promise<AppServices>;
29
+ /**
30
+ * Reset services (useful for testing)
31
+ */
32
+ export declare function resetServices(): void;