@tagma/sdk 0.3.0 → 0.3.2
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/README.md +14 -0
- package/package.json +1 -1
- package/src/dag.ts +9 -1
- package/src/validate-raw.ts +7 -3
package/README.md
CHANGED
|
@@ -326,6 +326,20 @@ Properties:
|
|
|
326
326
|
- `runId` — engine-assigned run ID, available after the first `pipeline_start` event (`null` until then)
|
|
327
327
|
- `status` — `'idle' | 'running' | 'done' | 'aborted'`
|
|
328
328
|
|
|
329
|
+
### `TriggerBlockedError` / `TriggerTimeoutError`
|
|
330
|
+
|
|
331
|
+
Typed error classes for trigger plugin error classification. The engine uses `instanceof` checks on these to set the correct task status (`blocked` or `timeout`) instead of matching on error message substrings.
|
|
332
|
+
|
|
333
|
+
Built-in triggers (`manual`, `file`) throw these automatically. Third-party trigger plugins should throw `TriggerBlockedError` for user/policy rejections and `TriggerTimeoutError` for genuine wait timeouts. Plugins that throw plain `Error` still work — the engine falls back to string matching for backward compatibility, but typed errors are preferred to avoid misclassification from coincidental substrings.
|
|
334
|
+
|
|
335
|
+
```ts
|
|
336
|
+
import { TriggerBlockedError, TriggerTimeoutError } from '@tagma/sdk';
|
|
337
|
+
|
|
338
|
+
// In a custom trigger plugin:
|
|
339
|
+
throw new TriggerBlockedError('Access denied by policy');
|
|
340
|
+
throw new TriggerTimeoutError('File did not appear within 30s');
|
|
341
|
+
```
|
|
342
|
+
|
|
329
343
|
### `loadPlugins(names: string[]): Promise<void>`
|
|
330
344
|
|
|
331
345
|
Dynamically loads and registers external plugin packages.
|
package/package.json
CHANGED
package/src/dag.ts
CHANGED
|
@@ -84,7 +84,15 @@ export function buildDag(config: PipelineConfig): Dag {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
if (task.continue_from) {
|
|
87
|
-
|
|
87
|
+
let resolved: string;
|
|
88
|
+
try {
|
|
89
|
+
resolved = resolveRef(task.continue_from, track.id);
|
|
90
|
+
} catch {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Task "${qid}": continue_from "${task.continue_from}" — no such task found. ` +
|
|
93
|
+
`Use a fully-qualified reference (trackId.taskId) or ensure the target task exists.`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
88
96
|
if (!deps.includes(resolved)) {
|
|
89
97
|
deps.push(resolved); // continue_from implies dependency
|
|
90
98
|
}
|
package/src/validate-raw.ts
CHANGED
|
@@ -241,11 +241,15 @@ function detectCycles(
|
|
|
241
241
|
function dfs(id: string): void {
|
|
242
242
|
if (inStack.has(id)) {
|
|
243
243
|
const cycleStart = pathStack.indexOf(id);
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
// Unique nodes in the cycle (without repeating the start node) for dedup.
|
|
245
|
+
// Previously the duplicate start node caused different sorted keys when
|
|
246
|
+
// the same cycle was discovered from different entry points.
|
|
247
|
+
const uniqueNodes = pathStack.slice(cycleStart);
|
|
248
|
+
const key = [...uniqueNodes].sort().join(',');
|
|
246
249
|
if (!seenCycles.has(key)) {
|
|
247
250
|
seenCycles.add(key);
|
|
248
|
-
|
|
251
|
+
const display = [...uniqueNodes, id]; // include start for readable display
|
|
252
|
+
errors.push({ path: 'tracks', message: `Circular dependency detected: ${display.join(' → ')}` });
|
|
249
253
|
}
|
|
250
254
|
return;
|
|
251
255
|
}
|