botinabox 2.4.2 → 2.5.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 (277) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +190 -190
  3. package/bin/botinabox.mjs +2 -2
  4. package/dist/channels/slack/index.d.ts +1 -1
  5. package/dist/{chat-pipeline-BWrtVqEP.d.ts → chat-pipeline-DuNX5WoL.d.ts} +3 -0
  6. package/dist/cli.js +0 -0
  7. package/dist/index.d.ts +11 -2
  8. package/dist/index.js +64 -27
  9. package/package.json +100 -99
  10. package/dist/channels/discord/adapter.d.ts +0 -32
  11. package/dist/channels/discord/adapter.js +0 -70
  12. package/dist/channels/discord/inbound.d.ts +0 -25
  13. package/dist/channels/discord/inbound.js +0 -24
  14. package/dist/channels/discord/models.d.ts +0 -8
  15. package/dist/channels/discord/models.js +0 -5
  16. package/dist/channels/discord/outbound.d.ts +0 -14
  17. package/dist/channels/discord/outbound.js +0 -38
  18. package/dist/channels/slack/adapter.d.ts +0 -33
  19. package/dist/channels/slack/adapter.js +0 -74
  20. package/dist/channels/slack/inbound.d.ts +0 -59
  21. package/dist/channels/slack/inbound.js +0 -96
  22. package/dist/channels/slack/models.d.ts +0 -9
  23. package/dist/channels/slack/models.js +0 -5
  24. package/dist/channels/slack/outbound.d.ts +0 -12
  25. package/dist/channels/slack/outbound.js +0 -18
  26. package/dist/channels/slack/transcribe.d.ts +0 -41
  27. package/dist/channels/slack/transcribe.js +0 -106
  28. package/dist/channels/webhook/adapter.d.ts +0 -23
  29. package/dist/channels/webhook/adapter.js +0 -86
  30. package/dist/channels/webhook/hmac.d.ts +0 -13
  31. package/dist/channels/webhook/hmac.js +0 -26
  32. package/dist/channels/webhook/models.d.ts +0 -9
  33. package/dist/channels/webhook/models.js +0 -5
  34. package/dist/channels/webhook/server.d.ts +0 -20
  35. package/dist/channels/webhook/server.js +0 -91
  36. package/dist/chat-pipeline-C-XlLGNl.d.ts +0 -648
  37. package/dist/chat-pipeline-CR1KF6eX.d.ts +0 -652
  38. package/dist/chat-pipeline-DisuC8SB.d.ts +0 -643
  39. package/dist/chunk-2LGXQPEA.js +0 -41
  40. package/dist/chunk-3X3YKI4T.js +0 -357
  41. package/dist/chunk-D47AIFOD.js +0 -351
  42. package/dist/chunk-DSNJKNEW.js +0 -328
  43. package/dist/chunk-GS2JFL6I.js +0 -144
  44. package/dist/chunk-J6S6QMUY.js +0 -144
  45. package/dist/chunk-QLA6YOFN.js +0 -22
  46. package/dist/chunk-UACT2WXX.js +0 -381
  47. package/dist/cli/templates/config.yml.d.ts +0 -7
  48. package/dist/cli/templates/config.yml.js +0 -61
  49. package/dist/cli/templates/env.d.ts +0 -1
  50. package/dist/cli/templates/env.js +0 -30
  51. package/dist/cli/templates/index.ts.d.ts +0 -2
  52. package/dist/cli/templates/index.ts.js +0 -30
  53. package/dist/cli/templates/package.json.d.ts +0 -5
  54. package/dist/cli/templates/package.json.js +0 -28
  55. package/dist/connector-DDahQw-2.d.ts +0 -63
  56. package/dist/connectors/google/calendar-connector.d.ts +0 -40
  57. package/dist/connectors/google/calendar-connector.js +0 -243
  58. package/dist/connectors/google/gmail-connector.d.ts +0 -42
  59. package/dist/connectors/google/gmail-connector.js +0 -345
  60. package/dist/connectors/google/oauth.d.ts +0 -48
  61. package/dist/connectors/google/oauth.js +0 -112
  62. package/dist/connectors/google/types.d.ts +0 -78
  63. package/dist/connectors/google/types.js +0 -2
  64. package/dist/core/chat/auto-discovery.d.ts +0 -16
  65. package/dist/core/chat/auto-discovery.js +0 -54
  66. package/dist/core/chat/channel-registry.d.ts +0 -45
  67. package/dist/core/chat/channel-registry.js +0 -96
  68. package/dist/core/chat/chat-pipeline.d.ts +0 -113
  69. package/dist/core/chat/chat-pipeline.js +0 -395
  70. package/dist/core/chat/chat-responder.d.ts +0 -90
  71. package/dist/core/chat/chat-responder.js +0 -185
  72. package/dist/core/chat/formatter.d.ts +0 -11
  73. package/dist/core/chat/formatter.js +0 -60
  74. package/dist/core/chat/index.d.ts +0 -24
  75. package/dist/core/chat/index.js +0 -18
  76. package/dist/core/chat/message-interpreter.d.ts +0 -91
  77. package/dist/core/chat/message-interpreter.js +0 -166
  78. package/dist/core/chat/message-store.d.ts +0 -66
  79. package/dist/core/chat/message-store.js +0 -131
  80. package/dist/core/chat/notification-queue.d.ts +0 -34
  81. package/dist/core/chat/notification-queue.js +0 -111
  82. package/dist/core/chat/pipeline.d.ts +0 -38
  83. package/dist/core/chat/pipeline.js +0 -89
  84. package/dist/core/chat/policies.d.ts +0 -16
  85. package/dist/core/chat/policies.js +0 -25
  86. package/dist/core/chat/routing.d.ts +0 -17
  87. package/dist/core/chat/routing.js +0 -36
  88. package/dist/core/chat/session-key.d.ts +0 -30
  89. package/dist/core/chat/session-key.js +0 -65
  90. package/dist/core/chat/session-manager.d.ts +0 -17
  91. package/dist/core/chat/session-manager.js +0 -23
  92. package/dist/core/chat/text-chunker.d.ts +0 -9
  93. package/dist/core/chat/text-chunker.js +0 -48
  94. package/dist/core/chat/triage-router.d.ts +0 -75
  95. package/dist/core/chat/triage-router.js +0 -142
  96. package/dist/core/chat/types.d.ts +0 -5
  97. package/dist/core/chat/types.js +0 -5
  98. package/dist/core/config/defaults.d.ts +0 -2
  99. package/dist/core/config/defaults.js +0 -38
  100. package/dist/core/config/index.d.ts +0 -6
  101. package/dist/core/config/index.js +0 -4
  102. package/dist/core/config/interpolate.d.ts +0 -5
  103. package/dist/core/config/interpolate.js +0 -27
  104. package/dist/core/config/loader.d.ts +0 -24
  105. package/dist/core/config/loader.js +0 -59
  106. package/dist/core/config/schema.d.ts +0 -5
  107. package/dist/core/config/schema.js +0 -119
  108. package/dist/core/data/core-entity-contexts.d.ts +0 -14
  109. package/dist/core/data/core-entity-contexts.js +0 -197
  110. package/dist/core/data/core-migrations.d.ts +0 -5
  111. package/dist/core/data/core-migrations.js +0 -45
  112. package/dist/core/data/core-schema.d.ts +0 -6
  113. package/dist/core/data/core-schema.js +0 -454
  114. package/dist/core/data/data-store.d.ts +0 -67
  115. package/dist/core/data/data-store.js +0 -218
  116. package/dist/core/data/domain-entity-contexts.d.ts +0 -29
  117. package/dist/core/data/domain-entity-contexts.js +0 -321
  118. package/dist/core/data/domain-schema.d.ts +0 -36
  119. package/dist/core/data/domain-schema.js +0 -323
  120. package/dist/core/data/index.d.ts +0 -7
  121. package/dist/core/data/index.js +0 -7
  122. package/dist/core/data/types.d.ts +0 -111
  123. package/dist/core/data/types.js +0 -1
  124. package/dist/core/hooks/hook-bus.d.ts +0 -18
  125. package/dist/core/hooks/hook-bus.js +0 -120
  126. package/dist/core/hooks/index.d.ts +0 -2
  127. package/dist/core/hooks/index.js +0 -1
  128. package/dist/core/hooks/types.d.ts +0 -19
  129. package/dist/core/hooks/types.js +0 -1
  130. package/dist/core/index.d.ts +0 -4
  131. package/dist/core/index.js +0 -4
  132. package/dist/core/llm/auto-discovery.d.ts +0 -11
  133. package/dist/core/llm/auto-discovery.js +0 -49
  134. package/dist/core/llm/cost-tracker.d.ts +0 -6
  135. package/dist/core/llm/cost-tracker.js +0 -38
  136. package/dist/core/llm/index.d.ts +0 -4
  137. package/dist/core/llm/index.js +0 -3
  138. package/dist/core/llm/model-router.d.ts +0 -25
  139. package/dist/core/llm/model-router.js +0 -49
  140. package/dist/core/llm/provider-registry.d.ts +0 -9
  141. package/dist/core/llm/provider-registry.js +0 -25
  142. package/dist/core/llm/types.d.ts +0 -2
  143. package/dist/core/llm/types.js +0 -2
  144. package/dist/core/orchestrator/adapters/api-adapter.d.ts +0 -34
  145. package/dist/core/orchestrator/adapters/api-adapter.js +0 -88
  146. package/dist/core/orchestrator/adapters/cli-adapter.d.ts +0 -22
  147. package/dist/core/orchestrator/adapters/cli-adapter.js +0 -69
  148. package/dist/core/orchestrator/adapters/deterministic-adapter.d.ts +0 -35
  149. package/dist/core/orchestrator/adapters/deterministic-adapter.js +0 -75
  150. package/dist/core/orchestrator/adapters/env-whitelist.d.ts +0 -4
  151. package/dist/core/orchestrator/adapters/env-whitelist.js +0 -27
  152. package/dist/core/orchestrator/adapters/output-extractor.d.ts +0 -11
  153. package/dist/core/orchestrator/adapters/output-extractor.js +0 -59
  154. package/dist/core/orchestrator/adapters/process-manager.d.ts +0 -15
  155. package/dist/core/orchestrator/adapters/process-manager.js +0 -26
  156. package/dist/core/orchestrator/adapters/tool-loop.d.ts +0 -22
  157. package/dist/core/orchestrator/adapters/tool-loop.js +0 -66
  158. package/dist/core/orchestrator/agent-registry.d.ts +0 -31
  159. package/dist/core/orchestrator/agent-registry.js +0 -135
  160. package/dist/core/orchestrator/budget-controller.d.ts +0 -19
  161. package/dist/core/orchestrator/budget-controller.js +0 -73
  162. package/dist/core/orchestrator/chain-guard.d.ts +0 -14
  163. package/dist/core/orchestrator/chain-guard.js +0 -23
  164. package/dist/core/orchestrator/circuit-breaker.d.ts +0 -65
  165. package/dist/core/orchestrator/circuit-breaker.js +0 -159
  166. package/dist/core/orchestrator/claude-stream-parser.d.ts +0 -31
  167. package/dist/core/orchestrator/claude-stream-parser.js +0 -99
  168. package/dist/core/orchestrator/config-revisions.d.ts +0 -6
  169. package/dist/core/orchestrator/config-revisions.js +0 -17
  170. package/dist/core/orchestrator/dependency-resolver.d.ts +0 -20
  171. package/dist/core/orchestrator/dependency-resolver.js +0 -78
  172. package/dist/core/orchestrator/governance-gate.d.ts +0 -110
  173. package/dist/core/orchestrator/governance-gate.js +0 -170
  174. package/dist/core/orchestrator/learning-pipeline.d.ts +0 -109
  175. package/dist/core/orchestrator/learning-pipeline.js +0 -249
  176. package/dist/core/orchestrator/loop-detector.d.ts +0 -51
  177. package/dist/core/orchestrator/loop-detector.js +0 -133
  178. package/dist/core/orchestrator/ndjson-logger.d.ts +0 -6
  179. package/dist/core/orchestrator/ndjson-logger.js +0 -18
  180. package/dist/core/orchestrator/permission-relay.d.ts +0 -72
  181. package/dist/core/orchestrator/permission-relay.js +0 -164
  182. package/dist/core/orchestrator/run-manager.d.ts +0 -31
  183. package/dist/core/orchestrator/run-manager.js +0 -178
  184. package/dist/core/orchestrator/scheduler.d.ts +0 -70
  185. package/dist/core/orchestrator/scheduler.js +0 -198
  186. package/dist/core/orchestrator/secret-store.d.ts +0 -57
  187. package/dist/core/orchestrator/secret-store.js +0 -171
  188. package/dist/core/orchestrator/session-manager.d.ts +0 -13
  189. package/dist/core/orchestrator/session-manager.js +0 -66
  190. package/dist/core/orchestrator/task-queue.d.ts +0 -34
  191. package/dist/core/orchestrator/task-queue.js +0 -83
  192. package/dist/core/orchestrator/template-interpolate.d.ts +0 -5
  193. package/dist/core/orchestrator/template-interpolate.js +0 -18
  194. package/dist/core/orchestrator/user-registry.d.ts +0 -47
  195. package/dist/core/orchestrator/user-registry.js +0 -76
  196. package/dist/core/orchestrator/wakeup-queue.d.ts +0 -9
  197. package/dist/core/orchestrator/wakeup-queue.js +0 -45
  198. package/dist/core/orchestrator/workflow-engine.d.ts +0 -47
  199. package/dist/core/orchestrator/workflow-engine.js +0 -204
  200. package/dist/core/security/audit.d.ts +0 -20
  201. package/dist/core/security/audit.js +0 -33
  202. package/dist/core/security/column-validator.d.ts +0 -20
  203. package/dist/core/security/column-validator.js +0 -37
  204. package/dist/core/security/index.d.ts +0 -5
  205. package/dist/core/security/index.js +0 -5
  206. package/dist/core/security/process-env.d.ts +0 -13
  207. package/dist/core/security/process-env.js +0 -49
  208. package/dist/core/security/sanitizer.d.ts +0 -11
  209. package/dist/core/security/sanitizer.js +0 -39
  210. package/dist/core/security/types.d.ts +0 -11
  211. package/dist/core/security/types.js +0 -1
  212. package/dist/core/update/auto-update.d.ts +0 -21
  213. package/dist/core/update/auto-update.js +0 -102
  214. package/dist/core/update/backup-manager.d.ts +0 -7
  215. package/dist/core/update/backup-manager.js +0 -24
  216. package/dist/core/update/index.d.ts +0 -8
  217. package/dist/core/update/index.js +0 -6
  218. package/dist/core/update/migration-hooks.d.ts +0 -11
  219. package/dist/core/update/migration-hooks.js +0 -10
  220. package/dist/core/update/types.d.ts +0 -11
  221. package/dist/core/update/types.js +0 -1
  222. package/dist/core/update/update-checker.d.ts +0 -11
  223. package/dist/core/update/update-checker.js +0 -63
  224. package/dist/core/update/update-manager.d.ts +0 -25
  225. package/dist/core/update/update-manager.js +0 -101
  226. package/dist/core/update/version-utils.d.ts +0 -6
  227. package/dist/core/update/version-utils.js +0 -34
  228. package/dist/gmail-connector-2FVYTQJH.js +0 -6
  229. package/dist/gmail-connector-MNUBRNFM.js +0 -6
  230. package/dist/gmail-connector-PS2VLGNE.js +0 -6
  231. package/dist/gmail-connector-ULSMN6X2.js +0 -6
  232. package/dist/gmail-connector-URRFX6A3.js +0 -6
  233. package/dist/inbound-AFBUPSPG.js +0 -10
  234. package/dist/inbound-AFOHYNUY.js +0 -6
  235. package/dist/inbound-CGIXRXGC.js +0 -8
  236. package/dist/inbound-MCOLRH6U.js +0 -10
  237. package/dist/inbound-SNEMBLGA.js +0 -6
  238. package/dist/inbound-ZJHAYVMF.js +0 -10
  239. package/dist/provider-qqJYv9nv.d.ts +0 -75
  240. package/dist/providers/anthropic/models.d.ts +0 -2
  241. package/dist/providers/anthropic/models.js +0 -29
  242. package/dist/providers/anthropic/provider.d.ts +0 -13
  243. package/dist/providers/anthropic/provider.js +0 -119
  244. package/dist/providers/anthropic/tool-converter.d.ts +0 -10
  245. package/dist/providers/anthropic/tool-converter.js +0 -7
  246. package/dist/providers/ollama/provider.d.ts +0 -17
  247. package/dist/providers/ollama/provider.js +0 -185
  248. package/dist/providers/openai/models.d.ts +0 -2
  249. package/dist/providers/openai/models.js +0 -29
  250. package/dist/providers/openai/provider.d.ts +0 -13
  251. package/dist/providers/openai/provider.js +0 -163
  252. package/dist/providers/openai/tool-converter.d.ts +0 -10
  253. package/dist/providers/openai/tool-converter.js +0 -10
  254. package/dist/shared/constants.d.ts +0 -50
  255. package/dist/shared/constants.js +0 -64
  256. package/dist/shared/index.d.ts +0 -14
  257. package/dist/shared/index.js +0 -14
  258. package/dist/shared/types/agent.d.ts +0 -36
  259. package/dist/shared/types/agent.js +0 -2
  260. package/dist/shared/types/channel.d.ts +0 -70
  261. package/dist/shared/types/channel.js +0 -2
  262. package/dist/shared/types/config.d.ts +0 -111
  263. package/dist/shared/types/config.js +0 -2
  264. package/dist/shared/types/connector.d.ts +0 -77
  265. package/dist/shared/types/connector.js +0 -2
  266. package/dist/shared/types/execution.d.ts +0 -29
  267. package/dist/shared/types/execution.js +0 -2
  268. package/dist/shared/types/provider.d.ts +0 -73
  269. package/dist/shared/types/provider.js +0 -2
  270. package/dist/shared/types/task.d.ts +0 -47
  271. package/dist/shared/types/task.js +0 -2
  272. package/dist/shared/types/workflow.d.ts +0 -39
  273. package/dist/shared/types/workflow.js +0 -2
  274. package/dist/shared/utils.d.ts +0 -6
  275. package/dist/shared/utils.js +0 -13
  276. package/dist/update-check.d.ts +0 -5
  277. package/dist/update-check.js +0 -56
@@ -1,142 +0,0 @@
1
- /**
2
- * TriageRouter — content-based routing with deterministic-first resolution.
3
- * Story 6.3
4
- *
5
- * Replaces the simple channel→agent binding with intelligent routing:
6
- * 1. Keyword/regex rules evaluated first (deterministic, ~4ms)
7
- * 2. LLM classification only for ambiguous messages (async, ~2-4s)
8
- * 3. Ownership chain logged for every routing decision
9
- *
10
- * Key constraint: specialists return to triage, never to another specialist.
11
- */
12
- export class TriageRouter {
13
- db;
14
- hooks;
15
- rules;
16
- fallbackAgent;
17
- llmFallback;
18
- persist;
19
- compiledRules;
20
- constructor(db, hooks, config) {
21
- this.db = db;
22
- this.hooks = hooks;
23
- this.rules = config.rules;
24
- this.fallbackAgent = config.fallbackAgent;
25
- this.llmFallback = config.llmFallback ?? true;
26
- this.persist = config.persist ?? true;
27
- // Pre-compile patterns for fast matching
28
- this.compiledRules = this.rules
29
- .sort((a, b) => (a.priority ?? 50) - (b.priority ?? 50))
30
- .map((rule) => ({
31
- rule,
32
- regexes: (rule.patterns ?? []).map((p) => new RegExp(p, 'i')),
33
- keywordSet: new Set((rule.keywords ?? []).map((k) => k.toLowerCase())),
34
- }));
35
- }
36
- /**
37
- * Route an inbound message to the best agent.
38
- * Returns the agent slug and the routing decision.
39
- */
40
- async route(msg) {
41
- const body = msg.body.toLowerCase();
42
- const words = new Set(body.split(/\s+/));
43
- // Phase 1: Deterministic — keyword + regex matching
44
- for (const { rule, regexes, keywordSet } of this.compiledRules) {
45
- // Keyword match
46
- for (const keyword of keywordSet) {
47
- if (words.has(keyword) || body.includes(keyword)) {
48
- const decision = this.buildDecision(rule.agentSlug, `keyword: '${keyword}'`, 'deterministic', msg);
49
- await this.logDecision(decision);
50
- return { agentSlug: rule.agentSlug, decision };
51
- }
52
- }
53
- // Regex match
54
- for (const regex of regexes) {
55
- if (regex.test(msg.body)) {
56
- const decision = this.buildDecision(rule.agentSlug, `pattern: ${regex.source}`, 'deterministic', msg);
57
- await this.logDecision(decision);
58
- return { agentSlug: rule.agentSlug, decision };
59
- }
60
- }
61
- }
62
- // Phase 2: LLM classification (if enabled)
63
- if (this.llmFallback) {
64
- const agentSlugs = this.rules.map((r) => r.agentSlug);
65
- const classified = await this.classifyWithLLM(msg, agentSlugs);
66
- if (classified) {
67
- const decision = this.buildDecision(classified.agentSlug, `llm: ${classified.reason}`, 'llm', msg);
68
- await this.logDecision(decision);
69
- return { agentSlug: classified.agentSlug, decision };
70
- }
71
- }
72
- // Phase 3: Fallback
73
- const decision = this.buildDecision(this.fallbackAgent, 'fallback: no rule matched', 'deterministic', msg);
74
- await this.logDecision(decision);
75
- return { agentSlug: this.fallbackAgent, decision };
76
- }
77
- /**
78
- * Query the ownership chain for a given message or channel.
79
- */
80
- async getDecisionHistory(filter) {
81
- const rows = await this.db.query('activity_log', {
82
- where: { event_type: 'triage_decision' },
83
- });
84
- let decisions = rows.map((r) => {
85
- try {
86
- return JSON.parse(r['payload']);
87
- }
88
- catch {
89
- return null;
90
- }
91
- }).filter((d) => d !== null);
92
- if (filter?.channel) {
93
- decisions = decisions.filter((d) => d.channel === filter.channel);
94
- }
95
- // Sort by timestamp descending
96
- decisions.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
97
- if (filter?.limit) {
98
- decisions = decisions.slice(0, filter.limit);
99
- }
100
- return decisions;
101
- }
102
- /**
103
- * LLM classification — emits a hook for external LLM integration.
104
- * Returns agent slug + reason, or undefined if LLM is unavailable.
105
- */
106
- async classifyWithLLM(msg, agentSlugs) {
107
- // Emit classification request — listeners provide the result
108
- const result = {};
109
- await this.hooks.emit('triage.classify', {
110
- message: msg,
111
- candidates: agentSlugs,
112
- respond: (slug, reason) => {
113
- result.agentSlug = slug;
114
- result.reason = reason;
115
- },
116
- });
117
- if (result.agentSlug && result.reason) {
118
- return { agentSlug: result.agentSlug, reason: result.reason };
119
- }
120
- return undefined;
121
- }
122
- buildDecision(target, reason, method, msg) {
123
- return {
124
- timestamp: new Date().toISOString(),
125
- source: 'triage',
126
- target: target ?? 'none',
127
- reason,
128
- method,
129
- messageId: msg.id,
130
- channel: msg.channel,
131
- };
132
- }
133
- async logDecision(decision) {
134
- if (!this.persist)
135
- return;
136
- await this.db.insert('activity_log', {
137
- event_type: 'triage_decision',
138
- payload: JSON.stringify(decision),
139
- });
140
- await this.hooks.emit('triage.routed', { decision });
141
- }
142
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Chat types — re-exports from @botinabox/shared channel types.
3
- * Story 4.1
4
- */
5
- export type { ChatType, FormattingMode, ChannelCapabilities, ChannelMeta, InboundMessage, Attachment, OutboundPayload, SendResult, HealthStatus, ChannelConfig, ChannelAdapter, } from "../../shared/index.js";
@@ -1,5 +0,0 @@
1
- /**
2
- * Chat types — re-exports from @botinabox/shared channel types.
3
- * Story 4.1
4
- */
5
- export {};
@@ -1,2 +0,0 @@
1
- import type { BotConfig } from "../../shared/index.js";
2
- export declare const DEFAULT_CONFIG: BotConfig;
@@ -1,38 +0,0 @@
1
- export const DEFAULT_CONFIG = {
2
- data: {
3
- path: "./data/bot.db",
4
- walMode: true,
5
- },
6
- channels: {},
7
- agents: [],
8
- providers: {},
9
- models: {
10
- aliases: {
11
- fast: "claude-haiku-4-5",
12
- smart: "claude-opus-4-6",
13
- balanced: "claude-sonnet-4-6",
14
- },
15
- default: "smart",
16
- routing: {
17
- conversation: "fast",
18
- task_execution: "smart",
19
- classification: "fast",
20
- },
21
- fallbackChain: [],
22
- },
23
- entities: {},
24
- security: {
25
- fieldLengthLimits: { default: 65535 },
26
- },
27
- render: {
28
- outputDir: "./context",
29
- watchIntervalMs: 30_000,
30
- },
31
- updates: {
32
- policy: "auto-compatible",
33
- checkIntervalMs: 86_400_000,
34
- },
35
- budget: {
36
- warnPercent: 80,
37
- },
38
- };
@@ -1,6 +0,0 @@
1
- export { loadConfig, getConfig, initConfig, _resetConfig } from "./loader.js";
2
- export type { ConfigLoadError, ConfigLoadResult } from "./loader.js";
3
- export { interpolateEnv } from "./interpolate.js";
4
- export { validateConfig } from "./schema.js";
5
- export type { SchemaError } from "./schema.js";
6
- export { DEFAULT_CONFIG } from "./defaults.js";
@@ -1,4 +0,0 @@
1
- export { loadConfig, getConfig, initConfig, _resetConfig } from "./loader.js";
2
- export { interpolateEnv } from "./interpolate.js";
3
- export { validateConfig } from "./schema.js";
4
- export { DEFAULT_CONFIG } from "./defaults.js";
@@ -1,5 +0,0 @@
1
- /**
2
- * Interpolate ${ENV_VAR} references in YAML string values.
3
- * Recursively walks objects and arrays.
4
- */
5
- export declare function interpolateEnv(value: unknown, env?: Record<string, string | undefined>): unknown;
@@ -1,27 +0,0 @@
1
- /**
2
- * Interpolate ${ENV_VAR} references in YAML string values.
3
- * Recursively walks objects and arrays.
4
- */
5
- export function interpolateEnv(value, env = process.env) {
6
- if (typeof value === "string") {
7
- return value.replace(/\$\{([^}]+)\}/g, (_, name) => {
8
- const envVal = env[name];
9
- if (envVal === undefined) {
10
- // Leave the placeholder if env var is not set (don't silently swallow)
11
- return `\${${name}}`;
12
- }
13
- return envVal;
14
- });
15
- }
16
- if (Array.isArray(value)) {
17
- return value.map(item => interpolateEnv(item, env));
18
- }
19
- if (value !== null && typeof value === "object") {
20
- const result = {};
21
- for (const [k, v] of Object.entries(value)) {
22
- result[k] = interpolateEnv(v, env);
23
- }
24
- return result;
25
- }
26
- return value;
27
- }
@@ -1,24 +0,0 @@
1
- import type { BotConfig } from "../../shared/index.js";
2
- export interface ConfigLoadError {
3
- field: string;
4
- message: string;
5
- }
6
- export interface ConfigLoadResult {
7
- config: BotConfig;
8
- errors: ConfigLoadError[];
9
- }
10
- /**
11
- * Load and merge config from file, with env var interpolation and runtime overrides.
12
- * Merge order: defaults < config file < runtime overrides
13
- */
14
- export declare function loadConfig(opts?: {
15
- configPath?: string;
16
- overrides?: Partial<BotConfig>;
17
- env?: Record<string, string | undefined>;
18
- }): ConfigLoadResult;
19
- /** Get the loaded config singleton. Call loadConfig() first. */
20
- export declare function getConfig(): BotConfig;
21
- /** Initialize the config singleton. Returns errors if any. */
22
- export declare function initConfig(opts?: Parameters<typeof loadConfig>[0]): ConfigLoadError[];
23
- /** Reset the singleton (for testing) */
24
- export declare function _resetConfig(): void;
@@ -1,59 +0,0 @@
1
- import { readFileSync, existsSync } from "node:fs";
2
- import { parse as parseYaml } from "yaml";
3
- import { DEFAULT_CONFIG } from "./defaults.js";
4
- import { interpolateEnv } from "./interpolate.js";
5
- function deepMerge(base, override) {
6
- if (override === undefined || override === null)
7
- return base;
8
- if (base === undefined || base === null)
9
- return override;
10
- if (typeof base !== "object" || typeof override !== "object")
11
- return override;
12
- if (Array.isArray(override))
13
- return override;
14
- const result = { ...base };
15
- for (const [k, v] of Object.entries(override)) {
16
- if (v !== undefined) {
17
- result[k] = deepMerge(result[k], v);
18
- }
19
- }
20
- return result;
21
- }
22
- /**
23
- * Load and merge config from file, with env var interpolation and runtime overrides.
24
- * Merge order: defaults < config file < runtime overrides
25
- */
26
- export function loadConfig(opts) {
27
- const configPath = opts?.configPath ?? "botinabox.config.yml";
28
- const errors = [];
29
- let fileConfig = {};
30
- if (existsSync(configPath)) {
31
- try {
32
- const raw = readFileSync(configPath, "utf-8");
33
- const parsed = parseYaml(raw);
34
- fileConfig = interpolateEnv(parsed, opts?.env ?? process.env);
35
- }
36
- catch (err) {
37
- errors.push({ field: "configPath", message: `Failed to parse ${configPath}: ${String(err)}` });
38
- }
39
- }
40
- const merged = deepMerge(deepMerge(DEFAULT_CONFIG, fileConfig), opts?.overrides ?? {});
41
- return { config: Object.freeze(merged), errors };
42
- }
43
- let _config = null;
44
- /** Get the loaded config singleton. Call loadConfig() first. */
45
- export function getConfig() {
46
- if (!_config)
47
- throw new Error("Config not loaded — call loadConfig() first");
48
- return _config;
49
- }
50
- /** Initialize the config singleton. Returns errors if any. */
51
- export function initConfig(opts) {
52
- const { config, errors } = loadConfig(opts);
53
- _config = config;
54
- return errors;
55
- }
56
- /** Reset the singleton (for testing) */
57
- export function _resetConfig() {
58
- _config = null;
59
- }
@@ -1,5 +0,0 @@
1
- export interface SchemaError {
2
- path: string;
3
- message: string;
4
- }
5
- export declare function validateConfig(config: unknown): SchemaError[];
@@ -1,119 +0,0 @@
1
- import Ajv from "ajv";
2
- const ajv = new Ajv({ allErrors: true, coerceTypes: false });
3
- const BOT_CONFIG_SCHEMA = {
4
- type: "object",
5
- additionalProperties: true,
6
- properties: {
7
- data: {
8
- type: "object",
9
- required: ["path", "walMode"],
10
- properties: {
11
- path: { type: "string", minLength: 1 },
12
- walMode: { type: "boolean" },
13
- backupDir: { type: "string" },
14
- },
15
- },
16
- models: {
17
- type: "object",
18
- required: ["aliases", "default", "routing", "fallbackChain"],
19
- properties: {
20
- aliases: { type: "object", additionalProperties: { type: "string" } },
21
- default: { type: "string", minLength: 1 },
22
- routing: { type: "object", additionalProperties: { type: "string" } },
23
- fallbackChain: { type: "array", items: { type: "string" } },
24
- costLimit: {
25
- type: "object",
26
- properties: {
27
- perRunCents: { type: "number", minimum: 0 },
28
- },
29
- },
30
- },
31
- },
32
- security: {
33
- type: "object",
34
- properties: {
35
- fieldLengthLimits: { type: "object", additionalProperties: { type: "number" } },
36
- allowedFilePrefixes: { type: "array", items: { type: "string" } },
37
- },
38
- },
39
- render: {
40
- type: "object",
41
- required: ["outputDir", "watchIntervalMs"],
42
- properties: {
43
- outputDir: { type: "string", minLength: 1 },
44
- watchIntervalMs: { type: "number", minimum: 1000 },
45
- },
46
- },
47
- updates: {
48
- type: "object",
49
- required: ["policy", "checkIntervalMs"],
50
- properties: {
51
- policy: { type: "string", enum: ["auto-all", "auto-compatible", "auto-patch", "notify", "manual"] },
52
- checkIntervalMs: { type: "number", minimum: 60_000 },
53
- },
54
- },
55
- budget: {
56
- type: "object",
57
- required: ["warnPercent"],
58
- properties: {
59
- warnPercent: { type: "number", minimum: 1, maximum: 100 },
60
- globalMonthlyCents: { type: "number", minimum: 0 },
61
- },
62
- },
63
- agents: {
64
- type: "array",
65
- items: {
66
- type: "object",
67
- required: ["slug", "name", "adapter"],
68
- properties: {
69
- slug: { type: "string", minLength: 1, pattern: "^[a-z0-9-]+$" },
70
- name: { type: "string", minLength: 1 },
71
- adapter: { type: "string", minLength: 1 },
72
- model: { type: "string" },
73
- workdir: { type: "string" },
74
- maxConcurrentRuns: { type: "number", minimum: 1 },
75
- budgetMonthlyCents: { type: "number", minimum: 0 },
76
- canCreateAgents: { type: "boolean" },
77
- skipPermissions: { type: "boolean" },
78
- },
79
- },
80
- },
81
- channels: {
82
- type: "object",
83
- additionalProperties: {
84
- type: "object",
85
- required: ["enabled"],
86
- properties: {
87
- enabled: { type: "boolean" },
88
- },
89
- },
90
- },
91
- providers: {
92
- type: "object",
93
- additionalProperties: {
94
- type: "object",
95
- required: ["enabled"],
96
- properties: {
97
- enabled: { type: "boolean" },
98
- },
99
- },
100
- },
101
- },
102
- };
103
- let _validate = null;
104
- function getValidator() {
105
- if (!_validate) {
106
- _validate = ajv.compile(BOT_CONFIG_SCHEMA);
107
- }
108
- return _validate;
109
- }
110
- export function validateConfig(config) {
111
- const validate = getValidator();
112
- const valid = validate(config);
113
- if (valid)
114
- return [];
115
- return (validate.errors ?? []).map(err => ({
116
- path: err.instancePath || "/",
117
- message: err.message ?? "invalid",
118
- }));
119
- }
@@ -1,14 +0,0 @@
1
- import type { DataStore } from "./data-store.js";
2
- /**
3
- * Define default entity context rendering for botinabox core tables.
4
- * Call after defineCoreTables() and before or after init().
5
- *
6
- * Renders:
7
- * - agents/ — per-agent context (AGENT.md, PROJECTS.md if agent_project exists)
8
- * - users/ — per-user context (USER.md) — protected
9
- * - skills/ — per-skill context (SKILL.md)
10
- *
11
- * Apps can override by calling db.defineEntityContext() with the same table name
12
- * BEFORE calling defineCoreEntityContexts().
13
- */
14
- export declare function defineCoreEntityContexts(db: DataStore): void;
@@ -1,197 +0,0 @@
1
- import { truncateAtWord } from "../../shared/utils.js";
2
- /**
3
- * Define default entity context rendering for botinabox core tables.
4
- * Call after defineCoreTables() and before or after init().
5
- *
6
- * Renders:
7
- * - agents/ — per-agent context (AGENT.md, PROJECTS.md if agent_project exists)
8
- * - users/ — per-user context (USER.md) — protected
9
- * - skills/ — per-skill context (SKILL.md)
10
- *
11
- * Apps can override by calling db.defineEntityContext() with the same table name
12
- * BEFORE calling defineCoreEntityContexts().
13
- */
14
- export function defineCoreEntityContexts(db) {
15
- // --- Agents ---
16
- db.defineEntityContext("agents", {
17
- table: "agents",
18
- directory: "agents",
19
- slugColumn: "slug",
20
- indexFile: "agents/AGENTS.md",
21
- files: {
22
- "AGENT.md": {
23
- source: { type: "self" },
24
- render: (rows) => {
25
- const a = rows[0];
26
- if (!a)
27
- return "";
28
- return [
29
- `# ${a.name}`,
30
- "",
31
- a.role ? `**Role:** ${a.role}` : null,
32
- a.adapter ? `**Adapter:** ${a.adapter}` : null,
33
- a.status ? `**Status:** ${a.status}` : null,
34
- a.cwd ? `**Working Directory:** ${a.cwd}` : null,
35
- a.reports_to ? `**Reports To:** ${a.reports_to}` : null,
36
- "",
37
- ]
38
- .filter(Boolean)
39
- .join("\n");
40
- },
41
- },
42
- "SKILLS.md": {
43
- source: {
44
- type: "manyToMany",
45
- junctionTable: "agent_skills",
46
- localKey: "agent_id",
47
- remoteKey: "skill_id",
48
- remoteTable: "skills",
49
- },
50
- omitIfEmpty: true,
51
- render: (rows) => {
52
- if (!rows.length)
53
- return "";
54
- const lines = [`# Skills (${rows.length})`, ""];
55
- for (const s of rows) {
56
- lines.push(`## ${s.name}`);
57
- if (s.category)
58
- lines.push(`**Category:** ${s.category}`);
59
- if (s.description)
60
- lines.push("", s.description);
61
- if (s.definition)
62
- lines.push("", "```", s.definition, "```");
63
- lines.push("");
64
- }
65
- return lines.join("\n");
66
- },
67
- },
68
- "PLAYBOOKS.md": {
69
- source: {
70
- type: "manyToMany",
71
- junctionTable: "agent_playbooks",
72
- localKey: "agent_id",
73
- remoteKey: "playbook_id",
74
- remoteTable: "playbooks",
75
- },
76
- omitIfEmpty: true,
77
- render: (rows) => {
78
- if (!rows.length)
79
- return "";
80
- const lines = [`# Playbooks (${rows.length})`, ""];
81
- for (const pb of rows) {
82
- lines.push(`## ${pb.pattern ?? pb.name ?? "Unnamed"}`);
83
- if (pb.rule)
84
- lines.push("", pb.rule);
85
- lines.push("");
86
- }
87
- return lines.join("\n");
88
- },
89
- },
90
- },
91
- });
92
- // --- Users (protected) ---
93
- db.defineEntityContext("users", {
94
- table: "users",
95
- directory: "users",
96
- slugColumn: "id",
97
- protected: true,
98
- indexFile: "users/USERS.md",
99
- files: {
100
- "USER.md": {
101
- source: { type: "self" },
102
- render: (rows) => {
103
- const u = rows[0];
104
- if (!u)
105
- return "";
106
- return [
107
- `# ${u.name}`,
108
- "",
109
- u.role ? `**Role:** ${u.role}` : null,
110
- u.title ? `**Title:** ${u.title}` : null,
111
- u.email ? `**Email:** ${u.email}` : null,
112
- u.timezone ? `**Timezone:** ${u.timezone}` : null,
113
- "",
114
- ]
115
- .filter(Boolean)
116
- .join("\n");
117
- },
118
- },
119
- },
120
- });
121
- // --- Skills ---
122
- db.defineEntityContext("skills", {
123
- table: "skills",
124
- directory: "skills",
125
- slugColumn: "slug",
126
- indexFile: "skills/SKILLS.md",
127
- files: {
128
- "SKILL.md": {
129
- source: { type: "self" },
130
- render: (rows) => {
131
- const s = rows[0];
132
- if (!s)
133
- return "";
134
- return [
135
- `# ${s.name}`,
136
- "",
137
- s.category ? `**Category:** ${s.category}` : null,
138
- s.description ? `\n${s.description}` : null,
139
- s.definition ? `\n## Definition\n\n${s.definition}` : null,
140
- "",
141
- ]
142
- .filter(Boolean)
143
- .join("\n");
144
- },
145
- },
146
- },
147
- });
148
- // --- Messages ---
149
- db.defineEntityContext("messages", {
150
- table: "messages",
151
- directory: "messages",
152
- slugColumn: "id",
153
- indexFile: "messages/MESSAGES.md",
154
- indexRender: (rows) => {
155
- const active = rows.filter((r) => r.deleted_at == null);
156
- if (!active.length)
157
- return "# Messages\n\nNo messages.\n";
158
- const recent = active.slice(-100);
159
- const lines = recent.map((r) => {
160
- const dir = r.direction === "outbound" ? "→" : "←";
161
- const who = r.from_agent ?? r.from_user ?? "unknown";
162
- const time = (r.created_at ?? "").slice(0, 16);
163
- const preview = truncateAtWord(r.body ?? "", 80);
164
- return `- ${dir} **${who}** (${time}): ${preview}`;
165
- });
166
- return `# Messages\n\nLast ${lines.length} messages:\n\n${lines.join("\n")}\n`;
167
- },
168
- files: {
169
- "MESSAGE.md": {
170
- source: { type: "self" },
171
- render: (rows) => {
172
- const m = rows[0];
173
- if (!m)
174
- return "";
175
- return [
176
- "# Message",
177
- "",
178
- `**Direction:** ${m.direction}`,
179
- m.from_user ? `**From User:** ${m.from_user}` : null,
180
- m.from_agent ? `**From Agent:** ${m.from_agent}` : null,
181
- `**Channel:** ${m.channel}`,
182
- m.thread_id ? `**Thread:** ${m.thread_id}` : null,
183
- m.task_id ? `**Task:** ${m.task_id}` : null,
184
- `**Time:** ${m.created_at}`,
185
- "",
186
- "---",
187
- "",
188
- m.body,
189
- "",
190
- ]
191
- .filter(Boolean)
192
- .join("\n");
193
- },
194
- },
195
- },
196
- });
197
- }
@@ -1,5 +0,0 @@
1
- /** Initial migration set for core tables */
2
- export declare const CORE_MIGRATIONS: Array<{
3
- version: string;
4
- sql: string;
5
- }>;