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,31 +0,0 @@
1
- import type { DataStore } from '../data/data-store.js';
2
- import type { HookBus } from '../hooks/hook-bus.js';
3
- import type { CircuitBreaker } from './circuit-breaker.js';
4
- export declare class RunManager {
5
- private db;
6
- private hooks;
7
- private config?;
8
- private locks;
9
- private orphanTimer;
10
- private readonly staleThresholdMs;
11
- private circuitBreaker?;
12
- constructor(db: DataStore, hooks: HookBus, config?: {
13
- staleThresholdMs?: number;
14
- maxBackoffMs?: number;
15
- } | undefined);
16
- /**
17
- * Attach a CircuitBreaker to prevent retries on broken agents.
18
- */
19
- setCircuitBreaker(cb: CircuitBreaker): void;
20
- isLocked(agentId: string): boolean;
21
- startRun(agentId: string, taskId: string, adapter?: string): Promise<string>;
22
- finishRun(runId: string, result: {
23
- exitCode: number;
24
- output?: string;
25
- costCents?: number;
26
- usage?: unknown;
27
- }): Promise<void>;
28
- reapOrphans(): Promise<void>;
29
- startOrphanReaper(intervalMs?: number): void;
30
- stopOrphanReaper(): void;
31
- }
@@ -1,178 +0,0 @@
1
- import { checkChainDepth, MAX_CHAIN_DEPTH } from './chain-guard.js';
2
- import { interpolate } from './template-interpolate.js';
3
- const DEFAULT_STALE_THRESHOLD_MS = 30 * 60 * 1000; // 30 minutes
4
- const BASE_BACKOFF_MS = 5_000;
5
- const DEFAULT_MAX_BACKOFF_MS = 5 * 60 * 1000; // 5 minutes
6
- export class RunManager {
7
- db;
8
- hooks;
9
- config;
10
- locks = new Map(); // agentId → runId
11
- orphanTimer = null;
12
- staleThresholdMs;
13
- circuitBreaker;
14
- constructor(db, hooks, config) {
15
- this.db = db;
16
- this.hooks = hooks;
17
- this.config = config;
18
- this.staleThresholdMs = config?.staleThresholdMs ?? DEFAULT_STALE_THRESHOLD_MS;
19
- }
20
- /**
21
- * Attach a CircuitBreaker to prevent retries on broken agents.
22
- */
23
- setCircuitBreaker(cb) {
24
- this.circuitBreaker = cb;
25
- }
26
- isLocked(agentId) {
27
- return this.locks.has(agentId);
28
- }
29
- async startRun(agentId, taskId, adapter) {
30
- if (this.locks.has(agentId)) {
31
- throw new Error(`Agent already has an active run`);
32
- }
33
- const row = await this.db.insert('runs', {
34
- agent_id: agentId,
35
- task_id: taskId,
36
- adapter: adapter,
37
- status: 'running',
38
- started_at: new Date().toISOString(),
39
- });
40
- const runId = row['id'];
41
- this.locks.set(agentId, runId);
42
- return runId;
43
- }
44
- async finishRun(runId, result) {
45
- const run = await this.db.get('runs', { id: runId });
46
- if (!run)
47
- throw new Error(`Run not found: ${runId}`);
48
- const succeeded = result.exitCode === 0;
49
- const status = succeeded ? 'succeeded' : 'failed';
50
- const usage = result.usage;
51
- await this.db.update('runs', { id: runId }, {
52
- status,
53
- completed_at: new Date().toISOString(),
54
- exit_code: result.exitCode,
55
- cost_cents: result.costCents ?? 0,
56
- input_tokens: usage?.['inputTokens'] ?? 0,
57
- output_tokens: usage?.['outputTokens'] ?? 0,
58
- error_message: result.exitCode !== 0 ? result.output : undefined,
59
- });
60
- // Release lock
61
- const agentId = run['agent_id'];
62
- this.locks.delete(agentId);
63
- const taskId = run['task_id'];
64
- if (!succeeded) {
65
- // Record failure in circuit breaker (if attached)
66
- if (this.circuitBreaker) {
67
- await this.circuitBreaker.recordFailure(agentId, result.output);
68
- }
69
- // Retry policy — skip retry if circuit breaker is open
70
- const task = await this.db.get('tasks', { id: taskId });
71
- if (task) {
72
- const retryCount = task['retry_count'] ?? 0;
73
- const maxRetries = task['max_retries'] ?? 0;
74
- const circuitOpen = this.circuitBreaker
75
- ? !this.circuitBreaker.canExecute(agentId)
76
- : false;
77
- if (retryCount < maxRetries && !circuitOpen) {
78
- // Exponential backoff: BASE_BACKOFF_MS * 2^retryCount
79
- const maxBackoff = this.config?.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;
80
- const backoffMs = Math.min(BASE_BACKOFF_MS * Math.pow(2, retryCount), maxBackoff);
81
- const nextRetryAt = new Date(Date.now() + backoffMs).toISOString();
82
- await this.db.update('tasks', { id: taskId }, {
83
- retry_count: retryCount + 1,
84
- next_retry_at: nextRetryAt,
85
- status: 'todo',
86
- execution_run_id: null,
87
- updated_at: new Date().toISOString(),
88
- });
89
- }
90
- else {
91
- // Retries exhausted or circuit open — mark task as failed
92
- await this.db.update('tasks', { id: taskId }, {
93
- status: 'failed',
94
- updated_at: new Date().toISOString(),
95
- });
96
- }
97
- }
98
- }
99
- else {
100
- // Record success in circuit breaker (if attached)
101
- if (this.circuitBreaker) {
102
- await this.circuitBreaker.recordSuccess(agentId);
103
- }
104
- // Mark task done with result before emitting run.completed,
105
- // so hook handlers can read task.result immediately.
106
- await this.db.update('tasks', { id: taskId }, {
107
- status: 'done',
108
- result: result.output,
109
- updated_at: new Date().toISOString(),
110
- });
111
- // Followup chain
112
- const task = await this.db.get('tasks', { id: taskId });
113
- if (task && task['followup_agent_id']) {
114
- const chainDepth = (task['chain_depth'] ?? 0) + 1;
115
- checkChainDepth(chainDepth, MAX_CHAIN_DEPTH);
116
- const followupAgentId = task['followup_agent_id'];
117
- const followupTemplate = task['followup_template'] ?? 'Followup: {{output}}';
118
- const context = { output: result.output ?? '' };
119
- const title = interpolate(followupTemplate, context);
120
- const chainOriginId = task['chain_origin_id'] ?? taskId;
121
- await this.db.insert('tasks', {
122
- title,
123
- description: title,
124
- assignee_id: followupAgentId,
125
- status: 'todo',
126
- priority: task['priority'] ?? 5,
127
- chain_depth: chainDepth,
128
- chain_origin_id: chainOriginId,
129
- });
130
- await this.hooks.emit('task.followup.created', {
131
- originTaskId: taskId,
132
- followupAgentId,
133
- chainDepth,
134
- });
135
- }
136
- }
137
- await this.hooks.emit('run.completed', {
138
- runId,
139
- agentId,
140
- taskId,
141
- status,
142
- exitCode: result.exitCode,
143
- });
144
- }
145
- async reapOrphans() {
146
- const cutoff = new Date(Date.now() - this.staleThresholdMs).toISOString();
147
- const staleRuns = (await this.db.query('runs', { where: { status: 'running' } }))
148
- .filter((r) => {
149
- const startedAt = r['started_at'];
150
- return startedAt != null && startedAt < cutoff;
151
- });
152
- for (const run of staleRuns) {
153
- await this.db.update('runs', { id: run['id'] }, {
154
- status: 'failed',
155
- completed_at: new Date().toISOString(),
156
- error_message: 'Orphaned run reaped by RunManager',
157
- });
158
- // Release in-memory lock if we hold it
159
- const agentId = run['agent_id'];
160
- if (this.locks.get(agentId) === run['id']) {
161
- this.locks.delete(agentId);
162
- }
163
- }
164
- }
165
- startOrphanReaper(intervalMs = 60_000) {
166
- if (this.orphanTimer)
167
- return;
168
- this.orphanTimer = setInterval(() => {
169
- void this.reapOrphans();
170
- }, intervalMs);
171
- }
172
- stopOrphanReaper() {
173
- if (this.orphanTimer) {
174
- clearInterval(this.orphanTimer);
175
- this.orphanTimer = null;
176
- }
177
- }
178
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * Scheduler — database-backed job scheduling with cron expressions.
3
- *
4
- * Supports one-time and recurring schedules. When a schedule fires,
5
- * it emits the schedule's `action` as a hook event with the
6
- * `action_config` payload. Consumers subscribe to handle the action.
7
- *
8
- * Supports one-time and recurring use cases.
9
- */
10
- import type { DataStore } from "../data/data-store.js";
11
- import type { HookBus } from "../hooks/hook-bus.js";
12
- export interface ScheduleDef {
13
- name: string;
14
- description?: string;
15
- /** Cron expression for recurring schedules */
16
- cron?: string;
17
- /** ISO 8601 datetime for one-time schedules */
18
- runAt?: string;
19
- /** Hook event name to emit when fired */
20
- action: string;
21
- /** JSON-serializable payload passed to the hook */
22
- actionConfig?: Record<string, unknown>;
23
- timezone?: string;
24
- }
25
- export interface Schedule {
26
- id: string;
27
- name: string;
28
- description: string | null;
29
- type: "one_time" | "recurring";
30
- cron: string | null;
31
- run_at: string | null;
32
- timezone: string;
33
- enabled: number;
34
- action: string;
35
- action_config: string;
36
- last_fired_at: string | null;
37
- next_fire_at: string | null;
38
- created_at: string;
39
- updated_at: string;
40
- deleted_at: string | null;
41
- }
42
- export declare class Scheduler {
43
- private db;
44
- private hooks;
45
- private timer;
46
- constructor(db: DataStore, hooks: HookBus);
47
- /**
48
- * Start the scheduler. Computes initial next_fire_at for schedules
49
- * that don't have one, then polls for due schedules.
50
- */
51
- start(pollIntervalMs?: number): Promise<void>;
52
- stop(): void;
53
- /** Check for and fire due schedules. */
54
- tick(): Promise<void>;
55
- /** Register a new schedule. */
56
- register(def: ScheduleDef): Promise<string>;
57
- /** Update an existing schedule. */
58
- update(id: string, changes: Partial<Pick<ScheduleDef, "name" | "cron" | "runAt" | "action" | "actionConfig" | "timezone" | "description">> & {
59
- enabled?: boolean;
60
- }): Promise<void>;
61
- /** Soft-delete a schedule. */
62
- unregister(id: string): Promise<void>;
63
- /** List schedules, optionally filtered. */
64
- list(filter?: {
65
- enabled?: boolean;
66
- action?: string;
67
- }): Promise<Schedule[]>;
68
- /** Compute next_fire_at for any enabled schedule missing it. */
69
- private initializeNextFireTimes;
70
- }
@@ -1,198 +0,0 @@
1
- /**
2
- * Scheduler — database-backed job scheduling with cron expressions.
3
- *
4
- * Supports one-time and recurring schedules. When a schedule fires,
5
- * it emits the schedule's `action` as a hook event with the
6
- * `action_config` payload. Consumers subscribe to handle the action.
7
- *
8
- * Supports one-time and recurring use cases.
9
- */
10
- import cronParser from "cron-parser";
11
- import { v4 as uuid } from "uuid";
12
- function computeNextFire(cron, timezone, after) {
13
- const interval = cronParser.parseExpression(cron, {
14
- currentDate: after ?? new Date(),
15
- tz: timezone,
16
- });
17
- return interval.next().toISOString();
18
- }
19
- export class Scheduler {
20
- db;
21
- hooks;
22
- timer = null;
23
- constructor(db, hooks) {
24
- this.db = db;
25
- this.hooks = hooks;
26
- }
27
- /**
28
- * Start the scheduler. Computes initial next_fire_at for schedules
29
- * that don't have one, then polls for due schedules.
30
- */
31
- async start(pollIntervalMs = 30_000) {
32
- await this.initializeNextFireTimes();
33
- this.timer = setInterval(() => {
34
- void this.tick();
35
- }, pollIntervalMs);
36
- // Fire immediately on start
37
- void this.tick();
38
- }
39
- stop() {
40
- if (this.timer) {
41
- clearInterval(this.timer);
42
- this.timer = null;
43
- }
44
- }
45
- /** Check for and fire due schedules. */
46
- async tick() {
47
- const now = new Date().toISOString();
48
- const schedules = (await this.db.query("schedules", {
49
- where: { enabled: 1 },
50
- })).filter((s) => s["deleted_at"] == null &&
51
- s["next_fire_at"] != null &&
52
- s["next_fire_at"] <= now);
53
- for (const schedule of schedules) {
54
- try {
55
- const config = JSON.parse(schedule.action_config || "{}");
56
- // Filter prototype pollution vectors
57
- const safeConfig = {};
58
- for (const [k, v] of Object.entries(config)) {
59
- if (!k.startsWith('__'))
60
- safeConfig[k] = v;
61
- }
62
- // Emit the action hook (e.g. 'connector.sync', 'channel.send')
63
- await this.hooks.emit(schedule.action, {
64
- schedule_id: schedule.id,
65
- schedule_name: schedule.name,
66
- ...safeConfig,
67
- });
68
- // Emit observability hook
69
- await this.hooks.emit("schedule.fired", {
70
- schedule_id: schedule.id,
71
- schedule_name: schedule.name,
72
- action: schedule.action,
73
- fired_at: now,
74
- });
75
- // Update last_fired_at and compute next
76
- if (schedule.type === "recurring" && schedule.cron) {
77
- const nextFire = computeNextFire(schedule.cron, schedule.timezone, new Date());
78
- await this.db.update("schedules", { id: schedule.id }, {
79
- last_fired_at: now,
80
- next_fire_at: nextFire,
81
- updated_at: now,
82
- });
83
- }
84
- else {
85
- // One-time: disable after firing
86
- await this.db.update("schedules", { id: schedule.id }, {
87
- last_fired_at: now,
88
- next_fire_at: null,
89
- enabled: 0,
90
- updated_at: now,
91
- });
92
- }
93
- }
94
- catch (err) {
95
- console.error(`[Scheduler] Error firing schedule "${schedule.name}":`, err);
96
- await this.hooks.emit("schedule.error", {
97
- schedule_id: schedule.id,
98
- schedule_name: schedule.name,
99
- error: String(err),
100
- });
101
- }
102
- }
103
- }
104
- /** Register a new schedule. */
105
- async register(def) {
106
- const id = uuid();
107
- const type = def.cron ? "recurring" : "one_time";
108
- const timezone = def.timezone ?? "UTC";
109
- let nextFire = null;
110
- if (def.cron) {
111
- nextFire = computeNextFire(def.cron, timezone);
112
- }
113
- else if (def.runAt) {
114
- nextFire = new Date(def.runAt).toISOString();
115
- }
116
- await this.db.insert("schedules", {
117
- id,
118
- name: def.name,
119
- description: def.description ?? null,
120
- type,
121
- cron: def.cron ?? null,
122
- run_at: def.runAt ?? null,
123
- timezone,
124
- enabled: 1,
125
- action: def.action,
126
- action_config: JSON.stringify(def.actionConfig ?? {}),
127
- next_fire_at: nextFire,
128
- });
129
- return id;
130
- }
131
- /** Update an existing schedule. */
132
- async update(id, changes) {
133
- const row = {
134
- updated_at: new Date().toISOString(),
135
- };
136
- if (changes.name !== undefined)
137
- row["name"] = changes.name;
138
- if (changes.description !== undefined)
139
- row["description"] = changes.description;
140
- if (changes.action !== undefined)
141
- row["action"] = changes.action;
142
- if (changes.actionConfig !== undefined)
143
- row["action_config"] = JSON.stringify(changes.actionConfig);
144
- if (changes.enabled !== undefined)
145
- row["enabled"] = changes.enabled ? 1 : 0;
146
- if (changes.cron !== undefined) {
147
- row["cron"] = changes.cron;
148
- row["type"] = "recurring";
149
- row["run_at"] = null;
150
- row["next_fire_at"] = computeNextFire(changes.cron, changes.timezone ?? "UTC");
151
- }
152
- else if (changes.runAt !== undefined) {
153
- row["run_at"] = changes.runAt;
154
- row["type"] = "one_time";
155
- row["cron"] = null;
156
- row["next_fire_at"] = new Date(changes.runAt).toISOString();
157
- }
158
- if (changes.timezone !== undefined)
159
- row["timezone"] = changes.timezone;
160
- await this.db.update("schedules", { id }, row);
161
- }
162
- /** Soft-delete a schedule. */
163
- async unregister(id) {
164
- await this.db.update("schedules", { id }, {
165
- enabled: 0,
166
- deleted_at: new Date().toISOString(),
167
- updated_at: new Date().toISOString(),
168
- });
169
- }
170
- /** List schedules, optionally filtered. */
171
- async list(filter) {
172
- const where = {};
173
- if (filter?.enabled !== undefined)
174
- where["enabled"] = filter.enabled ? 1 : 0;
175
- if (filter?.action !== undefined)
176
- where["action"] = filter.action;
177
- return (await this.db.query("schedules", { where })).filter((s) => s["deleted_at"] == null);
178
- }
179
- /** Compute next_fire_at for any enabled schedule missing it. */
180
- async initializeNextFireTimes() {
181
- const schedules = (await this.db.query("schedules", { where: { enabled: 1 } })).filter((s) => s["deleted_at"] == null && s["next_fire_at"] == null);
182
- for (const s of schedules) {
183
- let nextFire = null;
184
- if (s.type === "recurring" && s.cron) {
185
- nextFire = computeNextFire(s.cron, s.timezone);
186
- }
187
- else if (s.type === "one_time" && s.run_at) {
188
- nextFire = new Date(s.run_at).toISOString();
189
- }
190
- if (nextFire) {
191
- await this.db.update("schedules", { id: s.id }, {
192
- next_fire_at: nextFire,
193
- updated_at: new Date().toISOString(),
194
- });
195
- }
196
- }
197
- }
198
- }
@@ -1,57 +0,0 @@
1
- import type { DataStore } from "../data/data-store.js";
2
- import type { HookBus } from "../hooks/hook-bus.js";
3
- export interface SecretInput {
4
- name: string;
5
- type?: string;
6
- environment?: string;
7
- value?: string;
8
- location?: string;
9
- description?: string;
10
- rotation_schedule?: string;
11
- expires_at?: string;
12
- notes?: string;
13
- org_id?: string;
14
- }
15
- export interface SecretMeta {
16
- id: string;
17
- org_id: string | null;
18
- name: string;
19
- type: string;
20
- environment: string;
21
- location: string | null;
22
- description: string | null;
23
- rotation_schedule: string | null;
24
- expires_at: string | null;
25
- notes: string | null;
26
- created_at: string;
27
- updated_at: string;
28
- }
29
- export declare class SecretStore {
30
- private readonly db;
31
- private readonly hooks;
32
- private readonly encKey;
33
- /**
34
- * @param db - DataStore instance
35
- * @param hooks - HookBus instance
36
- * @param encryptionKey - Optional master key for encrypting secrets at rest.
37
- * When provided, all new secrets are encrypted with AES-256-GCM.
38
- * Existing plaintext secrets are read transparently (passthrough on decrypt).
39
- */
40
- constructor(db: DataStore, hooks: HookBus, encryptionKey?: string);
41
- set(input: SecretInput): Promise<SecretMeta>;
42
- get(name: string, environment?: string): Promise<string | null>;
43
- getMeta(name: string, environment?: string): Promise<SecretMeta | null>;
44
- list(): Promise<SecretMeta[]>;
45
- rotate(name: string, newValue: string, environment?: string): Promise<void>;
46
- delete(name: string, environment?: string): Promise<void>;
47
- /**
48
- * Load a sync cursor by key. Returns undefined if not found.
49
- * Cursors are stored as secrets with type='sync_cursor'.
50
- */
51
- loadCursor(key: string): Promise<string | undefined>;
52
- /**
53
- * Persist a sync cursor by key. Creates or updates the secret.
54
- */
55
- saveCursor(key: string, value: string): Promise<void>;
56
- private _toMeta;
57
- }