@telora/daemon-core 0.2.5

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 (81) hide show
  1. package/dist/activity-tracker.d.ts +69 -0
  2. package/dist/activity-tracker.d.ts.map +1 -0
  3. package/dist/activity-tracker.js +155 -0
  4. package/dist/activity-tracker.js.map +1 -0
  5. package/dist/api-client.d.ts +94 -0
  6. package/dist/api-client.d.ts.map +1 -0
  7. package/dist/api-client.js +145 -0
  8. package/dist/api-client.js.map +1 -0
  9. package/dist/config.d.ts +117 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +348 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/engine.d.ts +120 -0
  14. package/dist/engine.d.ts.map +1 -0
  15. package/dist/engine.js +18 -0
  16. package/dist/engine.js.map +1 -0
  17. package/dist/escalation-types.d.ts +31 -0
  18. package/dist/escalation-types.d.ts.map +1 -0
  19. package/dist/escalation-types.js +24 -0
  20. package/dist/escalation-types.js.map +1 -0
  21. package/dist/event-logger.d.ts +13 -0
  22. package/dist/event-logger.d.ts.map +1 -0
  23. package/dist/event-logger.js +82 -0
  24. package/dist/event-logger.js.map +1 -0
  25. package/dist/git.d.ts +39 -0
  26. package/dist/git.d.ts.map +1 -0
  27. package/dist/git.js +72 -0
  28. package/dist/git.js.map +1 -0
  29. package/dist/index.d.ts +20 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +36 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/lifecycle.d.ts +104 -0
  34. package/dist/lifecycle.d.ts.map +1 -0
  35. package/dist/lifecycle.js +192 -0
  36. package/dist/lifecycle.js.map +1 -0
  37. package/dist/log-manager.d.ts +83 -0
  38. package/dist/log-manager.d.ts.map +1 -0
  39. package/dist/log-manager.js +217 -0
  40. package/dist/log-manager.js.map +1 -0
  41. package/dist/otel-env.d.ts +29 -0
  42. package/dist/otel-env.d.ts.map +1 -0
  43. package/dist/otel-env.js +44 -0
  44. package/dist/otel-env.js.map +1 -0
  45. package/dist/resilience.d.ts +127 -0
  46. package/dist/resilience.d.ts.map +1 -0
  47. package/dist/resilience.js +300 -0
  48. package/dist/resilience.js.map +1 -0
  49. package/dist/resource-governor.d.ts +83 -0
  50. package/dist/resource-governor.d.ts.map +1 -0
  51. package/dist/resource-governor.js +184 -0
  52. package/dist/resource-governor.js.map +1 -0
  53. package/dist/spawn.d.ts +72 -0
  54. package/dist/spawn.d.ts.map +1 -0
  55. package/dist/spawn.js +82 -0
  56. package/dist/spawn.js.map +1 -0
  57. package/dist/stream-json.d.ts +885 -0
  58. package/dist/stream-json.d.ts.map +1 -0
  59. package/dist/stream-json.js +298 -0
  60. package/dist/stream-json.js.map +1 -0
  61. package/dist/token-usage.d.ts +67 -0
  62. package/dist/token-usage.d.ts.map +1 -0
  63. package/dist/token-usage.js +150 -0
  64. package/dist/token-usage.js.map +1 -0
  65. package/dist/transforms.d.ts +64 -0
  66. package/dist/transforms.d.ts.map +1 -0
  67. package/dist/transforms.js +78 -0
  68. package/dist/transforms.js.map +1 -0
  69. package/dist/unified-config.d.ts +62 -0
  70. package/dist/unified-config.d.ts.map +1 -0
  71. package/dist/unified-config.js +155 -0
  72. package/dist/unified-config.js.map +1 -0
  73. package/dist/workflow-types.d.ts +202 -0
  74. package/dist/workflow-types.d.ts.map +1 -0
  75. package/dist/workflow-types.js +15 -0
  76. package/dist/workflow-types.js.map +1 -0
  77. package/dist/worktree.d.ts +92 -0
  78. package/dist/worktree.d.ts.map +1 -0
  79. package/dist/worktree.js +221 -0
  80. package/dist/worktree.js.map +1 -0
  81. package/package.json +57 -0
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Activity tracker -- writes activity snapshots via a configurable flush callback.
3
+ *
4
+ * Maintains a local snapshot of what the agent is currently doing and flushes
5
+ * it via the provided callback. Uses dirty-checking (JSON.stringify comparison)
6
+ * to avoid redundant calls.
7
+ *
8
+ * Designed to be attached to a StreamJsonParser for a single agent session.
9
+ * Every flush is wrapped in try/catch -- a failed activity write must NEVER
10
+ * crash the process.
11
+ */
12
+ import type { StreamJsonParser } from './stream-json.js';
13
+ export interface ActivitySnapshot {
14
+ /** Name of the tool currently being invoked (e.g. "Edit", "Bash", "Read"). */
15
+ currentTool: string | null;
16
+ /** File path extracted from tool input, if any. */
17
+ currentFile: string | null;
18
+ /** Last text output from the assistant, truncated to 200 chars. */
19
+ lastText: string | null;
20
+ /** Number of completed turns (result events). */
21
+ turnCount: number;
22
+ /** Cumulative input + output tokens. */
23
+ totalTokens: number;
24
+ /** Cumulative cost in USD. */
25
+ totalCostUsd: number;
26
+ /** ISO timestamp of the last flush. */
27
+ updatedAt: string;
28
+ }
29
+ export declare class ActivityTracker {
30
+ private sessionId;
31
+ private snapshot;
32
+ private lastFlushedJson;
33
+ private flushInProgress;
34
+ private onNarrationCallback;
35
+ private flushCallback;
36
+ constructor(sessionId: string, flushCallback: (snapshot: ActivitySnapshot) => Promise<void>);
37
+ /**
38
+ * Set a callback for narration updates (called when lastText changes).
39
+ */
40
+ onNarration(callback: (text: string) => void): void;
41
+ /**
42
+ * Attach the tracker to a StreamJsonParser.
43
+ * Listens for assistant messages and result events.
44
+ */
45
+ attach(parser: StreamJsonParser): void;
46
+ /**
47
+ * Process an assistant message.
48
+ * - tool_use blocks: update currentTool/currentFile and flush immediately.
49
+ * - text blocks: update lastText (dirty, no immediate flush).
50
+ */
51
+ private handleAssistantMessage;
52
+ /**
53
+ * Process a result event.
54
+ * Increments turn count, updates token/cost totals, flushes.
55
+ */
56
+ private handleResult;
57
+ /**
58
+ * Final flush -- called when the session ends.
59
+ * Clears transient fields and writes one last snapshot.
60
+ */
61
+ finalFlush(): Promise<void>;
62
+ /**
63
+ * Write the current snapshot via the flush callback if it has changed.
64
+ * Dirty-checking via JSON.stringify comparison.
65
+ * Wrapped in try/catch -- failures are logged but never thrown.
66
+ */
67
+ private flush;
68
+ }
69
+ //# sourceMappingURL=activity-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-tracker.d.ts","sourceRoot":"","sources":["../src/activity-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAyE,MAAM,kBAAkB,CAAC;AAIhI,MAAM,WAAW,gBAAgB;IAC/B,8EAA8E;IAC9E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mDAAmD;IACnD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB;AA8BD,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,mBAAmB,CAAyC;IACpE,OAAO,CAAC,aAAa,CAAgD;gBAGnE,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC;IAe9D;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI;IAInD;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAUtC;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAwB9B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAiBpB;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;;;OAIG;YACW,KAAK;CAwBpB"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Activity tracker -- writes activity snapshots via a configurable flush callback.
3
+ *
4
+ * Maintains a local snapshot of what the agent is currently doing and flushes
5
+ * it via the provided callback. Uses dirty-checking (JSON.stringify comparison)
6
+ * to avoid redundant calls.
7
+ *
8
+ * Designed to be attached to a StreamJsonParser for a single agent session.
9
+ * Every flush is wrapped in try/catch -- a failed activity write must NEVER
10
+ * crash the process.
11
+ */
12
+ // -- File path extraction -----------------------------------------------------
13
+ /** Keys in tool input that commonly contain file paths. */
14
+ const FILE_PATH_KEYS = ['file_path', 'path', 'command', 'notebook_path'];
15
+ /**
16
+ * Extract a file path from tool input, if present.
17
+ * Checks common keys first, then falls back to scanning string values
18
+ * that look like absolute paths.
19
+ */
20
+ function extractFilePath(input) {
21
+ // Check well-known keys first
22
+ for (const key of FILE_PATH_KEYS) {
23
+ const val = input[key];
24
+ if (typeof val === 'string' && val.length > 0) {
25
+ // For 'command' key, try to extract a path from the command string
26
+ if (key === 'command') {
27
+ const pathMatch = val.match(/(?:^|\s)(\/[^\s'"]+)/);
28
+ return pathMatch ? pathMatch[1] : null;
29
+ }
30
+ return val;
31
+ }
32
+ }
33
+ return null;
34
+ }
35
+ // -- Tracker class ------------------------------------------------------------
36
+ export class ActivityTracker {
37
+ sessionId;
38
+ snapshot;
39
+ lastFlushedJson = '';
40
+ flushInProgress = false;
41
+ onNarrationCallback = null;
42
+ flushCallback;
43
+ constructor(sessionId, flushCallback) {
44
+ this.sessionId = sessionId;
45
+ this.flushCallback = flushCallback;
46
+ this.snapshot = {
47
+ currentTool: null,
48
+ currentFile: null,
49
+ lastText: null,
50
+ turnCount: 0,
51
+ totalTokens: 0,
52
+ totalCostUsd: 0,
53
+ updatedAt: new Date().toISOString(),
54
+ };
55
+ }
56
+ /**
57
+ * Set a callback for narration updates (called when lastText changes).
58
+ */
59
+ onNarration(callback) {
60
+ this.onNarrationCallback = callback;
61
+ }
62
+ /**
63
+ * Attach the tracker to a StreamJsonParser.
64
+ * Listens for assistant messages and result events.
65
+ */
66
+ attach(parser) {
67
+ parser.on('assistant', (msg) => {
68
+ this.handleAssistantMessage(msg);
69
+ });
70
+ parser.on('result', (result) => {
71
+ this.handleResult(result);
72
+ });
73
+ }
74
+ /**
75
+ * Process an assistant message.
76
+ * - tool_use blocks: update currentTool/currentFile and flush immediately.
77
+ * - text blocks: update lastText (dirty, no immediate flush).
78
+ */
79
+ handleAssistantMessage(msg) {
80
+ let hasToolUse = false;
81
+ for (const block of msg.message.content) {
82
+ if (block.type === 'tool_use') {
83
+ const toolBlock = block;
84
+ this.snapshot.currentTool = toolBlock.name;
85
+ this.snapshot.currentFile = extractFilePath(toolBlock.input);
86
+ hasToolUse = true;
87
+ }
88
+ else if (block.type === 'text') {
89
+ const textBlock = block;
90
+ if (textBlock.text.length > 0) {
91
+ this.snapshot.lastText = textBlock.text.slice(0, 200);
92
+ this.onNarrationCallback?.(this.snapshot.lastText);
93
+ }
94
+ }
95
+ }
96
+ // Flush immediately on tool_use to show real-time activity
97
+ if (hasToolUse) {
98
+ this.flush();
99
+ }
100
+ }
101
+ /**
102
+ * Process a result event.
103
+ * Increments turn count, updates token/cost totals, flushes.
104
+ */
105
+ handleResult(result) {
106
+ this.snapshot.turnCount++;
107
+ if (result.usage) {
108
+ this.snapshot.totalTokens += (result.usage.input_tokens ?? 0) + (result.usage.output_tokens ?? 0);
109
+ }
110
+ if (result.total_cost_usd) {
111
+ this.snapshot.totalCostUsd += result.total_cost_usd;
112
+ }
113
+ // Clear current tool/file since the turn is complete
114
+ this.snapshot.currentTool = null;
115
+ this.snapshot.currentFile = null;
116
+ this.flush();
117
+ }
118
+ /**
119
+ * Final flush -- called when the session ends.
120
+ * Clears transient fields and writes one last snapshot.
121
+ */
122
+ async finalFlush() {
123
+ this.snapshot.currentTool = null;
124
+ this.snapshot.currentFile = null;
125
+ await this.flush();
126
+ }
127
+ /**
128
+ * Write the current snapshot via the flush callback if it has changed.
129
+ * Dirty-checking via JSON.stringify comparison.
130
+ * Wrapped in try/catch -- failures are logged but never thrown.
131
+ */
132
+ async flush() {
133
+ // Avoid concurrent flushes stacking up
134
+ if (this.flushInProgress)
135
+ return;
136
+ this.snapshot.updatedAt = new Date().toISOString();
137
+ const json = JSON.stringify(this.snapshot);
138
+ // Skip if nothing changed
139
+ if (json === this.lastFlushedJson)
140
+ return;
141
+ this.flushInProgress = true;
142
+ try {
143
+ await this.flushCallback(this.snapshot);
144
+ this.lastFlushedJson = json;
145
+ }
146
+ catch (err) {
147
+ // Activity writes must NEVER crash the process
148
+ console.warn(`[activity-tracker] Failed to flush activity for session ${this.sessionId}:`, err.message);
149
+ }
150
+ finally {
151
+ this.flushInProgress = false;
152
+ }
153
+ }
154
+ }
155
+ //# sourceMappingURL=activity-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-tracker.js","sourceRoot":"","sources":["../src/activity-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Shared API client infrastructure for Telora engines.
3
+ *
4
+ * Provides a factory function that creates an API client bound to a config
5
+ * and a set of per-concern circuit breakers. Both the daemon and factory
6
+ * engines use this to communicate with the product-api edge function.
7
+ *
8
+ * The action-to-concern circuit breaker mapping stays engine-specific
9
+ * (daemon has 4 concerns, factory has 3). This module provides the
10
+ * factory function; each engine provides its own concern mapping.
11
+ */
12
+ import type { z } from 'zod';
13
+ import { CircuitBreaker } from './resilience.js';
14
+ /**
15
+ * Minimal configuration required by the API client.
16
+ *
17
+ * Both DaemonConfig and FactoryConfig are supersets of this interface --
18
+ * they include additional engine-specific fields (repoPath, worktreeDir, etc.)
19
+ * but the API client only needs the Telora URL and tracker ID.
20
+ */
21
+ export interface BaseApiConfig {
22
+ /** Base URL of the Telora instance (e.g., http://127.0.0.1:54321). */
23
+ teloraUrl: string;
24
+ /** Tracker ID used as the Bearer token for API authentication. */
25
+ trackerId: string;
26
+ }
27
+ /**
28
+ * The API client returned by `createApiClient`.
29
+ *
30
+ * Provides four methods:
31
+ * - `callApi`: retry + circuit breaker protected API call
32
+ * - `callApiValidated`: same as callApi but validates response with Zod
33
+ * - `callApiOnce`: single-attempt API call (no retry, no circuit breaker)
34
+ * - `validateTrackerAuth`: lightweight auth check at startup
35
+ */
36
+ export interface ApiClient {
37
+ /**
38
+ * Call the product-api edge function with retry and circuit breaker protection.
39
+ *
40
+ * The action string is mapped to a circuit breaker concern via the
41
+ * engine-specific `actionToConcern` function provided at creation time.
42
+ */
43
+ callApi<T>(action: string, params?: Record<string, unknown>): Promise<T>;
44
+ /**
45
+ * Call the product-api edge function with retry, circuit breaker,
46
+ * and Zod schema validation on the response.
47
+ *
48
+ * On validation failure, throws an error with the action name and Zod issue details.
49
+ */
50
+ callApiValidated<T>(action: string, schema: z.ZodType<T>, params?: Record<string, unknown>): Promise<T>;
51
+ /**
52
+ * Single attempt to call the product-api edge function.
53
+ * No retry logic, no circuit breaker -- used directly when the caller
54
+ * manages its own retry/resilience strategy.
55
+ *
56
+ * Throws ApiError with retryability classification on failure.
57
+ */
58
+ callApiOnce<T>(action: string, params?: Record<string, unknown>): Promise<T>;
59
+ /**
60
+ * Validate the configured tracker auth by calling a lightweight API endpoint.
61
+ * Should be called at engine startup before starting any polling loops.
62
+ * Throws immediately with a clear error message if auth is invalid.
63
+ */
64
+ validateTrackerAuth(): Promise<void>;
65
+ }
66
+ /**
67
+ * Create an API client bound to a config and circuit breaker topology.
68
+ *
69
+ * @param config - Base API config with teloraUrl and trackerId
70
+ * @param breakerMap - Map of concern names to CircuitBreaker instances.
71
+ * Each engine creates its own breakers with appropriate thresholds.
72
+ * @param actionToConcern - Function that maps an API action name to a
73
+ * circuit breaker concern key. Must always return a valid key in breakerMap
74
+ * (the engine provides fallback logic).
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * // In daemon:
79
+ * const breakers = {
80
+ * heartbeat: new CircuitBreaker({ ... }),
81
+ * polling: new CircuitBreaker({ ... }),
82
+ * activity: new CircuitBreaker({ ... }),
83
+ * delivery: new CircuitBreaker({ ... }),
84
+ * };
85
+ *
86
+ * const client = createApiClient(
87
+ * daemonConfig,
88
+ * breakers,
89
+ * (action) => actionMap[action] ?? 'delivery',
90
+ * );
91
+ * ```
92
+ */
93
+ export declare function createApiClient(config: BaseApiConfig, breakerMap: Record<string, CircuitBreaker>, actionToConcern: (action: string) => string): ApiClient;
94
+ //# sourceMappingURL=api-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,EAA2C,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAM1F;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;OAKG;IACH,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAEzE;;;;;OAKG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAExG;;;;;;OAMG;IACH,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE7E;;;;OAIG;IACH,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,EACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,EAC1C,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC1C,SAAS,CA2IX"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Shared API client infrastructure for Telora engines.
3
+ *
4
+ * Provides a factory function that creates an API client bound to a config
5
+ * and a set of per-concern circuit breakers. Both the daemon and factory
6
+ * engines use this to communicate with the product-api edge function.
7
+ *
8
+ * The action-to-concern circuit breaker mapping stays engine-specific
9
+ * (daemon has 4 concerns, factory has 3). This module provides the
10
+ * factory function; each engine provides its own concern mapping.
11
+ */
12
+ import { withRetry, ApiError, classifyHttpStatus } from './resilience.js';
13
+ // ---------------------------------------------------------------------------
14
+ // Factory function
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * Create an API client bound to a config and circuit breaker topology.
18
+ *
19
+ * @param config - Base API config with teloraUrl and trackerId
20
+ * @param breakerMap - Map of concern names to CircuitBreaker instances.
21
+ * Each engine creates its own breakers with appropriate thresholds.
22
+ * @param actionToConcern - Function that maps an API action name to a
23
+ * circuit breaker concern key. Must always return a valid key in breakerMap
24
+ * (the engine provides fallback logic).
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * // In daemon:
29
+ * const breakers = {
30
+ * heartbeat: new CircuitBreaker({ ... }),
31
+ * polling: new CircuitBreaker({ ... }),
32
+ * activity: new CircuitBreaker({ ... }),
33
+ * delivery: new CircuitBreaker({ ... }),
34
+ * };
35
+ *
36
+ * const client = createApiClient(
37
+ * daemonConfig,
38
+ * breakers,
39
+ * (action) => actionMap[action] ?? 'delivery',
40
+ * );
41
+ * ```
42
+ */
43
+ export function createApiClient(config, breakerMap, actionToConcern) {
44
+ /**
45
+ * Resolve the circuit breaker for a given API action.
46
+ */
47
+ function getCircuitBreakerForAction(action) {
48
+ const concern = actionToConcern(action);
49
+ return breakerMap[concern];
50
+ }
51
+ /**
52
+ * Single attempt to call the product-api edge function.
53
+ * Throws ApiError with retryability classification.
54
+ */
55
+ async function callApiOnceImpl(action, params = {}) {
56
+ const url = `${config.teloraUrl}/functions/v1/product-api`;
57
+ let response;
58
+ try {
59
+ response = await fetch(url, {
60
+ method: 'POST',
61
+ headers: {
62
+ Authorization: `Bearer ${config.trackerId}`,
63
+ 'Content-Type': 'application/json',
64
+ },
65
+ body: JSON.stringify({ action, ...params }),
66
+ });
67
+ }
68
+ catch (error) {
69
+ // Network-level errors (ECONNRESET, timeout, etc.) -- always retryable
70
+ throw Object.assign(error, { isRetryable: true });
71
+ }
72
+ const data = (await response.json());
73
+ if (!response.ok || !data.success) {
74
+ const classification = classifyHttpStatus(response.status);
75
+ throw new ApiError(data.error || `API error (${response.status})`, response.status, classification === 'retryable');
76
+ }
77
+ return data;
78
+ }
79
+ /**
80
+ * Call the product-api edge function with tracker authentication.
81
+ * Includes retry with exponential backoff and circuit breaker protection.
82
+ */
83
+ async function callApiImpl(action, params = {}) {
84
+ const breaker = getCircuitBreakerForAction(action);
85
+ return breaker.execute(() => withRetry(() => callApiOnceImpl(action, params), { maxAttempts: 3, baseDelayMs: 1000, label: `callApi(${action})` }));
86
+ }
87
+ /**
88
+ * Call the product-api edge function and validate the response with a Zod schema.
89
+ *
90
+ * On validation failure, throws an error with the action name and Zod issue details.
91
+ * The existing retry/circuit breaker catches the thrown error.
92
+ */
93
+ async function callApiValidatedImpl(action, schema, params = {}) {
94
+ const raw = await callApiImpl(action, params);
95
+ const result = schema.safeParse(raw);
96
+ if (!result.success) {
97
+ const issues = result.error.issues
98
+ .map((i) => `${i.path.join('.')}: ${i.message}`)
99
+ .join('; ');
100
+ throw new Error(`API response validation failed for ${action}: ${issues}`);
101
+ }
102
+ return result.data;
103
+ }
104
+ /**
105
+ * Validate the configured tracker auth by calling a lightweight API endpoint.
106
+ * Should be called at engine startup before starting any polling loops.
107
+ * Throws immediately with a clear error message if auth is invalid.
108
+ */
109
+ async function validateTrackerAuthImpl() {
110
+ const url = `${config.teloraUrl}/functions/v1/product-api`;
111
+ let response;
112
+ try {
113
+ response = await fetch(url, {
114
+ method: 'POST',
115
+ headers: {
116
+ Authorization: `Bearer ${config.trackerId}`,
117
+ 'Content-Type': 'application/json',
118
+ },
119
+ body: JSON.stringify({ action: 'daemon_heartbeat_ping' }),
120
+ });
121
+ }
122
+ catch (error) {
123
+ throw new Error(`Cannot reach Telora API at ${config.teloraUrl}: ${error.message}. ` +
124
+ `Check TELORA_URL and network connectivity.`);
125
+ }
126
+ if (response.status === 401 || response.status === 403) {
127
+ throw new Error(`Tracker authentication failed (HTTP ${response.status}). ` +
128
+ `The configured TELORA_TRACKER_ID may be invalid, expired, or revoked. ` +
129
+ `Check your tracker in Telora Settings > AI Work Trackers.`);
130
+ }
131
+ // Any other non-server error is also a problem at startup
132
+ // (but 404 for the ping action is fine -- it means auth passed but action doesn't exist)
133
+ if (response.status >= 500) {
134
+ throw new Error(`Telora API returned server error (HTTP ${response.status}) during auth validation. ` +
135
+ `The service may be temporarily unavailable. Retry in a few minutes.`);
136
+ }
137
+ }
138
+ return {
139
+ callApi: callApiImpl,
140
+ callApiValidated: callApiValidatedImpl,
141
+ callApiOnce: callApiOnceImpl,
142
+ validateTrackerAuth: validateTrackerAuthImpl,
143
+ };
144
+ }
145
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Shared configuration infrastructure for Telora daemon and factory engines.
3
+ *
4
+ * Provides:
5
+ * - BaseConfig interface with fields common to both DaemonConfig and FactoryConfig
6
+ * - Generic config file loader (JSON from disk)
7
+ * - Base config resolver (env vars over file config)
8
+ * - Base config validator (collects errors without throwing)
9
+ *
10
+ * Each engine imports these and layers its own fields on top.
11
+ */
12
+ /** Regex for UUID v1-v8 (loose check). */
13
+ export declare const UUID_REGEX: RegExp;
14
+ /**
15
+ * A single product entry in the multi-product configuration.
16
+ * Each entry scopes the daemon to one product + git repository.
17
+ */
18
+ export interface ProductEntry {
19
+ /** Product UUID from Telora. */
20
+ id: string;
21
+ /** Absolute path to the product's git repository. */
22
+ repoPath: string;
23
+ }
24
+ /**
25
+ * Derive a short human-readable label for a product entry.
26
+ * Uses the basename of the product's repoPath (e.g., "/home/user/repos/telora" → "telora").
27
+ * Falls back to an 8-char ID slice if repoPath is empty.
28
+ */
29
+ export declare function productLabel(product: ProductEntry): string;
30
+ /**
31
+ * Configuration fields shared by both DaemonConfig and FactoryConfig.
32
+ *
33
+ * These are the fields that appear in both engine configs with compatible
34
+ * types and semantics. Engine-specific fields (e.g. worktreeDir, integrationBranch,
35
+ * factoryWorktreeDir, maxConcurrentInstances) belong in each engine's own config.
36
+ */
37
+ export interface BaseConfig {
38
+ /** Telora API base URL (e.g. http://127.0.0.1:54321). */
39
+ teloraUrl: string;
40
+ /** Tracker ID for authentication. */
41
+ trackerId: string;
42
+ /** Organization UUID. */
43
+ organizationId: string;
44
+ /**
45
+ * Product UUID -- scopes this engine to a single product.
46
+ * @deprecated Use `products` array for multi-product support. Kept for
47
+ * backward compatibility and env-var override (TELORA_PRODUCT_ID).
48
+ * When `products` is set, this is the ID of the first product.
49
+ */
50
+ productId: string;
51
+ /**
52
+ * Absolute path to the git repository.
53
+ * @deprecated Use `products` array for multi-product support. Kept for
54
+ * backward compatibility and env-var override (TELORA_REPO_PATH).
55
+ * When `products` is set, this is the repoPath of the first product.
56
+ */
57
+ repoPath: string;
58
+ /**
59
+ * Multi-product configuration. Each entry maps a product UUID to a git
60
+ * repository path. The daemon iterates all products for polling and execution.
61
+ * Always populated at runtime -- single-product configs are normalized to
62
+ * a single-entry array.
63
+ */
64
+ products: ProductEntry[];
65
+ /** Path (or command name) for the Claude Code executable. */
66
+ claudeCodePath: string;
67
+ /** Directory for log files. */
68
+ logDir: string;
69
+ /** Session timeout in milliseconds. */
70
+ sessionTimeoutMs: number;
71
+ /** Optional path to MCP config file, or null if unset. */
72
+ mcpConfigPath: string | null;
73
+ }
74
+ /**
75
+ * Load a JSON config file from disk.
76
+ *
77
+ * Search order (when no explicit configPath):
78
+ * 1. ~/.telora/{defaultFilename} (global config, multi-product)
79
+ * 2. .telora/{defaultFilename} in cwd (repo-local, legacy)
80
+ *
81
+ * @param configPath Explicit path to a config file, or undefined to use defaults.
82
+ * @param defaultFilename Filename to look for inside `.telora/` (e.g. `daemon.json`).
83
+ * @returns Parsed JSON object, or an empty object if no config file is found.
84
+ * @throws If an explicit configPath is provided but the file does not exist,
85
+ * or if the file cannot be parsed as JSON.
86
+ */
87
+ export declare function loadConfigFile(configPath: string | undefined, defaultFilename: string): Record<string, unknown>;
88
+ /**
89
+ * Resolve BaseConfig fields from a combination of file config and environment
90
+ * variables. Environment variables take priority over file config values.
91
+ *
92
+ * Returns a Partial<BaseConfig> so each engine can merge it with its own
93
+ * engine-specific fields. Fields that are not set in either source are omitted.
94
+ *
95
+ * Multi-product resolution:
96
+ * 1. If `products` array exists in config file, use it directly
97
+ * 2. If TELORA_PRODUCT_ID + TELORA_REPO_PATH env vars are set, they produce
98
+ * a single-entry products array (useful for CI/testing)
99
+ * 3. If only legacy `productId` + `repoPath` in config, normalize to products array
100
+ * 4. `productId` and `repoPath` on the result always reflect the first product
101
+ *
102
+ * @param fileConfig Parsed JSON from the config file (keys are camelCase field names).
103
+ * @param envOverrides Environment variables -- typically pass `process.env`.
104
+ */
105
+ export declare function resolveBaseConfig(fileConfig: Record<string, unknown>, envOverrides: Record<string, string | undefined>): Partial<BaseConfig>;
106
+ /**
107
+ * Validate the shared BaseConfig fields.
108
+ *
109
+ * Returns an array of human-readable error messages (never throws).
110
+ * Engines should call this, then append their own engine-specific validation
111
+ * errors before deciding whether to throw.
112
+ *
113
+ * @param config Partial base config to validate. Missing required fields
114
+ * are reported as errors.
115
+ */
116
+ export declare function validateBaseConfig(config: Partial<BaseConfig>): string[];
117
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,0CAA0C;AAC1C,eAAO,MAAM,UAAU,QAAoE,CAAC;AAM5F;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAM1D;AAMD;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,6DAA6D;IAC7D,cAAc,EAAE,MAAM,CAAC;IACvB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,gBAAgB,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,eAAe,EAAE,MAAM,GACtB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgCzB;AA+FD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC/C,OAAO,CAAC,UAAU,CAAC,CAqDrB;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,MAAM,EAAE,CA2ExE"}