@smithers-orchestrator/graph 0.23.0 → 0.24.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/package.json +2 -2
- package/src/TaskAspects.ts +1 -0
- package/src/dom/extract.js +4 -8
- package/src/extract.js +47 -5
- package/src/index.d.ts +25 -4
- package/src/index.js +1 -0
- package/src/types.ts +22 -3
- package/src/worktree-path.js +24 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smithers-orchestrator/graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.2",
|
|
4
4
|
"description": "Framework-neutral Smithers workflow graph model and extraction helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"drizzle-orm": "^0.45.2",
|
|
24
24
|
"zod": "^4.3.6",
|
|
25
|
-
"@smithers-orchestrator/errors": "0.
|
|
25
|
+
"@smithers-orchestrator/errors": "0.24.2"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/bun": "latest",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { TaskAspects } from "./types";
|
package/src/dom/extract.js
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
// @smithers-type-exports-end
|
|
5
5
|
|
|
6
6
|
import { resolveStableId } from "@smithers-orchestrator/graph/utils/tree-ids";
|
|
7
|
-
import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
8
7
|
import { getTableName } from "drizzle-orm";
|
|
9
8
|
import { DEFAULT_MERGE_QUEUE_CONCURRENCY, WORKTREE_EMPTY_PATH_ERROR, } from "@smithers-orchestrator/graph/constants";
|
|
10
9
|
import { SmithersError } from "@smithers-orchestrator/errors/SmithersError";
|
|
10
|
+
import { resolveWorktreePath } from "@smithers-orchestrator/graph/worktree-path";
|
|
11
11
|
|
|
12
12
|
/** @typedef {import("../ExtractOptions.ts").ExtractOptions} ExtractOptions */
|
|
13
13
|
/** @typedef {import("../ExtractResult.ts").ExtractResult} ExtractResult */
|
|
@@ -251,13 +251,7 @@ export function extractFromHost(root, opts) {
|
|
|
251
251
|
if (!pathVal) {
|
|
252
252
|
throw new SmithersError("WORKTREE_EMPTY_PATH", WORKTREE_EMPTY_PATH_ERROR);
|
|
253
253
|
}
|
|
254
|
-
const
|
|
255
|
-
const base = typeof baseRoot === "string" && baseRoot.length > 0
|
|
256
|
-
? baseRoot
|
|
257
|
-
: process.cwd();
|
|
258
|
-
const normPath = isAbsolute(pathVal)
|
|
259
|
-
? resolvePath(pathVal)
|
|
260
|
-
: resolvePath(base, pathVal);
|
|
254
|
+
const normPath = resolveWorktreePath(pathVal, { baseRootDir: opts?.baseRootDir });
|
|
261
255
|
const branch = node.rawProps?.branch ? String(node.rawProps.branch) : undefined;
|
|
262
256
|
const baseBranch = node.rawProps?.baseBranch ? String(node.rawProps.baseBranch) : undefined;
|
|
263
257
|
nextWorktreeStack = [...worktreeStack, { id, path: normPath, branch, baseBranch }];
|
|
@@ -464,6 +458,7 @@ export function extractFromHost(root, opts) {
|
|
|
464
458
|
config: {
|
|
465
459
|
image: raw.image,
|
|
466
460
|
env: raw.env,
|
|
461
|
+
egress: raw.egress,
|
|
467
462
|
ports: raw.ports,
|
|
468
463
|
volumes: raw.volumes,
|
|
469
464
|
memoryLimit: raw.memoryLimit,
|
|
@@ -488,6 +483,7 @@ export function extractFromHost(root, opts) {
|
|
|
488
483
|
__sandboxConfig: {
|
|
489
484
|
image: raw.image,
|
|
490
485
|
env: raw.env,
|
|
486
|
+
egress: raw.egress,
|
|
491
487
|
ports: raw.ports,
|
|
492
488
|
volumes: raw.volumes,
|
|
493
489
|
memoryLimit: raw.memoryLimit,
|
package/src/extract.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
2
1
|
import { getTableName } from "drizzle-orm";
|
|
3
2
|
import { SmithersError } from "@smithers-orchestrator/errors/SmithersError";
|
|
4
3
|
import { validateForkSources } from "./validateForkSources.js";
|
|
4
|
+
import { resolveWorktreePath } from "./worktree-path.js";
|
|
5
5
|
/** @typedef {import("./TaskDescriptor.ts").TaskDescriptor} TaskDescriptor */
|
|
6
6
|
/** @typedef {import("./XmlNode.ts").XmlNode} XmlNode */
|
|
7
7
|
/** @typedef {import("./ExtractOptions.ts").ExtractOptions} ExtractOptions */
|
|
@@ -248,6 +248,49 @@ function approvalAutoApprove(value) {
|
|
|
248
248
|
: {}),
|
|
249
249
|
};
|
|
250
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Normalize the `__aspects` element prop attached by `<Task>` into the
|
|
253
|
+
* `TaskAspects` budget metadata the engine enforces. Only the budget configs
|
|
254
|
+
* are kept; the render-time accumulator and tracking flags are dropped (the
|
|
255
|
+
* engine keeps its own durable per-run accumulator and budgets enforce
|
|
256
|
+
* regardless of tracking).
|
|
257
|
+
*
|
|
258
|
+
* @param {unknown} value
|
|
259
|
+
* @returns {import("./types").TaskAspects | undefined}
|
|
260
|
+
*/
|
|
261
|
+
function aspects(value) {
|
|
262
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
const raw = /** @type {Record<string, unknown>} */ (value);
|
|
266
|
+
/** @type {import("./types").TaskAspects} */
|
|
267
|
+
const out = {};
|
|
268
|
+
const token = raw.tokenBudget;
|
|
269
|
+
if (token && typeof token === "object" && !Array.isArray(token) &&
|
|
270
|
+
typeof (/** @type {Record<string, unknown>} */ (token).max) === "number") {
|
|
271
|
+
const t = /** @type {Record<string, unknown>} */ (token);
|
|
272
|
+
out.tokenBudget = {
|
|
273
|
+
max: /** @type {number} */ (t.max),
|
|
274
|
+
...(typeof t.perTask === "number" ? { perTask: t.perTask } : {}),
|
|
275
|
+
...(t.onExceeded === "warn" || t.onExceeded === "skip-remaining" || t.onExceeded === "fail"
|
|
276
|
+
? { onExceeded: /** @type {"fail" | "warn" | "skip-remaining"} */ (t.onExceeded) }
|
|
277
|
+
: {}),
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
const latency = raw.latencySlo;
|
|
281
|
+
if (latency && typeof latency === "object" && !Array.isArray(latency) &&
|
|
282
|
+
typeof (/** @type {Record<string, unknown>} */ (latency).maxMs) === "number") {
|
|
283
|
+
const l = /** @type {Record<string, unknown>} */ (latency);
|
|
284
|
+
out.latencySlo = {
|
|
285
|
+
maxMs: /** @type {number} */ (l.maxMs),
|
|
286
|
+
...(typeof l.perTask === "number" ? { perTask: l.perTask } : {}),
|
|
287
|
+
...(l.onExceeded === "warn" || l.onExceeded === "fail"
|
|
288
|
+
? { onExceeded: /** @type {"fail" | "warn"} */ (l.onExceeded) }
|
|
289
|
+
: {}),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return out.tokenBudget || out.latencySlo ? out : undefined;
|
|
293
|
+
}
|
|
251
294
|
/**
|
|
252
295
|
* @param {"parallel" | "merge-queue"} tag
|
|
253
296
|
* @param {Record<string, unknown>} raw
|
|
@@ -364,14 +407,11 @@ export function extractGraph(root, opts) {
|
|
|
364
407
|
if (!pathVal) {
|
|
365
408
|
throw new SmithersError("WORKTREE_EMPTY_PATH", WORKTREE_EMPTY_PATH_ERROR);
|
|
366
409
|
}
|
|
367
|
-
const base = typeof opts?.baseRootDir === "string" && opts.baseRootDir.length > 0
|
|
368
|
-
? opts.baseRootDir
|
|
369
|
-
: process.cwd();
|
|
370
410
|
nextWorktreeStack = [
|
|
371
411
|
...ctx.worktreeStack,
|
|
372
412
|
{
|
|
373
413
|
id,
|
|
374
|
-
path:
|
|
414
|
+
path: resolveWorktreePath(pathVal, opts),
|
|
375
415
|
...(raw.branch ? { branch: String(raw.branch) } : {}),
|
|
376
416
|
...(raw.baseBranch ? { baseBranch: String(raw.baseBranch) } : {}),
|
|
377
417
|
},
|
|
@@ -463,6 +503,7 @@ export function extractGraph(root, opts) {
|
|
|
463
503
|
__sandboxConfig: {
|
|
464
504
|
image: raw.image,
|
|
465
505
|
env: raw.env,
|
|
506
|
+
egress: raw.egress,
|
|
466
507
|
ports: raw.ports,
|
|
467
508
|
volumes: raw.volumes,
|
|
468
509
|
memoryLimit: raw.memoryLimit,
|
|
@@ -630,6 +671,7 @@ export function extractGraph(root, opts) {
|
|
|
630
671
|
memoryConfig: raw.memory && typeof raw.memory === "object" && !Array.isArray(raw.memory)
|
|
631
672
|
? raw.memory
|
|
632
673
|
: undefined,
|
|
674
|
+
aspects: aspects(raw.__aspects),
|
|
633
675
|
});
|
|
634
676
|
}
|
|
635
677
|
let elementIndex = 0;
|
package/src/index.d.ts
CHANGED
|
@@ -26,9 +26,6 @@ type HostText$1 = {
|
|
|
26
26
|
type RetryPolicy$1 = {
|
|
27
27
|
backoff?: "fixed" | "linear" | "exponential";
|
|
28
28
|
initialDelayMs?: number;
|
|
29
|
-
maxDelayMs?: number;
|
|
30
|
-
multiplier?: number;
|
|
31
|
-
jitter?: boolean;
|
|
32
29
|
};
|
|
33
30
|
type CachePolicy$1<Ctx = unknown> = {
|
|
34
31
|
by?: (ctx: Ctx) => unknown;
|
|
@@ -112,6 +109,18 @@ type ApprovalOption$1 = {
|
|
|
112
109
|
summary?: string;
|
|
113
110
|
metadata?: Record<string, unknown>;
|
|
114
111
|
};
|
|
112
|
+
type TaskAspects$1 = {
|
|
113
|
+
tokenBudget?: {
|
|
114
|
+
max: number;
|
|
115
|
+
perTask?: number;
|
|
116
|
+
onExceeded?: "fail" | "warn" | "skip-remaining";
|
|
117
|
+
};
|
|
118
|
+
latencySlo?: {
|
|
119
|
+
maxMs: number;
|
|
120
|
+
perTask?: number;
|
|
121
|
+
onExceeded?: "fail" | "warn";
|
|
122
|
+
};
|
|
123
|
+
};
|
|
115
124
|
type TaskDescriptor$1 = {
|
|
116
125
|
nodeId: string;
|
|
117
126
|
ordinal: number;
|
|
@@ -159,6 +168,7 @@ type TaskDescriptor$1 = {
|
|
|
159
168
|
meta?: Record<string, unknown>;
|
|
160
169
|
scorers?: ScorersMap$1;
|
|
161
170
|
memoryConfig?: TaskMemoryConfig$1;
|
|
171
|
+
aspects?: TaskAspects$1;
|
|
162
172
|
};
|
|
163
173
|
type WorkflowGraph$2 = {
|
|
164
174
|
readonly xml: XmlNode$1 | null;
|
|
@@ -192,6 +202,16 @@ declare function extractGraph(root: HostNode$1 | null, opts?: ExtractOptions$1):
|
|
|
192
202
|
* @returns {WorkflowGraph}
|
|
193
203
|
*/
|
|
194
204
|
declare function extractFromHost(root: HostNode$1 | null, opts?: ExtractOptions$1): WorkflowGraph$1;
|
|
205
|
+
/**
|
|
206
|
+
* Resolve a <Worktree path> prop exactly the way graph extraction resolves it.
|
|
207
|
+
*
|
|
208
|
+
* @param {unknown} path
|
|
209
|
+
* @param {{ baseRootDir?: string }} [opts]
|
|
210
|
+
* @returns {string}
|
|
211
|
+
*/
|
|
212
|
+
declare function resolveWorktreePath(path: unknown, opts?: {
|
|
213
|
+
baseRootDir?: string;
|
|
214
|
+
}): string;
|
|
195
215
|
type ExtractOptions$1 = ExtractOptions$2;
|
|
196
216
|
type HostNode$1 = HostNode$2;
|
|
197
217
|
type WorkflowGraph$1 = WorkflowGraph$2;
|
|
@@ -215,6 +235,7 @@ type ScorerBinding = ScorerBinding$1;
|
|
|
215
235
|
type ScorerFn = ScorerFn$1;
|
|
216
236
|
type ScorerInput = ScorerInput$1;
|
|
217
237
|
type ScorersMap = ScorersMap$1;
|
|
238
|
+
type TaskAspects = TaskAspects$1;
|
|
218
239
|
type TaskDescriptor = TaskDescriptor$1;
|
|
219
240
|
type TaskMemoryConfig = TaskMemoryConfig$1;
|
|
220
241
|
type WorkflowGraph = WorkflowGraph$2;
|
|
@@ -222,4 +243,4 @@ type XmlElement = XmlElement$1;
|
|
|
222
243
|
type XmlNode = XmlNode$1;
|
|
223
244
|
type XmlText = XmlText$1;
|
|
224
245
|
|
|
225
|
-
export { type AgentLike, type ApprovalOption, type CachePolicy, type ExtractGraph, type ExtractOptions, type GraphSnapshot, type HostElement, type HostNode, type HostText, type MemoryNamespace, type MemoryNamespaceKind, type RetryPolicy, type SamplingConfig, type ScoreResult, type Scorer, type ScorerBinding, type ScorerFn, type ScorerInput, type ScorersMap, type TaskDescriptor, type TaskMemoryConfig, type WorkflowGraph, type XmlElement, type XmlNode, type XmlText, extractFromHost, extractGraph };
|
|
246
|
+
export { type AgentLike, type ApprovalOption, type CachePolicy, type ExtractGraph, type ExtractOptions, type GraphSnapshot, type HostElement, type HostNode, type HostText, type MemoryNamespace, type MemoryNamespaceKind, type RetryPolicy, type SamplingConfig, type ScoreResult, type Scorer, type ScorerBinding, type ScorerFn, type ScorerInput, type ScorersMap, type TaskAspects, type TaskDescriptor, type TaskMemoryConfig, type WorkflowGraph, type XmlElement, type XmlNode, type XmlText, extractFromHost, extractGraph, resolveWorktreePath };
|
package/src/index.js
CHANGED
package/src/types.ts
CHANGED
|
@@ -32,9 +32,6 @@ export type HostText = {
|
|
|
32
32
|
export type RetryPolicy = {
|
|
33
33
|
backoff?: "fixed" | "linear" | "exponential";
|
|
34
34
|
initialDelayMs?: number;
|
|
35
|
-
maxDelayMs?: number;
|
|
36
|
-
multiplier?: number;
|
|
37
|
-
jitter?: boolean;
|
|
38
35
|
};
|
|
39
36
|
|
|
40
37
|
export type CachePolicy<Ctx = unknown> = {
|
|
@@ -126,6 +123,26 @@ export type ApprovalOption = {
|
|
|
126
123
|
metadata?: Record<string, unknown>;
|
|
127
124
|
};
|
|
128
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Resolved `<Aspects>` budget configuration that applies to a task, extracted
|
|
128
|
+
* from the `__aspects` element prop. The engine reads this at task-dispatch
|
|
129
|
+
* time to enforce per-run token and latency budgets. The render-time
|
|
130
|
+
* accumulator carried alongside the budgets in the component tree is dropped
|
|
131
|
+
* here; the engine keeps its own durable accumulator.
|
|
132
|
+
*/
|
|
133
|
+
export type TaskAspects = {
|
|
134
|
+
tokenBudget?: {
|
|
135
|
+
max: number;
|
|
136
|
+
perTask?: number;
|
|
137
|
+
onExceeded?: "fail" | "warn" | "skip-remaining";
|
|
138
|
+
};
|
|
139
|
+
latencySlo?: {
|
|
140
|
+
maxMs: number;
|
|
141
|
+
perTask?: number;
|
|
142
|
+
onExceeded?: "fail" | "warn";
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
|
|
129
146
|
export type TaskDescriptor = {
|
|
130
147
|
nodeId: string;
|
|
131
148
|
ordinal: number;
|
|
@@ -176,6 +193,8 @@ export type TaskDescriptor = {
|
|
|
176
193
|
scorers?: ScorersMap;
|
|
177
194
|
|
|
178
195
|
memoryConfig?: TaskMemoryConfig;
|
|
196
|
+
/** Resolved `<Aspects>` budget configuration enforced by the engine at dispatch. */
|
|
197
|
+
aspects?: TaskAspects;
|
|
179
198
|
};
|
|
180
199
|
|
|
181
200
|
export type WorkflowGraph = {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { isAbsolute, resolve } from "node:path";
|
|
2
|
+
import { SmithersError } from "@smithers-orchestrator/errors/SmithersError";
|
|
3
|
+
import { WORKTREE_EMPTY_PATH_ERROR } from "./constants.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a <Worktree path> prop exactly the way graph extraction resolves it.
|
|
7
|
+
*
|
|
8
|
+
* @param {unknown} path
|
|
9
|
+
* @param {{ baseRootDir?: string }} [opts]
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
export function resolveWorktreePath(path, opts) {
|
|
13
|
+
const pathVal = String(path ?? "").trim();
|
|
14
|
+
if (!pathVal) {
|
|
15
|
+
throw new SmithersError("WORKTREE_EMPTY_PATH", WORKTREE_EMPTY_PATH_ERROR);
|
|
16
|
+
}
|
|
17
|
+
if (isAbsolute(pathVal)) {
|
|
18
|
+
return resolve(pathVal);
|
|
19
|
+
}
|
|
20
|
+
const base = typeof opts?.baseRootDir === "string" && opts.baseRootDir.length > 0
|
|
21
|
+
? opts.baseRootDir
|
|
22
|
+
: process.cwd();
|
|
23
|
+
return resolve(base, pathVal);
|
|
24
|
+
}
|