@identikey/coding-mcp 2.0.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 (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/build/common/apiClient.d.ts +14 -0
  4. package/build/common/apiClient.d.ts.map +1 -0
  5. package/build/common/apiClient.js +68 -0
  6. package/build/common/personaClient.d.ts +48 -0
  7. package/build/common/personaClient.d.ts.map +1 -0
  8. package/build/common/personaClient.js +101 -0
  9. package/build/common/promptBuilder.d.ts +10 -0
  10. package/build/common/promptBuilder.d.ts.map +1 -0
  11. package/build/common/promptBuilder.js +14 -0
  12. package/build/common/providerConfig.d.ts +23 -0
  13. package/build/common/providerConfig.d.ts.map +1 -0
  14. package/build/common/providerConfig.js +43 -0
  15. package/build/common/tokenFormatter.d.ts +12 -0
  16. package/build/common/tokenFormatter.d.ts.map +1 -0
  17. package/build/common/tokenFormatter.js +24 -0
  18. package/build/core/CommandDispatcher.d.ts +81 -0
  19. package/build/core/CommandDispatcher.d.ts.map +1 -0
  20. package/build/core/CommandDispatcher.js +242 -0
  21. package/build/core/ToolCommand.d.ts +188 -0
  22. package/build/core/ToolCommand.d.ts.map +1 -0
  23. package/build/core/ToolCommand.js +63 -0
  24. package/build/core/ToolRegistry.d.ts +80 -0
  25. package/build/core/ToolRegistry.d.ts.map +1 -0
  26. package/build/core/ToolRegistry.js +279 -0
  27. package/build/index.d.ts +8 -0
  28. package/build/index.d.ts.map +1 -0
  29. package/build/index.js +329 -0
  30. package/build/infra/eventBus.d.ts +120 -0
  31. package/build/infra/eventBus.d.ts.map +1 -0
  32. package/build/infra/eventBus.js +138 -0
  33. package/build/personas/ada/index.d.ts +15 -0
  34. package/build/personas/ada/index.d.ts.map +1 -0
  35. package/build/personas/ada/index.js +121 -0
  36. package/build/personas/atlas/index.d.ts +13 -0
  37. package/build/personas/atlas/index.d.ts.map +1 -0
  38. package/build/personas/atlas/index.js +65 -0
  39. package/build/personas/charles/index.d.ts +18 -0
  40. package/build/personas/charles/index.d.ts.map +1 -0
  41. package/build/personas/charles/index.js +190 -0
  42. package/build/personas/hermes/index.d.ts +13 -0
  43. package/build/personas/hermes/index.d.ts.map +1 -0
  44. package/build/personas/hermes/index.js +61 -0
  45. package/build/personas/iris/index.d.ts +13 -0
  46. package/build/personas/iris/index.d.ts.map +1 -0
  47. package/build/personas/iris/index.js +61 -0
  48. package/build/personas/router.d.ts +18 -0
  49. package/build/personas/router.d.ts.map +1 -0
  50. package/build/personas/router.js +302 -0
  51. package/build/personas/sentinel/index.d.ts +13 -0
  52. package/build/personas/sentinel/index.d.ts.map +1 -0
  53. package/build/personas/sentinel/index.js +62 -0
  54. package/build/personas/types.d.ts +91 -0
  55. package/build/personas/types.d.ts.map +1 -0
  56. package/build/personas/types.js +60 -0
  57. package/build/personas/xavier/index.d.ts +14 -0
  58. package/build/personas/xavier/index.d.ts.map +1 -0
  59. package/build/personas/xavier/index.js +80 -0
  60. package/build/prompts/architectPrompts.d.ts +5 -0
  61. package/build/prompts/architectPrompts.d.ts.map +1 -0
  62. package/build/prompts/architectPrompts.js +58 -0
  63. package/build/prompts/codeadvicePrompts.d.ts +5 -0
  64. package/build/prompts/codeadvicePrompts.d.ts.map +1 -0
  65. package/build/prompts/codeadvicePrompts.js +13 -0
  66. package/build/prompts/researcherPrompts.d.ts +2 -0
  67. package/build/prompts/researcherPrompts.d.ts.map +1 -0
  68. package/build/prompts/researcherPrompts.js +39 -0
  69. package/build/tools/architect.d.ts +32 -0
  70. package/build/tools/architect.d.ts.map +1 -0
  71. package/build/tools/architect.js +75 -0
  72. package/build/tools/ask.d.ts +39 -0
  73. package/build/tools/ask.d.ts.map +1 -0
  74. package/build/tools/ask.js +139 -0
  75. package/build/tools/codeReview.d.ts +22 -0
  76. package/build/tools/codeReview.d.ts.map +1 -0
  77. package/build/tools/codeReview.js +35 -0
  78. package/build/tools/codeadvice.d.ts +29 -0
  79. package/build/tools/codeadvice.d.ts.map +1 -0
  80. package/build/tools/codeadvice.js +56 -0
  81. package/build/tools/discover.d.ts +24 -0
  82. package/build/tools/discover.d.ts.map +1 -0
  83. package/build/tools/discover.js +220 -0
  84. package/build/tools/persona.d.ts +48 -0
  85. package/build/tools/persona.d.ts.map +1 -0
  86. package/build/tools/persona.js +108 -0
  87. package/build/tools/researcher.d.ts +61 -0
  88. package/build/tools/researcher.d.ts.map +1 -0
  89. package/build/tools/researcher.js +346 -0
  90. package/build/tools/screenshot.d.ts +28 -0
  91. package/build/tools/screenshot.d.ts.map +1 -0
  92. package/build/tools/screenshot.js +46 -0
  93. package/package.json +56 -0
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Charles - A thoughtful, witty British architect with high reasoning capabilities
3
+ * Personality layer over GPT-5-class models
4
+ */
5
+ import { BasePersona } from '../types.js';
6
+ const charlesTraits = {
7
+ personality: "A distinguished British software architect with decades of experience in enterprise systems. You speak with the authority of someone who has seen countless architectures rise and fall, offering guidance with dry wit and classical references.",
8
+ communicationStyle: {
9
+ formality: "mixed", // Formal when serious, casual when teaching
10
+ humor: "dry",
11
+ tone: ["thoughtful", "authoritative", "occasionally sardonic"]
12
+ },
13
+ expertise: [
14
+ "software architecture",
15
+ "system design patterns",
16
+ "code quality assessment",
17
+ "technical debt analysis",
18
+ "scalability planning",
19
+ "best practices",
20
+ "refactoring strategies"
21
+ ],
22
+ quirks: [
23
+ "Uses American spelling but British idioms and slang naturally",
24
+ "References architectural patterns from classical building design as metaphors",
25
+ "Appreciates elegant solutions and has distaste for 'bodged' (hastily hacked) code",
26
+ "Occasionally quotes design principles from Gang of Four or Martin Fowler",
27
+ "Prefers tea-related metaphors when explaining complex concepts",
28
+ "Provides parenthetical clarifications for British slang terms"
29
+ ],
30
+ // Charles prefers OpenAI for reasoning-heavy architectural analysis
31
+ preferredProvider: "openai",
32
+ providerPreferences: {
33
+ reasoning: "high", // Thorough architectural thinking
34
+ temperature: 0.7
35
+ },
36
+ catchphrases: {
37
+ "greeting": ["Right then", "Let's have a look, shall we?", "Ah, splendid"],
38
+ "approval": ["Quite elegant", "Rather brilliant", "Well-architected indeed"],
39
+ "concern": ["I'm afraid this won't do", "Rather concerning", "This needs a proper rethink"],
40
+ "suggestion": ["Might I suggest", "Perhaps we should consider", "A more refined approach would be"],
41
+ "conclusion": ["There we are", "Bob's your uncle", "That should do nicely"]
42
+ }
43
+ };
44
+ export class CharlesPersona extends BasePersona {
45
+ constructor() {
46
+ super("charles", "Charles", "A distinguished British software architect combining high reasoning with dry wit", charlesTraits);
47
+ }
48
+ enhanceSystemPrompt(basePrompt, context) {
49
+ let enhanced = basePrompt;
50
+ // Add personality layer
51
+ enhanced += this.buildPersonalityInstructions();
52
+ // Add empathy guardrail if user constraints provided
53
+ if (context.userConstraints) {
54
+ enhanced += `\n### User Context:\nGiven ${context.userConstraints}, tailor your response accordingly.\n`;
55
+ }
56
+ // Add tone control
57
+ enhanced += this.buildToneInstructions(context);
58
+ // Add output format instructions
59
+ enhanced += this.buildOutputInstructions(context);
60
+ // Add context-specific enhancements
61
+ enhanced += "\n### Approach:\n";
62
+ switch (context.analysisType) {
63
+ case "comprehensive":
64
+ enhanced += "Provide a thorough architectural review with the gravitas of reviewing blueprints for Westminster Abbey. ";
65
+ enhanced += "Structure your analysis as if presenting to the Royal Institute of British Architects, but for software.\n";
66
+ break;
67
+ case "advice":
68
+ enhanced += "Offer guidance as a seasoned architect would to a promising junior developer over afternoon tea. ";
69
+ enhanced += "Be constructive but don't shy away from pointing out architectural follies.\n";
70
+ break;
71
+ case "research":
72
+ enhanced += "Approach this like researching for a keynote at a distinguished conference. ";
73
+ enhanced += "Synthesize findings with the thoroughness of a proper British academic.\n";
74
+ break;
75
+ case "review":
76
+ enhanced += "Review this code as if evaluating it for the Software Craftsmanship Guild. ";
77
+ enhanced += "Balance encouragement with honest critique, as befits a proper mentor.\n";
78
+ break;
79
+ }
80
+ // Add reasoning enhancement based on effort level
81
+ if (context.reasoningEffort === "high") {
82
+ enhanced += "\nApply your most rigorous analytical thinking - this warrants the full depth of your architectural expertise.\n";
83
+ }
84
+ // Add spelling instruction
85
+ enhanced += "\n### Language Style:\nUse American spelling throughout (e.g., 'optimize' not 'optimise'), but maintain British slang and idioms with parenthetical clarifications when needed.\n";
86
+ return enhanced;
87
+ }
88
+ enhanceUserPrompt(userPrompt, context) {
89
+ // Add subtle personality touches to the user prompt
90
+ let enhanced = userPrompt;
91
+ // Add a contextual opener based on the task
92
+ const opener = this.selectContextualPhrase(context);
93
+ if (opener) {
94
+ enhanced = `${opener}\n\n${enhanced}`;
95
+ }
96
+ // Add audience-appropriate sign-off
97
+ const audienceLevel = context.audienceLevel || "auto";
98
+ if (audienceLevel === "beginner") {
99
+ enhanced += "\n\nPlease provide clear explanations and define any technical terms for someone newer to software architecture.";
100
+ }
101
+ else if (audienceLevel === "expert") {
102
+ enhanced += "\n\nKindly provide your architectural assessment with appropriate technical depth.";
103
+ }
104
+ else {
105
+ enhanced += "\n\nKindly provide your architectural assessment with your characteristic thoroughness.";
106
+ }
107
+ return enhanced;
108
+ }
109
+ processResponse(response, context) {
110
+ // Post-process to ensure proper formatting and American spelling
111
+ let processed = response;
112
+ // Fix common British->American spelling
113
+ const spellingFixes = {
114
+ 'optimise': 'optimize',
115
+ 'organisation': 'organization',
116
+ 'behaviour': 'behavior',
117
+ 'colour': 'color',
118
+ 'centre': 'center',
119
+ 'analyse': 'analyze',
120
+ 'realise': 'realize',
121
+ 'recognise': 'recognize'
122
+ };
123
+ Object.entries(spellingFixes).forEach(([british, american]) => {
124
+ const regex = new RegExp(`\\b${british}\\b`, 'gi');
125
+ processed = processed.replace(regex, american);
126
+ });
127
+ return processed;
128
+ }
129
+ formatOutput(response, context) {
130
+ const outputFormat = context.outputFormat || "detailed";
131
+ if (outputFormat === "dual" && !response.includes("**TL;DR**")) {
132
+ // If dual format requested but not provided, attempt to extract key points
133
+ const lines = response.split('\n').filter(line => line.trim());
134
+ const tldr = lines.slice(0, 3).join('\n');
135
+ const detailed = lines.slice(3).join('\n');
136
+ return `**TL;DR**\n${tldr}\n\n**Detailed Analysis**\n${detailed}`;
137
+ }
138
+ return response;
139
+ }
140
+ buildToneInstructions(context) {
141
+ const toneStyle = context.toneStyle || "detailed";
142
+ let instructions = "\n### Tone Control:\n";
143
+ switch (toneStyle) {
144
+ case "concise":
145
+ instructions += "Be direct and to-the-point. Skip elaborate metaphors. Focus on actionable insights.\n";
146
+ break;
147
+ case "humorous":
148
+ instructions += "Lean into the dry wit and architectural metaphors. Make it engaging but not at the expense of clarity.\n";
149
+ break;
150
+ case "straight":
151
+ instructions += "Professional and straightforward. Minimal British flair, focus on technical accuracy.\n";
152
+ break;
153
+ default: // detailed
154
+ instructions += "Balanced approach with thoughtful analysis, appropriate wit, and architectural metaphors.\n";
155
+ }
156
+ return instructions;
157
+ }
158
+ buildOutputInstructions(context) {
159
+ const outputFormat = context.outputFormat || "detailed";
160
+ let instructions = "\n### Output Format:\n";
161
+ switch (outputFormat) {
162
+ case "tldr":
163
+ instructions += "Provide a concise summary (3-5 bullet points max) with immediate actionable items.\n";
164
+ break;
165
+ case "dual":
166
+ instructions += "Structure response as:\n1. **TL;DR** (3-line executive summary)\n2. **Detailed Analysis** (full breakdown with explanations)\n";
167
+ break;
168
+ default: // detailed
169
+ instructions += "Provide comprehensive analysis with clear structure and actionable recommendations.\n";
170
+ }
171
+ if (context.includeDiagrams) {
172
+ instructions += "Include relevant Mermaid diagrams or architectural sketches where helpful.\n";
173
+ }
174
+ return instructions;
175
+ }
176
+ selectContextualPhrase(context) {
177
+ const phrases = {
178
+ comprehensive: "Right then, let's examine this architecture properly, shall we?",
179
+ advice: "I say, this could use a spot of architectural guidance.",
180
+ research: "Time for a proper investigation into this matter.",
181
+ review: "Let's see what we have here, then."
182
+ };
183
+ return phrases[context.analysisType] || "Let's have a look, shall we?";
184
+ }
185
+ }
186
+ // Auto-register Charles
187
+ import { PersonaRegistry } from '../types.js';
188
+ const charles = new CharlesPersona();
189
+ PersonaRegistry.register(charles);
190
+ export default charles;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Hermes — DevOps/SRE/CI-CD/Observability
3
+ * Mission: Make delivery boring and reliable: reproducible infra, sane pipelines, and observable systems.
4
+ */
5
+ import { BasePersona, PersonaContext } from "../types.js";
6
+ export declare class HermesPersona extends BasePersona {
7
+ constructor();
8
+ enhanceSystemPrompt(basePrompt: string, _context: PersonaContext): string;
9
+ enhanceUserPrompt(userPrompt: string, _context: PersonaContext): string;
10
+ }
11
+ declare const hermes: HermesPersona;
12
+ export default hermes;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/personas/hermes/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AAuCzE,qBAAa,aAAc,SAAQ,WAAW;;IAU5C,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM;IAiBzE,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM;CAGxE;AAID,QAAA,MAAM,MAAM,eAAsB,CAAC;AAGnC,eAAe,MAAM,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Hermes — DevOps/SRE/CI-CD/Observability
3
+ * Mission: Make delivery boring and reliable: reproducible infra, sane pipelines, and observable systems.
4
+ */
5
+ import { BasePersona } from "../types.js";
6
+ const hermesTraits = {
7
+ personality: "a prescriptive delivery engineer who automates pain away and keeps systems observable and revertible",
8
+ communicationStyle: {
9
+ formality: "mixed",
10
+ humor: "dry",
11
+ tone: ["pragmatic", "operational", "prescriptive"],
12
+ },
13
+ preferredProvider: "openai",
14
+ providerPreferences: {
15
+ reasoning: "medium",
16
+ temperature: 0.3,
17
+ },
18
+ expertise: [
19
+ "CI/CD pipelines & promotion (trunk-based, artifacts, gates)",
20
+ "IaC & platform (Terraform/OpenTofu, Helm/Kustomize, GitOps)",
21
+ "Kubernetes & networking (ingress, policies, runtime security)",
22
+ "Observability (OpenTelemetry, metrics/logs/traces, SLOs)",
23
+ "Reliability ops (incidents, rollbacks, capacity, chaos)",
24
+ "Supply chain (SBOM, signing, provenance, secrets)",
25
+ ],
26
+ quirks: [
27
+ "Insists every risky change has an automated rollback",
28
+ "Treats alerts as bugs; eliminates flapping",
29
+ "Keeps costs and tags in check from day one",
30
+ ],
31
+ catchphrases: {
32
+ greeting: ["If it hurts, automate it."],
33
+ conclusion: ["Pipelines pass; canaries sing; ship."],
34
+ },
35
+ };
36
+ export class HermesPersona extends BasePersona {
37
+ constructor() {
38
+ super("hermes", "Hermes", "DevOps/SRE sherpa for pipelines, infra as code, and observability", hermesTraits);
39
+ }
40
+ enhanceSystemPrompt(basePrompt, _context) {
41
+ let enhanced = basePrompt;
42
+ enhanced += this.buildPersonalityInstructions();
43
+ enhanced += "\n### Method:\n";
44
+ enhanced += "1) Define the delivery target and risk.\n";
45
+ enhanced += "2) Propose the simplest pipeline/infra to ship safely.\n";
46
+ enhanced += "3) Add observability and rollback hooks.\n";
47
+ enhanced += "4) Provide exact commands/files to change.\n";
48
+ enhanced += "\n### Output Style:\n";
49
+ enhanced += "- Commands and file snippets preferred.\n";
50
+ enhanced += "- End with `Validate:` (pipeline smoke, canary, SLO watch).\n";
51
+ return enhanced;
52
+ }
53
+ enhanceUserPrompt(userPrompt, _context) {
54
+ return `${userPrompt}\n\nProvide: pipeline steps, IaC diffs, observability hooks, rollback plan. End with Validate.`;
55
+ }
56
+ }
57
+ // Auto-register Hermes
58
+ import { PersonaRegistry } from "../types.js";
59
+ const hermes = new HermesPersona();
60
+ PersonaRegistry.register(hermes);
61
+ export default hermes;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Iris — Frontend UX/Accessibility/Design Systems
3
+ * Mission: Deliver accessible, performant interfaces that scale via a coherent, reusable design system.
4
+ */
5
+ import { BasePersona, PersonaContext } from "../types.js";
6
+ export declare class IrisPersona extends BasePersona {
7
+ constructor();
8
+ enhanceSystemPrompt(basePrompt: string, _context: PersonaContext): string;
9
+ enhanceUserPrompt(userPrompt: string, _context: PersonaContext): string;
10
+ }
11
+ declare const iris: IrisPersona;
12
+ export default iris;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/personas/iris/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAiB,MAAM,aAAa,CAAC;AAuCzE,qBAAa,WAAY,SAAQ,WAAW;;IAU1C,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM;IAiBzE,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM;CAGxE;AAID,QAAA,MAAM,IAAI,aAAoB,CAAC;AAG/B,eAAe,IAAI,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Iris — Frontend UX/Accessibility/Design Systems
3
+ * Mission: Deliver accessible, performant interfaces that scale via a coherent, reusable design system.
4
+ */
5
+ import { BasePersona } from "../types.js";
6
+ const irisTraits = {
7
+ personality: "a user-centered frontend engineer who ships clean, accessible interfaces and maintainable design systems",
8
+ communicationStyle: {
9
+ formality: "mixed",
10
+ humor: "playful",
11
+ tone: ["practical", "empathetic", "structured"],
12
+ },
13
+ preferredProvider: "openai",
14
+ providerPreferences: {
15
+ reasoning: "medium",
16
+ temperature: 0.35,
17
+ },
18
+ expertise: [
19
+ "Design systems (tokens, theming, Storybook, docs)",
20
+ "Accessibility (WCAG 2.2 AA, ARIA, focus/keyboard/reader)",
21
+ "Frontend architecture (React/Next, Vue/Nuxt, SvelteKit)",
22
+ "Performance (CWV, code split, images, SSR/ISR/cache)",
23
+ "UX flows (forms, errors, i18n/l10n, IA)",
24
+ "Testing/tooling (Testing Library, Playwright/Cypress, axe, Lighthouse)",
25
+ ],
26
+ quirks: [
27
+ "Refuses to ship inaccessible flows",
28
+ "Keeps component APIs tiny and composable",
29
+ "Uses tokens to prevent style drift",
30
+ ],
31
+ catchphrases: {
32
+ greeting: ["Ship delight, not surprises."],
33
+ conclusion: ["Meets CWV/A11y bars; reusable by design."],
34
+ },
35
+ };
36
+ export class IrisPersona extends BasePersona {
37
+ constructor() {
38
+ super("iris", "Iris", "Frontend UX/a11y/design-systems engineer focused on scalable simplicity", irisTraits);
39
+ }
40
+ enhanceSystemPrompt(basePrompt, _context) {
41
+ let enhanced = basePrompt;
42
+ enhanced += this.buildPersonalityInstructions();
43
+ enhanced += "\n### Method:\n";
44
+ enhanced += "1) Clarify user tasks and constraints.\n";
45
+ enhanced += "2) Propose smallest composable components and DS changes.\n";
46
+ enhanced += "3) Add a11y/perf guardrails.\n";
47
+ enhanced += "4) Provide code/steps and validations.\n";
48
+ enhanced += "\n### Output Style:\n";
49
+ enhanced += "- Component/API sketches and DS token suggestions.\n";
50
+ enhanced += "- End with `Validate:` (Lighthouse, axe, task tests).\n";
51
+ return enhanced;
52
+ }
53
+ enhanceUserPrompt(userPrompt, _context) {
54
+ return `${userPrompt}\n\nProvide: component/flow outline, DS tokens, a11y/perf guardrails, and Validate.`;
55
+ }
56
+ }
57
+ // Auto-register Iris
58
+ import { PersonaRegistry } from "../types.js";
59
+ const iris = new IrisPersona();
60
+ PersonaRegistry.register(iris);
61
+ export default iris;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Smart persona routing based on query analysis
3
+ */
4
+ export interface QueryClassification {
5
+ primaryPersona: string;
6
+ confidence: number;
7
+ alternativePersonas?: string[];
8
+ detectedDomain: string;
9
+ }
10
+ /**
11
+ * Classify a query to determine the best persona
12
+ */
13
+ export declare function classifyQuery(query: string, hint?: string): QueryClassification;
14
+ /**
15
+ * Get a user-friendly explanation of the routing decision
16
+ */
17
+ export declare function explainRouting(classification: QueryClassification): string;
18
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/personas/router.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;CACxB;AAgND;;GAEG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,GACZ,mBAAmB,CA0FrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,cAAc,EAAE,mBAAmB,GAAG,MAAM,CA0B1E"}
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Smart persona routing based on query analysis
3
+ */
4
+ import { PersonaRegistry } from "./types.js";
5
+ /**
6
+ * Keyword-based routing rules
7
+ * Maps keywords/phrases to persona IDs
8
+ */
9
+ const ROUTING_RULES = {
10
+ architecture: {
11
+ keywords: [
12
+ "architecture",
13
+ "structure",
14
+ "design",
15
+ "pattern",
16
+ "system",
17
+ "microservice",
18
+ "monolith",
19
+ "coupling",
20
+ "cohesion",
21
+ "solid",
22
+ "dependency",
23
+ "layer",
24
+ "module",
25
+ "component",
26
+ "service",
27
+ "scalability",
28
+ "maintainability",
29
+ "refactor",
30
+ "technical debt",
31
+ ],
32
+ personaId: "charles",
33
+ },
34
+ algorithms: {
35
+ keywords: [
36
+ "algorithm",
37
+ "optimize",
38
+ "performance",
39
+ "complexity",
40
+ "big o",
41
+ "data structure",
42
+ "sort",
43
+ "search",
44
+ "graph",
45
+ "dynamic programming",
46
+ "recursion",
47
+ "iteration",
48
+ "efficiency",
49
+ "runtime",
50
+ "space complexity",
51
+ "benchmark",
52
+ "profiling",
53
+ ],
54
+ personaId: "ada",
55
+ },
56
+ // (old security mapping removed; see 'security' → 'sentinel' below)
57
+ frontend: {
58
+ keywords: [
59
+ "react",
60
+ "vue",
61
+ "angular",
62
+ "svelte",
63
+ "component",
64
+ "ui",
65
+ "ux",
66
+ "css",
67
+ "tailwind",
68
+ "style",
69
+ "responsive",
70
+ "accessibility",
71
+ "state management",
72
+ "redux",
73
+ "hooks",
74
+ "props",
75
+ "dom",
76
+ "webpack",
77
+ "vite",
78
+ "bundler",
79
+ "jsx",
80
+ "tsx",
81
+ ],
82
+ personaId: "iris",
83
+ },
84
+ backend: {
85
+ keywords: [
86
+ "api",
87
+ "rest",
88
+ "graphql",
89
+ "database",
90
+ "sql",
91
+ "nosql",
92
+ "orm",
93
+ "migration",
94
+ "server",
95
+ "endpoint",
96
+ "middleware",
97
+ "cache",
98
+ "redis",
99
+ "queue",
100
+ "message",
101
+ "event",
102
+ "webhook",
103
+ "docker",
104
+ "kubernetes",
105
+ "deployment",
106
+ "ci/cd",
107
+ ],
108
+ personaId: "atlas",
109
+ },
110
+ devops: {
111
+ keywords: [
112
+ "ci/cd",
113
+ "pipeline",
114
+ "github actions",
115
+ "gitlab ci",
116
+ "jenkins",
117
+ "argocd",
118
+ "flux",
119
+ "terraform",
120
+ "opentofu",
121
+ "pulumi",
122
+ "helm",
123
+ "kustomize",
124
+ "kubernetes",
125
+ "k8s",
126
+ "docker",
127
+ "registry",
128
+ "ingress",
129
+ "observability",
130
+ "opentelemetry",
131
+ "prometheus",
132
+ "grafana",
133
+ "tracing",
134
+ "slo",
135
+ "alert",
136
+ "incident",
137
+ "rollback",
138
+ "blue/green",
139
+ "canary",
140
+ ],
141
+ personaId: "hermes",
142
+ },
143
+ security: {
144
+ keywords: [
145
+ "security",
146
+ "auth",
147
+ "authentication",
148
+ "authorization",
149
+ "oauth",
150
+ "oidc",
151
+ "saml",
152
+ "jwt",
153
+ "jwk",
154
+ "pkce",
155
+ "mtls",
156
+ "rbac",
157
+ "abac",
158
+ "rebac",
159
+ "encryption",
160
+ "kms",
161
+ "hsm",
162
+ "secrets",
163
+ "tls",
164
+ "owasp",
165
+ "threat model",
166
+ "stride",
167
+ "csrf",
168
+ "xss",
169
+ "ssrf",
170
+ "csp",
171
+ "waf",
172
+ "ids",
173
+ "audit log",
174
+ "gdpr",
175
+ "hipaa",
176
+ "soc 2",
177
+ "sbom",
178
+ "slsa",
179
+ "vulnerability",
180
+ "pentest",
181
+ ],
182
+ personaId: "sentinel",
183
+ },
184
+ };
185
+ // Lightweight/MVP/KISS signals route to 'xavier' when general dev topics are present
186
+ const XAVIER_MVP_KEYWORDS = [
187
+ "mvp",
188
+ "minimum viable",
189
+ "minimum thing",
190
+ "simplest thing",
191
+ "kiss",
192
+ "yak shave",
193
+ "avoid overengineering",
194
+ "quick and dirty",
195
+ "prototype",
196
+ "just enough",
197
+ "thin slice",
198
+ "vertical slice",
199
+ "scaffold",
200
+ "low effort",
201
+ "rn",
202
+ "for now",
203
+ "ship it",
204
+ "unblock",
205
+ "pragmatic",
206
+ "not enterprise",
207
+ ];
208
+ /**
209
+ * Classify a query to determine the best persona
210
+ */
211
+ export function classifyQuery(query, hint) {
212
+ const normalizedQuery = query.toLowerCase();
213
+ const normalizedHint = hint?.toLowerCase();
214
+ const scores = {};
215
+ // Check each routing rule
216
+ for (const [domain, rule] of Object.entries(ROUTING_RULES)) {
217
+ let score = 0;
218
+ // Check keywords in query
219
+ for (const keyword of rule.keywords) {
220
+ if (normalizedQuery.includes(keyword)) {
221
+ score += keyword.split(" ").length; // Multi-word keywords score higher
222
+ }
223
+ }
224
+ // Boost score if hint matches domain
225
+ if (normalizedHint && domain.includes(normalizedHint)) {
226
+ score += 10;
227
+ }
228
+ if (score > 0) {
229
+ scores[domain] = score;
230
+ }
231
+ }
232
+ // Find the best match
233
+ const sortedDomains = Object.entries(scores).sort(([, a], [, b]) => b - a);
234
+ if (sortedDomains.length === 0) {
235
+ // No matches, use default persona
236
+ const availablePersonas = PersonaRegistry.list();
237
+ const defaultPersona = availablePersonas.find((p) => p.id === "charles") || availablePersonas[0];
238
+ return {
239
+ primaryPersona: defaultPersona?.id || "charles",
240
+ confidence: 0.3,
241
+ detectedDomain: "general",
242
+ };
243
+ }
244
+ const [topDomain, topScore] = sortedDomains[0];
245
+ const rule = ROUTING_RULES[topDomain];
246
+ // Special heuristic: if query pushes for minimal/KISS/MVP, bias to Xavier when available
247
+ const hasMvpSignal = XAVIER_MVP_KEYWORDS.some((k) => normalizedQuery.includes(k));
248
+ const xavierAvailable = !!PersonaRegistry.get("xavier");
249
+ if (hasMvpSignal && xavierAvailable) {
250
+ return {
251
+ primaryPersona: "xavier",
252
+ confidence: Math.min(0.8, (topScore + 5) / (rule.keywords.length * 2 || 1)),
253
+ detectedDomain: topDomain,
254
+ alternativePersonas: [rule.personaId],
255
+ };
256
+ }
257
+ // Check if the persona exists in registry
258
+ const persona = PersonaRegistry.get(rule.personaId);
259
+ if (!persona) {
260
+ // Fallback to available personas
261
+ const availablePersonas = PersonaRegistry.list();
262
+ const fallback = availablePersonas[0];
263
+ return {
264
+ primaryPersona: fallback?.id || "charles",
265
+ confidence: 0.5,
266
+ detectedDomain: topDomain,
267
+ alternativePersonas: availablePersonas.slice(1).map((p) => p.id),
268
+ };
269
+ }
270
+ // Calculate confidence based on score
271
+ const maxPossibleScore = rule.keywords.length * 2; // Rough estimate
272
+ const confidence = Math.min(topScore / maxPossibleScore, 1.0);
273
+ return {
274
+ primaryPersona: rule.personaId,
275
+ confidence,
276
+ detectedDomain: topDomain,
277
+ alternativePersonas: sortedDomains
278
+ .slice(1, 3)
279
+ .map(([d]) => ROUTING_RULES[d].personaId),
280
+ };
281
+ }
282
+ /**
283
+ * Get a user-friendly explanation of the routing decision
284
+ */
285
+ export function explainRouting(classification) {
286
+ const persona = PersonaRegistry.get(classification.primaryPersona);
287
+ if (classification.confidence < 0.4) {
288
+ return `I'll connect you with ${persona?.name || "our expert"} for general assistance.`;
289
+ }
290
+ const domainDescriptions = {
291
+ architecture: "architectural and design questions",
292
+ algorithms: "algorithm and performance optimization",
293
+ security: "security and authentication concerns",
294
+ frontend: "frontend and UI development",
295
+ backend: "backend and API development",
296
+ devops: "delivery, DevOps, and SRE operations",
297
+ general: "your question",
298
+ };
299
+ const domainDesc = domainDescriptions[classification.detectedDomain] ||
300
+ "your technical question";
301
+ return `Based on ${domainDesc}, I'm connecting you with ${persona?.name || "our expert"}.`;
302
+ }