@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.
- package/dist/activity-tracker.d.ts +69 -0
- package/dist/activity-tracker.d.ts.map +1 -0
- package/dist/activity-tracker.js +155 -0
- package/dist/activity-tracker.js.map +1 -0
- package/dist/api-client.d.ts +94 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +145 -0
- package/dist/api-client.js.map +1 -0
- package/dist/config.d.ts +117 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +348 -0
- package/dist/config.js.map +1 -0
- package/dist/engine.d.ts +120 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +18 -0
- package/dist/engine.js.map +1 -0
- package/dist/escalation-types.d.ts +31 -0
- package/dist/escalation-types.d.ts.map +1 -0
- package/dist/escalation-types.js +24 -0
- package/dist/escalation-types.js.map +1 -0
- package/dist/event-logger.d.ts +13 -0
- package/dist/event-logger.d.ts.map +1 -0
- package/dist/event-logger.js +82 -0
- package/dist/event-logger.js.map +1 -0
- package/dist/git.d.ts +39 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +72 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +104 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +192 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/log-manager.d.ts +83 -0
- package/dist/log-manager.d.ts.map +1 -0
- package/dist/log-manager.js +217 -0
- package/dist/log-manager.js.map +1 -0
- package/dist/otel-env.d.ts +29 -0
- package/dist/otel-env.d.ts.map +1 -0
- package/dist/otel-env.js +44 -0
- package/dist/otel-env.js.map +1 -0
- package/dist/resilience.d.ts +127 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +300 -0
- package/dist/resilience.js.map +1 -0
- package/dist/resource-governor.d.ts +83 -0
- package/dist/resource-governor.d.ts.map +1 -0
- package/dist/resource-governor.js +184 -0
- package/dist/resource-governor.js.map +1 -0
- package/dist/spawn.d.ts +72 -0
- package/dist/spawn.d.ts.map +1 -0
- package/dist/spawn.js +82 -0
- package/dist/spawn.js.map +1 -0
- package/dist/stream-json.d.ts +885 -0
- package/dist/stream-json.d.ts.map +1 -0
- package/dist/stream-json.js +298 -0
- package/dist/stream-json.js.map +1 -0
- package/dist/token-usage.d.ts +67 -0
- package/dist/token-usage.d.ts.map +1 -0
- package/dist/token-usage.js +150 -0
- package/dist/token-usage.js.map +1 -0
- package/dist/transforms.d.ts +64 -0
- package/dist/transforms.d.ts.map +1 -0
- package/dist/transforms.js +78 -0
- package/dist/transforms.js.map +1 -0
- package/dist/unified-config.d.ts +62 -0
- package/dist/unified-config.d.ts.map +1 -0
- package/dist/unified-config.js +155 -0
- package/dist/unified-config.js.map +1 -0
- package/dist/workflow-types.d.ts +202 -0
- package/dist/workflow-types.d.ts.map +1 -0
- package/dist/workflow-types.js +15 -0
- package/dist/workflow-types.js.map +1 -0
- package/dist/worktree.d.ts +92 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +221 -0
- package/dist/worktree.js.map +1 -0
- 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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"}
|
package/dist/config.d.ts
ADDED
|
@@ -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"}
|