@exaudeus/workrail 3.25.0 → 3.26.1
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/cli/commands/index.d.ts +5 -0
- package/dist/cli/commands/index.js +12 -1
- package/dist/cli/commands/worktrain-await.d.ts +35 -0
- package/dist/cli/commands/worktrain-await.js +207 -0
- package/dist/cli/commands/worktrain-inbox.d.ts +23 -0
- package/dist/cli/commands/worktrain-inbox.js +82 -0
- package/dist/cli/commands/worktrain-init.d.ts +23 -0
- package/dist/cli/commands/worktrain-init.js +338 -0
- package/dist/cli/commands/worktrain-spawn.d.ts +28 -0
- package/dist/cli/commands/worktrain-spawn.js +106 -0
- package/dist/cli/commands/worktrain-tell.d.ts +25 -0
- package/dist/cli/commands/worktrain-tell.js +32 -0
- package/dist/cli-worktrain.d.ts +2 -0
- package/dist/cli-worktrain.js +169 -0
- package/dist/cli.js +13 -3
- package/dist/config/config-file.d.ts +2 -0
- package/dist/config/config-file.js +55 -0
- package/dist/daemon/agent-loop.d.ts +90 -0
- package/dist/daemon/agent-loop.js +214 -0
- package/dist/daemon/pi-mono-loader.d.ts +0 -5
- package/dist/daemon/pi-mono-loader.js +0 -64
- package/dist/daemon/soul-template.d.ts +2 -0
- package/dist/daemon/soul-template.js +22 -0
- package/dist/daemon/workflow-runner.d.ts +24 -2
- package/dist/daemon/workflow-runner.js +244 -120
- package/dist/manifest.json +147 -51
- package/dist/mcp/output-schemas.d.ts +154 -154
- package/dist/mcp/transports/bridge-entry.js +20 -2
- package/dist/mcp/transports/bridge-events.d.ts +34 -0
- package/dist/mcp/transports/bridge-events.js +24 -0
- package/dist/mcp/transports/fatal-exit.d.ts +5 -0
- package/dist/mcp/transports/fatal-exit.js +82 -0
- package/dist/mcp/transports/http-entry.js +3 -0
- package/dist/mcp/transports/stdio-entry.js +3 -7
- package/dist/mcp/v2/tools.d.ts +7 -7
- package/dist/trigger/delivery-action.d.ts +37 -0
- package/dist/trigger/delivery-action.js +204 -0
- package/dist/trigger/delivery-client.d.ts +11 -0
- package/dist/trigger/delivery-client.js +27 -0
- package/dist/trigger/trigger-listener.d.ts +2 -0
- package/dist/trigger/trigger-listener.js +12 -2
- package/dist/trigger/trigger-router.d.ts +8 -2
- package/dist/trigger/trigger-router.js +164 -6
- package/dist/trigger/trigger-store.d.ts +11 -3
- package/dist/trigger/trigger-store.js +254 -13
- package/dist/trigger/types.d.ts +24 -0
- package/dist/trigger/types.js +4 -0
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.d.ts +22 -22
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.d.ts +114 -114
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +454 -454
- package/dist/v2/durable-core/schemas/session/blockers.d.ts +14 -14
- package/dist/v2/durable-core/schemas/session/events.d.ts +93 -93
- package/dist/v2/durable-core/schemas/session/gaps.d.ts +2 -2
- package/dist/v2/durable-core/schemas/session/validation-event.d.ts +4 -4
- package/dist/v2/usecases/console-routes.js +33 -3
- package/package.json +6 -4
- package/spec/workflow-tags.json +1 -0
- package/workflows/classify-task-workflow.json +68 -0
- package/workflows/coding-task-workflow-agentic.lean.v2.json +43 -13
|
@@ -43,6 +43,7 @@ const express_1 = __importDefault(require("express"));
|
|
|
43
43
|
const http = __importStar(require("node:http"));
|
|
44
44
|
const trigger_store_js_1 = require("./trigger-store.js");
|
|
45
45
|
const trigger_router_js_1 = require("./trigger-router.js");
|
|
46
|
+
const config_file_js_1 = require("../config/config-file.js");
|
|
46
47
|
const workflow_runner_js_1 = require("../daemon/workflow-runner.js");
|
|
47
48
|
const types_js_1 = require("./types.js");
|
|
48
49
|
const DEFAULT_TRIGGER_PORT = 3200;
|
|
@@ -111,7 +112,10 @@ async function startTriggerListener(ctx, options) {
|
|
|
111
112
|
if (!apiKey) {
|
|
112
113
|
return { _kind: 'err', error: { kind: 'missing_api_key' } };
|
|
113
114
|
}
|
|
114
|
-
const
|
|
115
|
+
const workspaceResult = (0, config_file_js_1.loadWorkspacesFromConfigFile)();
|
|
116
|
+
const loadedWorkspaces = workspaceResult.kind === 'ok' ? workspaceResult.value : {};
|
|
117
|
+
const workspaces = options.workspaces ?? loadedWorkspaces;
|
|
118
|
+
const configResult = await (0, trigger_store_js_1.loadTriggerConfigFromFile)(options.workspacePath, env, workspaces);
|
|
115
119
|
let triggerIndex;
|
|
116
120
|
if (configResult.kind === 'err') {
|
|
117
121
|
if (configResult.error.kind === 'file_not_found') {
|
|
@@ -132,8 +136,14 @@ async function startTriggerListener(ctx, options) {
|
|
|
132
136
|
triggerIndex = indexResult.value;
|
|
133
137
|
console.log(`[TriggerListener] Loaded ${configResult.value.triggers.length} trigger(s) from triggers.yml`);
|
|
134
138
|
}
|
|
139
|
+
const workrailConfig = (0, config_file_js_1.loadWorkrailConfigFile)();
|
|
140
|
+
const maxConcurrencyRaw = workrailConfig.kind === 'ok'
|
|
141
|
+
? workrailConfig.value['maxConcurrentSessions']
|
|
142
|
+
: undefined;
|
|
143
|
+
const parsed = parseInt(maxConcurrencyRaw ?? '', 10);
|
|
144
|
+
const maxConcurrentSessions = !isNaN(parsed) ? parsed : undefined;
|
|
135
145
|
const runWorkflowFn = options.runWorkflowFn ?? workflow_runner_js_1.runWorkflow;
|
|
136
|
-
const router = new trigger_router_js_1.TriggerRouter(triggerIndex, ctx, apiKey, runWorkflowFn);
|
|
146
|
+
const router = new trigger_router_js_1.TriggerRouter(triggerIndex, ctx, apiKey, runWorkflowFn, undefined, maxConcurrentSessions);
|
|
137
147
|
const app = createTriggerApp(router);
|
|
138
148
|
await (0, workflow_runner_js_1.runStartupRecovery)().catch((err) => {
|
|
139
149
|
console.warn('[TriggerListener] Startup recovery encountered an unexpected error:', err instanceof Error ? err.message : String(err));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { WorkflowTrigger, WorkflowRunResult } from '../daemon/workflow-runner.js';
|
|
2
2
|
import type { V2ToolContext } from '../mcp/types.js';
|
|
3
3
|
import type { TriggerDefinition, WebhookEvent } from './types.js';
|
|
4
|
+
import type { ExecFn } from './delivery-action.js';
|
|
4
5
|
export type RouteError = {
|
|
5
6
|
readonly kind: 'not_found';
|
|
6
7
|
readonly triggerId: string;
|
|
@@ -18,14 +19,19 @@ export type RouteResult = {
|
|
|
18
19
|
readonly error: RouteError;
|
|
19
20
|
};
|
|
20
21
|
export type RunWorkflowFn = (trigger: WorkflowTrigger, ctx: V2ToolContext, apiKey: string) => Promise<WorkflowRunResult>;
|
|
21
|
-
export declare function interpolateGoalTemplate(template: string, staticGoal: string, payload: Readonly<Record<string, unknown
|
|
22
|
+
export declare function interpolateGoalTemplate(template: string, staticGoal: string, payload: Readonly<Record<string, unknown>>, triggerId: string): string;
|
|
22
23
|
export declare class TriggerRouter {
|
|
23
24
|
private readonly index;
|
|
24
25
|
private readonly ctx;
|
|
25
26
|
private readonly apiKey;
|
|
26
27
|
private readonly runWorkflowFn;
|
|
27
28
|
private readonly queue;
|
|
28
|
-
|
|
29
|
+
private readonly execFn;
|
|
30
|
+
private readonly semaphore;
|
|
31
|
+
private readonly _maxConcurrentSessions;
|
|
32
|
+
constructor(index: ReadonlyMap<string, TriggerDefinition>, ctx: V2ToolContext, apiKey: string, runWorkflowFn: RunWorkflowFn, execFn?: ExecFn, maxConcurrentSessions?: number);
|
|
33
|
+
get activeSessions(): number;
|
|
34
|
+
get maxConcurrentSessions(): number;
|
|
29
35
|
route(event: WebhookEvent): RouteResult;
|
|
30
36
|
dispatch(workflowTrigger: WorkflowTrigger): string;
|
|
31
37
|
listTriggers(): readonly TriggerDefinition[];
|
|
@@ -36,8 +36,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
36
36
|
exports.TriggerRouter = void 0;
|
|
37
37
|
exports.interpolateGoalTemplate = interpolateGoalTemplate;
|
|
38
38
|
const crypto = __importStar(require("node:crypto"));
|
|
39
|
+
const node_child_process_1 = require("node:child_process");
|
|
40
|
+
const node_util_1 = require("node:util");
|
|
39
41
|
const index_js_1 = require("../v2/infra/in-memory/keyed-async-queue/index.js");
|
|
40
|
-
|
|
42
|
+
const delivery_client_js_1 = require("./delivery-client.js");
|
|
43
|
+
const delivery_action_js_1 = require("./delivery-action.js");
|
|
44
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
45
|
+
function interpolateGoalTemplate(template, staticGoal, payload, triggerId) {
|
|
41
46
|
const TOKEN_RE = /\{\{([^}]+)\}\}/g;
|
|
42
47
|
const tokens = [];
|
|
43
48
|
let match;
|
|
@@ -51,6 +56,8 @@ function interpolateGoalTemplate(template, staticGoal, payload) {
|
|
|
51
56
|
for (const token of tokens) {
|
|
52
57
|
const value = extractDotPath(payload, token);
|
|
53
58
|
if (value === undefined || value === null) {
|
|
59
|
+
console.warn(`[TriggerRouter] goalTemplate variable '${token}' not found in payload ` +
|
|
60
|
+
`for trigger '${triggerId}' (template: '${template}'). Falling back to static goal.`);
|
|
54
61
|
return staticGoal;
|
|
55
62
|
}
|
|
56
63
|
resolved.set(token, String(value));
|
|
@@ -108,13 +115,97 @@ function validateHmac(rawBody, secret, headerValue) {
|
|
|
108
115
|
}
|
|
109
116
|
return crypto.timingSafeEqual(Buffer.from(expected, 'utf8'), Buffer.from(received, 'utf8'));
|
|
110
117
|
}
|
|
118
|
+
async function maybeRunDelivery(triggerId, trigger, result, execFn) {
|
|
119
|
+
if (result._tag !== 'success')
|
|
120
|
+
return;
|
|
121
|
+
if (result.lastStepNotes === undefined) {
|
|
122
|
+
if (trigger.autoCommit === true) {
|
|
123
|
+
console.warn(`[TriggerRouter] Delivery skipped: triggerId=${triggerId} -- ` +
|
|
124
|
+
`lastStepNotes is absent (agent did not provide notes on the final step). ` +
|
|
125
|
+
`Ensure the workflow produces a JSON handoff block in its final step notes.`);
|
|
126
|
+
}
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
if (trigger.autoCommit !== true)
|
|
130
|
+
return;
|
|
131
|
+
const parseResult = (0, delivery_action_js_1.parseHandoffArtifact)(result.lastStepNotes);
|
|
132
|
+
if (parseResult.kind === 'err') {
|
|
133
|
+
console.warn(`[TriggerRouter] Delivery skipped: triggerId=${triggerId} -- ` +
|
|
134
|
+
`handoff artifact not parseable: ${parseResult.error}. ` +
|
|
135
|
+
`Ensure the workflow's final step produces a JSON block with commitType, filesChanged, etc.`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const deliveryResult = await (0, delivery_action_js_1.runDelivery)(parseResult.value, trigger.workspacePath, { autoCommit: trigger.autoCommit, autoOpenPR: trigger.autoOpenPR }, execFn);
|
|
139
|
+
switch (deliveryResult._tag) {
|
|
140
|
+
case 'committed':
|
|
141
|
+
console.log(`[TriggerRouter] Delivery committed: triggerId=${triggerId} sha=${deliveryResult.sha}`);
|
|
142
|
+
break;
|
|
143
|
+
case 'pr_opened':
|
|
144
|
+
console.log(`[TriggerRouter] Delivery PR opened: triggerId=${triggerId} url=${deliveryResult.url}`);
|
|
145
|
+
break;
|
|
146
|
+
case 'skipped':
|
|
147
|
+
console.log(`[TriggerRouter] Delivery skipped: triggerId=${triggerId} reason=${deliveryResult.reason}`);
|
|
148
|
+
break;
|
|
149
|
+
case 'error':
|
|
150
|
+
console.warn(`[TriggerRouter] Delivery error: triggerId=${triggerId} phase=${deliveryResult.phase} ` +
|
|
151
|
+
`details=${deliveryResult.details}`);
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
class Semaphore {
|
|
156
|
+
constructor(max) {
|
|
157
|
+
this.max = max;
|
|
158
|
+
this.active = 0;
|
|
159
|
+
this.waiters = [];
|
|
160
|
+
}
|
|
161
|
+
acquire() {
|
|
162
|
+
if (this.active < this.max) {
|
|
163
|
+
this.active++;
|
|
164
|
+
return Promise.resolve();
|
|
165
|
+
}
|
|
166
|
+
return new Promise((resolve) => {
|
|
167
|
+
this.waiters.push(resolve);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
release() {
|
|
171
|
+
const next = this.waiters.shift();
|
|
172
|
+
if (next !== undefined) {
|
|
173
|
+
next();
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this.active--;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
get activeCount() {
|
|
180
|
+
return this.active;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const DEFAULT_MAX_CONCURRENT_SESSIONS = 3;
|
|
111
184
|
class TriggerRouter {
|
|
112
|
-
constructor(index, ctx, apiKey, runWorkflowFn) {
|
|
185
|
+
constructor(index, ctx, apiKey, runWorkflowFn, execFn, maxConcurrentSessions) {
|
|
113
186
|
this.index = index;
|
|
114
187
|
this.ctx = ctx;
|
|
115
188
|
this.apiKey = apiKey;
|
|
116
189
|
this.runWorkflowFn = runWorkflowFn;
|
|
117
190
|
this.queue = new index_js_1.KeyedAsyncQueue();
|
|
191
|
+
this.execFn = execFn ?? execFileAsync;
|
|
192
|
+
const requested = maxConcurrentSessions ?? DEFAULT_MAX_CONCURRENT_SESSIONS;
|
|
193
|
+
const cap = Number.isNaN(requested) ? DEFAULT_MAX_CONCURRENT_SESSIONS : requested;
|
|
194
|
+
if (cap < 1) {
|
|
195
|
+
console.warn(`[TriggerRouter] maxConcurrentSessions must be >= 1; received ${cap}, clamping to 1.`);
|
|
196
|
+
this._maxConcurrentSessions = 1;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
this._maxConcurrentSessions = cap;
|
|
200
|
+
}
|
|
201
|
+
this.semaphore = new Semaphore(this._maxConcurrentSessions);
|
|
202
|
+
console.log(`[TriggerRouter] maxConcurrentSessions=${this._maxConcurrentSessions}`);
|
|
203
|
+
}
|
|
204
|
+
get activeSessions() {
|
|
205
|
+
return this.semaphore.activeCount;
|
|
206
|
+
}
|
|
207
|
+
get maxConcurrentSessions() {
|
|
208
|
+
return this._maxConcurrentSessions;
|
|
118
209
|
}
|
|
119
210
|
route(event) {
|
|
120
211
|
const trigger = this.index.get(event.triggerId);
|
|
@@ -141,7 +232,7 @@ class TriggerRouter {
|
|
|
141
232
|
workflowContext = { payload: event.payload };
|
|
142
233
|
}
|
|
143
234
|
const goal = trigger.goalTemplate
|
|
144
|
-
? interpolateGoalTemplate(trigger.goalTemplate, trigger.goal, event.payload)
|
|
235
|
+
? interpolateGoalTemplate(trigger.goalTemplate, trigger.goal, event.payload, trigger.id)
|
|
145
236
|
: trigger.goal;
|
|
146
237
|
const workflowTrigger = {
|
|
147
238
|
workflowId: trigger.workflowId,
|
|
@@ -150,27 +241,94 @@ class TriggerRouter {
|
|
|
150
241
|
context: workflowContext,
|
|
151
242
|
...(trigger.referenceUrls !== undefined ? { referenceUrls: trigger.referenceUrls } : {}),
|
|
152
243
|
...(trigger.agentConfig !== undefined ? { agentConfig: trigger.agentConfig } : {}),
|
|
244
|
+
...(trigger.soulFile !== undefined ? { soulFile: trigger.soulFile } : {}),
|
|
153
245
|
};
|
|
154
|
-
|
|
155
|
-
|
|
246
|
+
const queueKey = trigger.concurrencyMode === 'parallel'
|
|
247
|
+
? `${trigger.id}:${crypto.randomUUID()}`
|
|
248
|
+
: trigger.id;
|
|
249
|
+
void this.queue.enqueue(queueKey, async () => {
|
|
250
|
+
if (this.semaphore.activeCount >= this._maxConcurrentSessions) {
|
|
251
|
+
console.warn(`[TriggerRouter] Concurrency limit reached ` +
|
|
252
|
+
`(${this.semaphore.activeCount}/${this._maxConcurrentSessions} active): ` +
|
|
253
|
+
`queuing dispatch for triggerId=${trigger.id}`);
|
|
254
|
+
}
|
|
255
|
+
await this.semaphore.acquire();
|
|
256
|
+
let result;
|
|
257
|
+
try {
|
|
258
|
+
result = await this.runWorkflowFn(workflowTrigger, this.ctx, this.apiKey);
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
this.semaphore.release();
|
|
262
|
+
}
|
|
263
|
+
const originalTag = result._tag;
|
|
264
|
+
const originalResult = result;
|
|
265
|
+
if (trigger.callbackUrl) {
|
|
266
|
+
const deliveryResult = await (0, delivery_client_js_1.post)(trigger.callbackUrl, result);
|
|
267
|
+
if (deliveryResult.kind === 'err') {
|
|
268
|
+
const deliveryError = deliveryResult.error.kind === 'http_error'
|
|
269
|
+
? `HTTP ${deliveryResult.error.status}: ${deliveryResult.error.body}`
|
|
270
|
+
: deliveryResult.error.message;
|
|
271
|
+
console.error(`[TriggerRouter] Delivery failed: triggerId=${trigger.id} ` +
|
|
272
|
+
`callbackUrl=${trigger.callbackUrl} error=${deliveryError}`);
|
|
273
|
+
const deliveryFailed = {
|
|
274
|
+
_tag: 'delivery_failed',
|
|
275
|
+
workflowId: trigger.workflowId,
|
|
276
|
+
stopReason: result.stopReason,
|
|
277
|
+
deliveryError,
|
|
278
|
+
};
|
|
279
|
+
result = deliveryFailed;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
156
282
|
if (result._tag === 'success') {
|
|
157
283
|
console.log(`[TriggerRouter] Workflow completed: triggerId=${trigger.id} ` +
|
|
158
284
|
`workflowId=${trigger.workflowId} stopReason=${result.stopReason}`);
|
|
159
285
|
}
|
|
286
|
+
else if (result._tag === 'delivery_failed') {
|
|
287
|
+
const outcomeLabel = originalTag === 'success'
|
|
288
|
+
? 'Workflow succeeded but delivery failed'
|
|
289
|
+
: 'Workflow failed and delivery also failed';
|
|
290
|
+
console.log(`[TriggerRouter] ${outcomeLabel}: triggerId=${trigger.id} ` +
|
|
291
|
+
`workflowId=${trigger.workflowId} stopReason=${result.stopReason}`);
|
|
292
|
+
}
|
|
293
|
+
else if (result._tag === 'timeout') {
|
|
294
|
+
console.log(`[TriggerRouter] Workflow timed out: triggerId=${trigger.id} ` +
|
|
295
|
+
`workflowId=${trigger.workflowId} reason=${result.reason} message=${result.message}`);
|
|
296
|
+
}
|
|
160
297
|
else {
|
|
161
298
|
console.log(`[TriggerRouter] Workflow failed: triggerId=${trigger.id} ` +
|
|
162
299
|
`workflowId=${trigger.workflowId} error=${result.message} stopReason=${result.stopReason}`);
|
|
163
300
|
}
|
|
301
|
+
await maybeRunDelivery(trigger.id, trigger, originalResult, this.execFn);
|
|
164
302
|
});
|
|
165
303
|
return { _tag: 'enqueued', triggerId: trigger.id };
|
|
166
304
|
}
|
|
167
305
|
dispatch(workflowTrigger) {
|
|
168
306
|
void this.queue.enqueue(workflowTrigger.workflowId, async () => {
|
|
169
|
-
|
|
307
|
+
if (this.semaphore.activeCount >= this._maxConcurrentSessions) {
|
|
308
|
+
console.warn(`[TriggerRouter] Concurrency limit reached ` +
|
|
309
|
+
`(${this.semaphore.activeCount}/${this._maxConcurrentSessions} active): ` +
|
|
310
|
+
`queuing dispatch for workflowId=${workflowTrigger.workflowId}`);
|
|
311
|
+
}
|
|
312
|
+
await this.semaphore.acquire();
|
|
313
|
+
let result;
|
|
314
|
+
try {
|
|
315
|
+
result = await this.runWorkflowFn(workflowTrigger, this.ctx, this.apiKey);
|
|
316
|
+
}
|
|
317
|
+
finally {
|
|
318
|
+
this.semaphore.release();
|
|
319
|
+
}
|
|
170
320
|
if (result._tag === 'success') {
|
|
171
321
|
console.log(`[TriggerRouter] Dispatch completed: workflowId=${workflowTrigger.workflowId} ` +
|
|
172
322
|
`stopReason=${result.stopReason}`);
|
|
173
323
|
}
|
|
324
|
+
else if (result._tag === 'delivery_failed') {
|
|
325
|
+
console.log(`[TriggerRouter] Dispatch delivery failed: workflowId=${workflowTrigger.workflowId} ` +
|
|
326
|
+
`stopReason=${result.stopReason} deliveryError=${result.deliveryError}`);
|
|
327
|
+
}
|
|
328
|
+
else if (result._tag === 'timeout') {
|
|
329
|
+
console.log(`[TriggerRouter] Dispatch timed out: workflowId=${workflowTrigger.workflowId} ` +
|
|
330
|
+
`reason=${result.reason} message=${result.message}`);
|
|
331
|
+
}
|
|
174
332
|
else {
|
|
175
333
|
console.log(`[TriggerRouter] Dispatch failed: workflowId=${workflowTrigger.workflowId} ` +
|
|
176
334
|
`error=${result.message} stopReason=${result.stopReason}`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Result } from '../runtime/result.js';
|
|
2
|
-
import { type TriggerConfig, type TriggerDefinition } from './types.js';
|
|
2
|
+
import { type TriggerConfig, type TriggerDefinition, type WorkspaceConfig } from './types.js';
|
|
3
3
|
export type TriggerStoreError = {
|
|
4
4
|
readonly kind: 'parse_error';
|
|
5
5
|
readonly message: string;
|
|
@@ -12,10 +12,18 @@ export type TriggerStoreError = {
|
|
|
12
12
|
readonly kind: 'missing_field';
|
|
13
13
|
readonly field: string;
|
|
14
14
|
readonly triggerId: string;
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: 'invalid_field_value';
|
|
17
|
+
readonly field: string;
|
|
18
|
+
readonly triggerId: string;
|
|
15
19
|
} | {
|
|
16
20
|
readonly kind: 'unknown_provider';
|
|
17
21
|
readonly provider: string;
|
|
18
22
|
readonly triggerId: string;
|
|
23
|
+
} | {
|
|
24
|
+
readonly kind: 'unknown_workspace';
|
|
25
|
+
readonly workspaceName: string;
|
|
26
|
+
readonly triggerId: string;
|
|
19
27
|
} | {
|
|
20
28
|
readonly kind: 'file_not_found';
|
|
21
29
|
readonly filePath: string;
|
|
@@ -26,6 +34,6 @@ export type TriggerStoreError = {
|
|
|
26
34
|
readonly kind: 'duplicate_id';
|
|
27
35
|
readonly triggerId: string;
|
|
28
36
|
};
|
|
29
|
-
export declare function loadTriggerConfig(yamlContent: string, env?: Record<string, string | undefined
|
|
30
|
-
export declare function loadTriggerConfigFromFile(workspacePath: string, env?: Record<string, string | undefined
|
|
37
|
+
export declare function loadTriggerConfig(yamlContent: string, env?: Record<string, string | undefined>, workspaces?: Readonly<Record<string, WorkspaceConfig>>): Result<TriggerConfig, TriggerStoreError>;
|
|
38
|
+
export declare function loadTriggerConfigFromFile(workspacePath: string, env?: Record<string, string | undefined>, workspaces?: Readonly<Record<string, WorkspaceConfig>>): Promise<Result<TriggerConfig, TriggerStoreError>>;
|
|
31
39
|
export declare function buildTriggerIndex(config: TriggerConfig): Result<Map<string, TriggerDefinition>, TriggerStoreError>;
|