codehere 0.2.2 → 0.3.0-rc.10

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 (238) hide show
  1. package/README.md +88 -68
  2. package/dist/domain/entities/task.js +4 -4
  3. package/dist/error-handler.js +4 -9
  4. package/dist/index.js +261 -1224
  5. package/dist/infrastructure/config/product-context.js +7 -6
  6. package/dist/infrastructure/hooks/claude-sdk-hook.js +348 -72
  7. package/dist/infrastructure/observability/execution-tracer.js +11 -6
  8. package/dist/infrastructure/orchestration/agent-adapter.js +13 -0
  9. package/dist/infrastructure/orchestration/agent-installer.js +101 -0
  10. package/dist/infrastructure/orchestration/agents-config-seed.js +56 -0
  11. package/dist/infrastructure/orchestration/aider-adapter.js +319 -0
  12. package/dist/infrastructure/orchestration/artifacts-extractor.js +175 -0
  13. package/dist/infrastructure/orchestration/claude-code-adapter.js +352 -0
  14. package/dist/infrastructure/orchestration/codex-adapter.js +310 -0
  15. package/dist/infrastructure/orchestration/conductor-adapter.js +340 -0
  16. package/dist/infrastructure/orchestration/generic-cli-adapter.js +553 -0
  17. package/dist/infrastructure/orchestration/opencode-adapter.js +275 -0
  18. package/dist/infrastructure/orchestration/progress-aggregator.js +189 -0
  19. package/dist/infrastructure/orchestration/readiness.js +106 -0
  20. package/dist/infrastructure/orchestration/session-manager.js +278 -0
  21. package/dist/infrastructure/orchestration/session-persistence.js +109 -0
  22. package/dist/infrastructure/protocols/mcp-helpers.js +10 -30
  23. package/dist/infrastructure/protocols/mcp-server-impl.js +359 -21
  24. package/dist/infrastructure/protocols/probe-port.js +36 -0
  25. package/dist/infrastructure/protocols/ui-page.js +1827 -0
  26. package/dist/infrastructure/security/file-collection.js +115 -0
  27. package/dist/infrastructure/security/trust-scorer.js +301 -56
  28. package/dist/infrastructure/storage/task-repository.js +8 -7
  29. package/dist/monitoring.js +9 -38
  30. package/dist/presentation/cli/commands/help-command.js +96 -139
  31. package/dist/presentation/cli/commands/hook-command.js +17 -24
  32. package/dist/presentation/cli/commands/report-command.js +59 -72
  33. package/dist/presentation/cli/commands/setup-command.js +4 -4
  34. package/dist/presentation/cli/commands/status-command.js +321 -30
  35. package/dist/presentation/cli/commands/trust-command.js +84 -72
  36. package/dist/presentation/cli/error-display.js +17 -21
  37. package/dist/presentation/cli/repl.js +474 -0
  38. package/dist/ui.js +11 -11
  39. package/package.json +24 -62
  40. package/dist/agents/base.js +0 -101
  41. package/dist/agents/orchestrator-model-driven.js +0 -141
  42. package/dist/agents/react-orchestrator-agent.js +0 -54
  43. package/dist/application/agents/execution-agent.js +0 -508
  44. package/dist/application/agents/multi-agent-orchestrator.js +0 -295
  45. package/dist/application/agents/planning-agent.js +0 -433
  46. package/dist/application/agents/validation-agent.js +0 -317
  47. package/dist/application/architectures/plan-and-act.js +0 -242
  48. package/dist/application/index.js +0 -12
  49. package/dist/application/services/agent-factory.js +0 -28
  50. package/dist/application/services/dependency-container.js +0 -596
  51. package/dist/application/services/git-context-service.js +0 -83
  52. package/dist/application/services/intelligent-router.js +0 -934
  53. package/dist/application/services/tool-executor-service.js +0 -94
  54. package/dist/application/use-cases/ask-question-use-case.js +0 -338
  55. package/dist/application/use-cases/edit-file-use-case.js +0 -830
  56. package/dist/application/use-cases/explain-file-use-case.js +0 -50
  57. package/dist/application/use-cases/index-codebase-use-case.js +0 -113
  58. package/dist/application/use-cases/planning-use-case.js +0 -276
  59. package/dist/application/use-cases/react-orchestration-use-case.js +0 -329
  60. package/dist/application/use-cases/reflexion-use-case.js +0 -30
  61. package/dist/application/workflows/deterministic-workflows.js +0 -189
  62. package/dist/ast-parser.js +0 -331
  63. package/dist/cache.js +0 -180
  64. package/dist/chat.js +0 -251
  65. package/dist/code-analysis.js +0 -327
  66. package/dist/context.js +0 -187
  67. package/dist/docs.js +0 -146
  68. package/dist/domain/entities/code-chunk.js +0 -6
  69. package/dist/domain/entities/decision.js +0 -9
  70. package/dist/domain/entities/edit.js +0 -6
  71. package/dist/domain/entities/knowledge-node.js +0 -9
  72. package/dist/domain/entities/knowledge-preservation.js +0 -10
  73. package/dist/domain/entities/memory.js +0 -6
  74. package/dist/domain/entities/pattern.js +0 -7
  75. package/dist/domain/entities/plan.js +0 -6
  76. package/dist/domain/entities/query.js +0 -6
  77. package/dist/domain/errors/embeddings-not-found-error.js +0 -13
  78. package/dist/domain/index.js +0 -19
  79. package/dist/domain/interfaces/ai-service.interface.js +0 -6
  80. package/dist/domain/interfaces/code-analyzer.interface.js +0 -6
  81. package/dist/domain/interfaces/decision-repository.interface.js +0 -9
  82. package/dist/domain/interfaces/embedding-repository.interface.js +0 -6
  83. package/dist/domain/interfaces/knowledge-graph-repository.interface.js +0 -9
  84. package/dist/domain/interfaces/knowledge-preservation-repository.interface.js +0 -8
  85. package/dist/domain/interfaces/memory-repository.interface.js +0 -6
  86. package/dist/domain/interfaces/pattern-repository.interface.js +0 -6
  87. package/dist/domain/interfaces/verification-service.interface.js +0 -6
  88. package/dist/domain/services/cross-team-pattern-sharing.js +0 -125
  89. package/dist/domain/services/decision-recorder.js +0 -223
  90. package/dist/domain/services/decision-retriever.js +0 -133
  91. package/dist/domain/services/environment-mode-manager.js +0 -22
  92. package/dist/domain/services/graded-memory-activation.js +0 -69
  93. package/dist/domain/services/knowledge-access.js +0 -132
  94. package/dist/domain/services/knowledge-extractor.js +0 -247
  95. package/dist/domain/services/knowledge-graph-builder.js +0 -268
  96. package/dist/domain/services/knowledge-graph-query.js +0 -187
  97. package/dist/domain/services/memory-retriever.js +0 -82
  98. package/dist/domain/services/memory-synthesizer.js +0 -91
  99. package/dist/domain/services/pattern-extractor.js +0 -442
  100. package/dist/domain/services/query-intent-classifier.js +0 -140
  101. package/dist/domain/services/react-loop.js +0 -186
  102. package/dist/domain/services/risk-tier-detector.js +0 -78
  103. package/dist/edit.js +0 -319
  104. package/dist/embed.js +0 -459
  105. package/dist/formatter.js +0 -168
  106. package/dist/git.js +0 -198
  107. package/dist/infrastructure/ai/cohere-ai-service.js +0 -607
  108. package/dist/infrastructure/ai/command-r-evaluation.js +0 -206
  109. package/dist/infrastructure/ai/model-config.js +0 -84
  110. package/dist/infrastructure/ai/provider-ai-service.js +0 -477
  111. package/dist/infrastructure/cache/embedding-cache.js +0 -175
  112. package/dist/infrastructure/cache/query-result-cache.js +0 -66
  113. package/dist/infrastructure/cache/response-cache.js +0 -48
  114. package/dist/infrastructure/cache/security-scan-cache.js +0 -47
  115. package/dist/infrastructure/chunking/ast-code-chunker.js +0 -19
  116. package/dist/infrastructure/chunking/code-aware-chunker.js +0 -397
  117. package/dist/infrastructure/context/context-compressor.js +0 -329
  118. package/dist/infrastructure/context/conversation-context.js +0 -128
  119. package/dist/infrastructure/context/session-manager.js +0 -94
  120. package/dist/infrastructure/cost/cost-tracker.js +0 -360
  121. package/dist/infrastructure/file-scanner/file-scanner.js +0 -106
  122. package/dist/infrastructure/governance/nist-ai-rmf.js +0 -292
  123. package/dist/infrastructure/governance/policy-as-code.js +0 -258
  124. package/dist/infrastructure/governance/prompt-to-code-lineage.js +0 -239
  125. package/dist/infrastructure/index.js +0 -7
  126. package/dist/infrastructure/observability/prompt-versioner.js +0 -145
  127. package/dist/infrastructure/protocols/a2a-metadata.js +0 -137
  128. package/dist/infrastructure/protocols/a2a-protocol.js +0 -314
  129. package/dist/infrastructure/protocols/mcp-oauth.js +0 -184
  130. package/dist/infrastructure/protocols/mcp-server.js +0 -333
  131. package/dist/infrastructure/protocols/streaming-handler.js +0 -103
  132. package/dist/infrastructure/providers/cohere-provider.js +0 -444
  133. package/dist/infrastructure/providers/fake-provider.js +0 -130
  134. package/dist/infrastructure/providers/local-llm-provider.js +0 -330
  135. package/dist/infrastructure/providers/model-config.types.js +0 -9
  136. package/dist/infrastructure/providers/model-provider.interface.js +0 -8
  137. package/dist/infrastructure/providers/openai-provider.js +0 -413
  138. package/dist/infrastructure/providers/openrouter-provider.js +0 -399
  139. package/dist/infrastructure/providers/operation-provider-resolver.js +0 -105
  140. package/dist/infrastructure/providers/provider-config-loader.js +0 -120
  141. package/dist/infrastructure/providers/provider-registry.js +0 -88
  142. package/dist/infrastructure/safety/pattern-detector.js +0 -133
  143. package/dist/infrastructure/security/ai-sast-scanner.js +0 -290
  144. package/dist/infrastructure/security/docker-sandbox.js +0 -178
  145. package/dist/infrastructure/security/enhanced-security-gate.js +0 -151
  146. package/dist/infrastructure/security/license-scanner.js +0 -167
  147. package/dist/infrastructure/security/provider-bias-detector.js +0 -164
  148. package/dist/infrastructure/security/sandbox-executor.js +0 -64
  149. package/dist/infrastructure/serialization/toon-serializer.js +0 -119
  150. package/dist/infrastructure/storage/memory-stream-service.js +0 -204
  151. package/dist/infrastructure/storage/plan-repository.js +0 -96
  152. package/dist/infrastructure/storage/sqlite-decision-repository.js +0 -232
  153. package/dist/infrastructure/storage/sqlite-embedding-repository.js +0 -311
  154. package/dist/infrastructure/storage/sqlite-knowledge-graph-repository.js +0 -417
  155. package/dist/infrastructure/storage/sqlite-knowledge-preservation-repository.js +0 -230
  156. package/dist/infrastructure/storage/sqlite-memory-repository.js +0 -229
  157. package/dist/infrastructure/storage/sqlite-pattern-repository.js +0 -249
  158. package/dist/infrastructure/storage/task-helpers.js +0 -197
  159. package/dist/infrastructure/telemetry/telemetry-service.js +0 -167
  160. package/dist/infrastructure/ux/appropriate-friction.js +0 -213
  161. package/dist/infrastructure/ux/bi-directional-learning.js +0 -337
  162. package/dist/infrastructure/ux/capability-boundaries.js +0 -42
  163. package/dist/infrastructure/ux/comprehensive-formatter.js +0 -117
  164. package/dist/infrastructure/ux/contextual-feature-discovery.js +0 -10
  165. package/dist/infrastructure/ux/expectation-management.js +0 -327
  166. package/dist/infrastructure/ux/feature-discovery.js +0 -14
  167. package/dist/infrastructure/ux/feedback-prompt.js +0 -45
  168. package/dist/infrastructure/ux/hitl-validation.js +0 -297
  169. package/dist/infrastructure/ux/progress-indicator.js +0 -116
  170. package/dist/infrastructure/ux/progressive-disclosure.js +0 -236
  171. package/dist/infrastructure/ux/review-checkpoint.js +0 -72
  172. package/dist/infrastructure/ux/staged-feature-intro.js +0 -24
  173. package/dist/infrastructure/ux/stream-markdown.js +0 -151
  174. package/dist/infrastructure/ux/syntax-highlighter.js +0 -91
  175. package/dist/infrastructure/ux/team-standards.js +0 -196
  176. package/dist/infrastructure/ux/transparency.js +0 -71
  177. package/dist/infrastructure/validation/agent-feedback.js +0 -55
  178. package/dist/infrastructure/validation/agent-validation-helper.js +0 -137
  179. package/dist/infrastructure/validation/review-handler.js +0 -40
  180. package/dist/infrastructure/validation/summary-aggregator.js +0 -70
  181. package/dist/infrastructure/validation/summary-extractor.js +0 -45
  182. package/dist/infrastructure/validation/trace-summary.js +0 -52
  183. package/dist/infrastructure/verification/verification-service.js +0 -47
  184. package/dist/infrastructure/xai/attention-visualizer.js +0 -172
  185. package/dist/infrastructure/xai/cot-visualizer.js +0 -283
  186. package/dist/infrastructure/xai/decision-tree-log.js +0 -212
  187. package/dist/infrastructure/xai/interactive-xai.js +0 -260
  188. package/dist/infrastructure/xai/uncertainty-quantifier.js +0 -198
  189. package/dist/intelligent-retrieval.js +0 -272
  190. package/dist/intent/classifier.js +0 -2
  191. package/dist/intent/context.js +0 -2
  192. package/dist/iterative-refinement.js +0 -189
  193. package/dist/learning.js +0 -232
  194. package/dist/log.js +0 -31
  195. package/dist/migrate.js +0 -133
  196. package/dist/parallel-processor.js +0 -534
  197. package/dist/planner.js +0 -198
  198. package/dist/policy.js +0 -26
  199. package/dist/presentation/cli/commands/ask-command.js +0 -314
  200. package/dist/presentation/cli/commands/cost-command.js +0 -191
  201. package/dist/presentation/cli/commands/decision-command.js +0 -207
  202. package/dist/presentation/cli/commands/docs-command.js +0 -25
  203. package/dist/presentation/cli/commands/fix-command.js +0 -53
  204. package/dist/presentation/cli/commands/knowledge-command.js +0 -129
  205. package/dist/presentation/cli/commands/learning-dashboard-command.js +0 -183
  206. package/dist/presentation/cli/commands/models-command.js +0 -194
  207. package/dist/presentation/cli/commands/orchestrate-command.js +0 -207
  208. package/dist/presentation/cli/commands/plan-command.js +0 -246
  209. package/dist/presentation/cli/commands/product-command.js +0 -199
  210. package/dist/presentation/cli/commands/react-command.js +0 -181
  211. package/dist/presentation/cli/commands/review-command.js +0 -154
  212. package/dist/presentation/cli/commands/run-command.js +0 -188
  213. package/dist/presentation/cli/commands/smart-command.js +0 -395
  214. package/dist/presentation/cli/commands/suggest-command.js +0 -138
  215. package/dist/presentation/cli/commands/trace-command.js +0 -129
  216. package/dist/presentation/cli/commands/undo-command.js +0 -150
  217. package/dist/query-optimizer.js +0 -205
  218. package/dist/refactor.js +0 -116
  219. package/dist/review.js +0 -206
  220. package/dist/search.js +0 -163
  221. package/dist/session.js +0 -704
  222. package/dist/task-verification.js +0 -336
  223. package/dist/testgen.js +0 -166
  224. package/dist/token-optimizer.js +0 -277
  225. package/dist/tools/bash.js +0 -213
  226. package/dist/tools/edit.js +0 -235
  227. package/dist/tools/executor.js +0 -153
  228. package/dist/tools/git-tool.js +0 -292
  229. package/dist/tools/parser.js +0 -158
  230. package/dist/tools/registry.js +0 -302
  231. package/dist/tools/search.js +0 -100
  232. package/dist/types.js +0 -2
  233. package/dist/utils/check-api-status.js +0 -100
  234. package/dist/utils/diff-parser.js +0 -162
  235. package/dist/verification/backup.js +0 -259
  236. package/dist/verification/compiler.js +0 -264
  237. package/dist/verification/index.js +0 -273
  238. package/dist/verification/test-runner.js +0 -379
@@ -0,0 +1,340 @@
1
+ /**
2
+ * F6 Conductor — codehere's own meta-agent.
3
+ *
4
+ * Plain English in, agent actions out. The Conductor is a first-class
5
+ * AgentAdapter that doesn't fork a subprocess — instead it ROUTES the
6
+ * incoming prompt to one of the dogfooded specialists (Claude Code, Codex,
7
+ * Aider, OpenCode) based on intent, then proxies the spawned session's
8
+ * events back to the caller verbatim, with a single Conductor-attributed
9
+ * "delegated to X" event prepended so the audit log records the routing
10
+ * decision.
11
+ *
12
+ * This is the v0.4-alpha SCAFFOLD. Routing is rule-based (keyword → adapter)
13
+ * for now. The v0.4 stable target replaces the rule lookup with an LLM
14
+ * classifier — Claude Haiku 4.5 prompted to pick the best specialist given
15
+ * the user's request, the available agents, and any context from past
16
+ * sessions. The seam (`pickSpecialist`) is the same; only the body changes.
17
+ *
18
+ * Why this matters: until Conductor exists, codehere is "a UI over other
19
+ * people's agents." With Conductor, codehere becomes a participant in the
20
+ * thread — the user talks to *codehere*, codehere talks to the agents, and
21
+ * the user gets a single conversational surface instead of having to know
22
+ * which specialist suits the task. This is the seam the v0.4+ Slack-shape
23
+ * thread UX (`@conductor` mention) attaches to.
24
+ *
25
+ * What v0.4-alpha intentionally does NOT do:
26
+ * - LLM-backed classifier (rule-based only)
27
+ * - Multi-step plans (one prompt → one specialist)
28
+ * - Cross-session memory (Conductor sees only the current prompt)
29
+ * - Mid-session redirection (once delegated, the specialist owns the session)
30
+ *
31
+ * Adding any of those before v0.4-stable rc.1 violates the "rc.N is feature-
32
+ * frozen, beta.N+1 may only harden or fix" rule.
33
+ *
34
+ * @see docs/CONDUCTOR.md for the full design + roadmap from scaffold → stable
35
+ * @see memory/project_decisions_log.md Decision 05 (F6 as first-class foundation)
36
+ */
37
+ import { EventEmitter } from 'events';
38
+ import { randomUUID } from 'crypto';
39
+ const ROUTING_RULES = [
40
+ {
41
+ triggers: ['review', 'audit', 'explain', 'understand', 'analyze', 'analyse', 'why', 'what does'],
42
+ preferred: ['claude-code', 'codex', 'aider'],
43
+ reason: 'review/audit/explain tasks favor Claude Code',
44
+ },
45
+ {
46
+ triggers: ['refactor', 'restructure', 'reorganize', 'reorganise', 'rewrite the', 'extract'],
47
+ preferred: ['codex', 'claude-code', 'aider'],
48
+ reason: 'structural refactors favor Codex',
49
+ },
50
+ {
51
+ triggers: ['fix', 'patch', 'bugfix', 'hotfix', 'repair', 'resolve'],
52
+ preferred: ['aider', 'claude-code', 'codex'],
53
+ reason: 'targeted fixes favor Aider',
54
+ },
55
+ {
56
+ triggers: ['scaffold', 'generate', 'create new', 'bootstrap', 'set up'],
57
+ preferred: ['opencode', 'claude-code', 'codex'],
58
+ reason: 'greenfield generation favors OpenCode',
59
+ },
60
+ {
61
+ triggers: ['add tests', 'write tests', 'test coverage', 'unit test', 'integration test'],
62
+ preferred: ['codex', 'claude-code', 'aider'],
63
+ reason: 'test authoring favors Codex',
64
+ },
65
+ ];
66
+ /** Default specialist when no routing rule matches. */
67
+ const DEFAULT_SPECIALIST = 'claude-code';
68
+ /**
69
+ * Tokenize a prompt for trigger matching. Splits on any non-alphanumeric
70
+ * boundary (whitespace, hyphens, punctuation), lowercases everything. So:
71
+ *
72
+ * "Bug fix" → ["bug", "fix"]
73
+ * "set-up auth" → ["set", "up", "auth"] (trigger "set up" still matches via phrase below)
74
+ * "unit-test it" → ["unit", "test", "it"]
75
+ * "prefix matter" → ["prefix", "matter"] (does NOT match `fix`)
76
+ * "hotfixes" → ["hotfixes"] (does NOT match `fix`)
77
+ *
78
+ * Multi-word triggers ("add tests", "create new") are matched against the
79
+ * normalized prompt directly using word boundaries — so they catch
80
+ * "add tests" but not "added testing harness".
81
+ */
82
+ function tokenize(prompt) {
83
+ const tokens = new Set(prompt
84
+ .toLowerCase()
85
+ .split(/[^a-z0-9]+/)
86
+ .filter(Boolean));
87
+ // Normalized form for multi-word phrase matching: ANY non-alphanumeric char
88
+ // (hyphens, underscores, slashes, dots, colons, commas, etc.) becomes a space,
89
+ // then collapse runs of whitespace. This matches the tokenizer's split rule
90
+ // exactly, so multi-word triggers like "add tests" catch all of:
91
+ // "add tests" "add-tests" "add_tests" "add/tests" "add:tests" "add.tests"
92
+ // Note: must NOT collapse the leading/trailing spaces — they're load-bearing
93
+ // for the boundary check below (`.includes(' ' + t + ' ')`).
94
+ const normalized = ' ' + prompt.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim() + ' ';
95
+ return { tokens, normalized };
96
+ }
97
+ /**
98
+ * Test whether a routing trigger matches a prompt. Single-word triggers must
99
+ * appear as whole tokens (no substring matches). Multi-word triggers must
100
+ * appear as a phrase in the normalized prompt (with leading/trailing spaces
101
+ * to enforce word boundaries on the ends).
102
+ */
103
+ function triggerMatches(trigger, tokens, normalized) {
104
+ const t = trigger.toLowerCase().trim();
105
+ if (!t)
106
+ return false;
107
+ if (t.includes(' ')) {
108
+ return normalized.includes(' ' + t + ' ');
109
+ }
110
+ return tokens.has(t);
111
+ }
112
+ /**
113
+ * Pick the right specialist for a given prompt.
114
+ *
115
+ * Algorithm:
116
+ * 1. Tokenize the prompt (whole-word matching, no substring false-positives).
117
+ * 2. Walk routing rules in order. Stop at the first rule whose triggers match.
118
+ * 3. Within that rule, return the first preferred adapter that's installed.
119
+ * 4. If that rule had a match but none of its preferred adapters are
120
+ * installed, return DEFAULT_SPECIALIST (or first installed) with a
121
+ * HONEST reason that names the matched rule and the fallback.
122
+ * 5. If no rule matched at all, return DEFAULT_SPECIALIST (or first
123
+ * installed) with a "no intent matched" reason.
124
+ *
125
+ * Returns null if NO specialist is installed (caller must handle).
126
+ *
127
+ * Known limitation: a prompt with multiple intents (e.g. "fix the bug and
128
+ * add tests") routes by the first matching rule, not the dominant intent.
129
+ * The v0.4 LLM classifier inherently handles dominance via confidence
130
+ * scoring; the rule-based path here keeps the deterministic-priority
131
+ * contract instead.
132
+ */
133
+ export function pickSpecialist(prompt, installedAgentIds) {
134
+ if (installedAgentIds.length === 0) {
135
+ return null;
136
+ }
137
+ const installedSet = new Set(installedAgentIds);
138
+ const { tokens, normalized } = tokenize(prompt);
139
+ for (const rule of ROUTING_RULES) {
140
+ const matches = rule.triggers.some((t) => triggerMatches(t, tokens, normalized));
141
+ if (!matches)
142
+ continue;
143
+ // Rule matched. Walk preferred specialists in order.
144
+ for (const candidate of rule.preferred) {
145
+ if (installedSet.has(candidate)) {
146
+ return { agentId: candidate, reason: rule.reason };
147
+ }
148
+ }
149
+ // Rule matched but none of its preferred specialists are installed.
150
+ // Fall through with an HONEST reason that names the matched rule + fallback,
151
+ // so the audit log records what actually happened (Codex review caught
152
+ // the prior version saying "default routing" here, which was a lie).
153
+ const fallbackId = installedSet.has(DEFAULT_SPECIALIST) ? DEFAULT_SPECIALIST : installedAgentIds[0];
154
+ return {
155
+ agentId: fallbackId,
156
+ reason: `${rule.reason} — but none of [${rule.preferred.join(', ')}] installed; falling back to ${fallbackId}`,
157
+ };
158
+ }
159
+ // No rule matched. Default routing.
160
+ if (installedSet.has(DEFAULT_SPECIALIST)) {
161
+ return { agentId: DEFAULT_SPECIALIST, reason: 'default routing (no specific intent matched)' };
162
+ }
163
+ return { agentId: installedAgentIds[0], reason: 'fallback to first available specialist' };
164
+ }
165
+ /**
166
+ * Build the Conductor adapter. The lookup function is injected so we can
167
+ * register against the same registry without creating an import cycle.
168
+ *
169
+ * IMPORTANT: the lookup is called at spawn time, NOT module-load time, so
170
+ * it sees the fully-populated registry including any user-config adapters.
171
+ */
172
+ export function buildConductorAdapter(lookup) {
173
+ const adapter = {
174
+ id: 'conductor',
175
+ label: 'Conductor (codehere)',
176
+ // Conductor doesn't run as its own OS process — there's nothing to detect
177
+ // via `ps`. The processPattern returned here will never match, by design.
178
+ processPattern: /__conductor_never_matches__/,
179
+ isInstalled() {
180
+ // Conductor is "installed" iff at least one specialist is installed.
181
+ // Anything else would be a confusing UX (offer Conductor when it has
182
+ // nothing to delegate to).
183
+ return lookup().some((a) => a.id !== 'conductor' && a.isInstalled());
184
+ },
185
+ checkReadiness() {
186
+ const specialists = lookup().filter((a) => a.id !== 'conductor');
187
+ const installedSpecialists = specialists.filter((a) => a.isInstalled());
188
+ if (installedSpecialists.length === 0) {
189
+ return {
190
+ id: 'conductor',
191
+ label: 'Conductor (codehere)',
192
+ state: 'needs_install',
193
+ installed: false,
194
+ installHint: {
195
+ command: 'npm install -g @anthropic-ai/claude-code',
196
+ url: 'https://github.com/codehere/codehere#install',
197
+ },
198
+ authHint: {
199
+ detail: 'Conductor delegates to specialists. Install at least one (Claude Code, Codex, Aider, or OpenCode) and Conductor becomes available automatically.',
200
+ },
201
+ };
202
+ }
203
+ return {
204
+ id: 'conductor',
205
+ label: 'Conductor (codehere)',
206
+ state: 'ready',
207
+ installed: true,
208
+ };
209
+ },
210
+ spawn(prompt, options) {
211
+ return spawnConductor(prompt, options ?? {}, lookup);
212
+ },
213
+ };
214
+ return adapter;
215
+ }
216
+ /**
217
+ * Spawn the Conductor session. Does not fork a process — instead picks a
218
+ * specialist, spawns it, and proxies its events through with a single
219
+ * "delegated" event prepended to the buffer.
220
+ */
221
+ function spawnConductor(prompt, options, lookup) {
222
+ const sessionId = randomUUID();
223
+ const startedAt = Date.now();
224
+ const emitter = new EventEmitter();
225
+ const buffer = [];
226
+ let statusValue = 'running';
227
+ // Look up installed specialists (excluding Conductor itself to avoid recursion)
228
+ const installedAgentIds = lookup()
229
+ .filter((a) => a.id !== 'conductor' && a.isInstalled())
230
+ .map((a) => a.id);
231
+ const decision = pickSpecialist(prompt, installedAgentIds);
232
+ // If nothing's installed, emit an error event and return a non-running session.
233
+ if (!decision) {
234
+ statusValue = 'error';
235
+ const errEvent = {
236
+ type: 'error',
237
+ timestamp: Date.now(),
238
+ data: {
239
+ message: 'Conductor has no specialists to delegate to. Install at least one of: Claude Code, Codex, Aider, OpenCode.',
240
+ },
241
+ };
242
+ buffer.push(errEvent);
243
+ queueMicrotask(() => emitter.emit('event', errEvent));
244
+ return synthesizeSession({ sessionId, startedAt, prompt, statusValue, emitter, buffer });
245
+ }
246
+ // Emit the routing-decision event FIRST so the audit log records WHY this
247
+ // specialist was chosen. Layer 7 agent-provenance — every action attributable.
248
+ const routingEvent = {
249
+ type: 'codehere:conductor-routing',
250
+ timestamp: Date.now(),
251
+ data: {
252
+ conductorSessionId: sessionId,
253
+ delegatedTo: decision.agentId,
254
+ reason: decision.reason,
255
+ promptExcerpt: prompt.slice(0, 200),
256
+ },
257
+ };
258
+ buffer.push(routingEvent);
259
+ queueMicrotask(() => emitter.emit('event', routingEvent));
260
+ // Find the chosen specialist adapter and spawn against it.
261
+ const specialist = lookup().find((a) => a.id === decision.agentId);
262
+ if (!specialist) {
263
+ // Defensive: pickSpecialist returned an ID not in the registry. Shouldn't
264
+ // happen if installedAgentIds was derived from lookup(), but guard anyway.
265
+ statusValue = 'error';
266
+ const errEvent = {
267
+ type: 'error',
268
+ timestamp: Date.now(),
269
+ data: { message: `Conductor picked '${decision.agentId}' but no adapter with that ID is registered.` },
270
+ };
271
+ buffer.push(errEvent);
272
+ queueMicrotask(() => emitter.emit('event', errEvent));
273
+ return synthesizeSession({ sessionId, startedAt, prompt, statusValue, emitter, buffer });
274
+ }
275
+ // Spawn the specialist session and proxy every event through.
276
+ const specialistSession = specialist.spawn(prompt, options);
277
+ let stepsSnapshot = [];
278
+ let artifactsSnapshot;
279
+ specialistSession.subscribe((evt) => {
280
+ buffer.push(evt);
281
+ emitter.emit('event', evt);
282
+ // Mirror progress + artifacts so PM-UX layers see them on the Conductor session, too.
283
+ if (specialistSession.steps)
284
+ stepsSnapshot = specialistSession.steps;
285
+ if (specialistSession.artifacts)
286
+ artifactsSnapshot = specialistSession.artifacts;
287
+ if (evt.type === 'codehere:complete' || evt.type === 'codehere:error') {
288
+ statusValue = specialistSession.status;
289
+ }
290
+ });
291
+ return {
292
+ sessionId,
293
+ startedAt,
294
+ prompt,
295
+ agent: 'conductor',
296
+ get status() {
297
+ return statusValue;
298
+ },
299
+ get steps() {
300
+ return stepsSnapshot;
301
+ },
302
+ get artifacts() {
303
+ return artifactsSnapshot;
304
+ },
305
+ canAppendMessage: false, // v0.4-alpha doesn't support mid-session redirection
306
+ subscribe(handler) {
307
+ for (const e of buffer)
308
+ handler(e);
309
+ emitter.on('event', handler);
310
+ return () => emitter.off('event', handler);
311
+ },
312
+ kill() {
313
+ specialistSession.kill();
314
+ statusValue = 'killed';
315
+ },
316
+ };
317
+ }
318
+ /** Build a TaskSession that just replays an event buffer — used for error states. */
319
+ function synthesizeSession(args) {
320
+ const { sessionId, startedAt, prompt, statusValue, emitter, buffer } = args;
321
+ return {
322
+ sessionId,
323
+ startedAt,
324
+ prompt,
325
+ agent: 'conductor',
326
+ get status() {
327
+ return statusValue;
328
+ },
329
+ subscribe(handler) {
330
+ for (const e of buffer)
331
+ handler(e);
332
+ emitter.on('event', handler);
333
+ return () => emitter.off('event', handler);
334
+ },
335
+ kill() {
336
+ /* nothing to kill — never started */
337
+ },
338
+ };
339
+ }
340
+ //# sourceMappingURL=conductor-adapter.js.map