@sapiom/harness 0.8.9 → 0.10.0
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/CHANGELOG.md +99 -0
- package/README.md +11 -1
- package/dist/core/agent-project-discovery.d.ts +235 -1
- package/dist/core/agent-project-discovery.d.ts.map +1 -1
- package/dist/core/agent-project-discovery.js +303 -1
- package/dist/core/agent-project-discovery.js.map +1 -1
- package/dist/core/canvas-interconnections.d.ts +31 -0
- package/dist/core/canvas-interconnections.d.ts.map +1 -1
- package/dist/core/canvas-interconnections.js +294 -21
- package/dist/core/canvas-interconnections.js.map +1 -1
- package/dist/core/canvas-render.d.ts +32 -0
- package/dist/core/canvas-render.d.ts.map +1 -1
- package/dist/core/canvas-render.js +50 -41
- package/dist/core/canvas-render.js.map +1 -1
- package/dist/core/definition-name.d.ts +12 -0
- package/dist/core/definition-name.d.ts.map +1 -1
- package/dist/core/definition-name.js +14 -5
- package/dist/core/definition-name.js.map +1 -1
- package/dist/core/system-graph-inventory.d.ts +68 -0
- package/dist/core/system-graph-inventory.d.ts.map +1 -0
- package/dist/core/system-graph-inventory.js +312 -0
- package/dist/core/system-graph-inventory.js.map +1 -0
- package/dist/core/system-graph-relationships.d.ts +41 -0
- package/dist/core/system-graph-relationships.d.ts.map +1 -0
- package/dist/core/system-graph-relationships.js +98 -0
- package/dist/core/system-graph-relationships.js.map +1 -0
- package/dist/core/system-graph-store.d.ts +45 -0
- package/dist/core/system-graph-store.d.ts.map +1 -0
- package/dist/core/system-graph-store.js +222 -0
- package/dist/core/system-graph-store.js.map +1 -0
- package/dist/core/system-graph-watcher.d.ts +51 -0
- package/dist/core/system-graph-watcher.d.ts.map +1 -0
- package/dist/core/system-graph-watcher.js +448 -0
- package/dist/core/system-graph-watcher.js.map +1 -0
- package/dist/core/system-graph.d.ts +43 -0
- package/dist/core/system-graph.d.ts.map +1 -0
- package/dist/core/system-graph.js +321 -0
- package/dist/core/system-graph.js.map +1 -0
- package/dist/core/workflow-registry.d.ts +84 -6
- package/dist/core/workflow-registry.d.ts.map +1 -1
- package/dist/core/workflow-registry.js +191 -91
- package/dist/core/workflow-registry.js.map +1 -1
- package/dist/core/workspace-watcher.d.ts +21 -13
- package/dist/core/workspace-watcher.d.ts.map +1 -1
- package/dist/core/workspace-watcher.js +79 -81
- package/dist/core/workspace-watcher.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server/agent-move.d.ts +134 -0
- package/dist/server/agent-move.d.ts.map +1 -0
- package/dist/server/agent-move.js +343 -0
- package/dist/server/agent-move.js.map +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +275 -22
- package/dist/server/index.js.map +1 -1
- package/dist/server/rest.d.ts +3 -0
- package/dist/server/rest.d.ts.map +1 -1
- package/dist/server/rest.js +3 -0
- package/dist/server/rest.js.map +1 -1
- package/dist/server/studio-rail.d.ts +76 -0
- package/dist/server/studio-rail.d.ts.map +1 -0
- package/dist/server/studio-rail.js +234 -0
- package/dist/server/studio-rail.js.map +1 -0
- package/dist/server/system-graph.d.ts +14 -0
- package/dist/server/system-graph.d.ts.map +1 -0
- package/dist/server/system-graph.js +40 -0
- package/dist/server/system-graph.js.map +1 -0
- package/dist/server/workflow-graph.d.ts +43 -0
- package/dist/server/workflow-graph.d.ts.map +1 -0
- package/dist/server/workflow-graph.js +200 -0
- package/dist/server/workflow-graph.js.map +1 -0
- package/dist/shared/system-graph.d.ts +59 -0
- package/dist/shared/system-graph.d.ts.map +1 -0
- package/dist/shared/system-graph.js +76 -0
- package/dist/shared/system-graph.js.map +1 -0
- package/dist/shared/types.d.ts +45 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js.map +1 -1
- package/dist/web/assets/index-BLrCZ-6M.css +32 -0
- package/dist/web/assets/index-CzCPIbq9.js +513 -0
- package/dist/web/index.html +2 -2
- package/package.json +3 -3
- package/dist/web/assets/index-B18B2y5o.js +0 -494
- package/dist/web/assets/index-jGBbXx9R.css +0 -32
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { workspaceRelativeLocalKey } from "../shared/system-graph.js";
|
|
4
|
+
import { canonicalGraphPath, isWithinGraphPath, } from "./system-graph-inventory.js";
|
|
5
|
+
import { CachedAgentRelationshipProvider, SourceAgentRelationshipProvider, } from "./system-graph-relationships.js";
|
|
6
|
+
export { HarnessRegistryInventoryProvider } from "./system-graph-inventory.js";
|
|
7
|
+
export { CachedAgentRelationshipProvider, SourceAgentRelationshipProvider, } from "./system-graph-relationships.js";
|
|
8
|
+
function workspaceKeyForRoot(root) {
|
|
9
|
+
return `workspace-${createHash("sha256").update(root).digest("hex").slice(0, 16)}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Resolves only roots the running Studio already knows about. A caller cannot
|
|
13
|
+
* manufacture a key and turn the graph endpoint into an arbitrary path scan.
|
|
14
|
+
*/
|
|
15
|
+
export class LocalWorkspaceScopeCatalog {
|
|
16
|
+
constructor(listRoots) {
|
|
17
|
+
this.listRoots = listRoots;
|
|
18
|
+
}
|
|
19
|
+
async list() {
|
|
20
|
+
const byRoot = new Map();
|
|
21
|
+
for (const root of await this.listRoots()) {
|
|
22
|
+
const canonical = canonicalGraphPath(root);
|
|
23
|
+
byRoot.set(canonical, {
|
|
24
|
+
workspaceKey: workspaceKeyForRoot(canonical),
|
|
25
|
+
cwd: root,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return [...byRoot.entries()]
|
|
29
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
30
|
+
.map(([, summary]) => summary);
|
|
31
|
+
}
|
|
32
|
+
async resolve(workspaceKey) {
|
|
33
|
+
for (const root of await this.listRoots()) {
|
|
34
|
+
const canonical = canonicalGraphPath(root);
|
|
35
|
+
if (workspaceKeyForRoot(canonical) === workspaceKey) {
|
|
36
|
+
return { workspaceKey, root: canonical };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function warningOrder(left, right) {
|
|
43
|
+
return (left.code.localeCompare(right.code) ||
|
|
44
|
+
(left.agentKey ?? "").localeCompare(right.agentKey ?? "") ||
|
|
45
|
+
left.message.localeCompare(right.message));
|
|
46
|
+
}
|
|
47
|
+
function fallbackAgentKey(scope, sourceRoot) {
|
|
48
|
+
const canonicalScope = canonicalGraphPath(scope.root);
|
|
49
|
+
const canonicalSource = canonicalGraphPath(sourceRoot);
|
|
50
|
+
if (isWithinGraphPath(canonicalScope, canonicalSource)) {
|
|
51
|
+
const localKey = workspaceRelativeLocalKey(canonicalScope, canonicalSource);
|
|
52
|
+
if (localKey)
|
|
53
|
+
return localKey;
|
|
54
|
+
}
|
|
55
|
+
return `local:${createHash("sha256")
|
|
56
|
+
.update(canonicalSource)
|
|
57
|
+
.digest("hex")
|
|
58
|
+
.slice(0, 16)}`;
|
|
59
|
+
}
|
|
60
|
+
function safeAgentKey(value) {
|
|
61
|
+
const key = value.trim();
|
|
62
|
+
if (key === "" ||
|
|
63
|
+
/[\0\r\n]/.test(key) ||
|
|
64
|
+
path.posix.isAbsolute(key) ||
|
|
65
|
+
path.win32.isAbsolute(key) ||
|
|
66
|
+
key.includes("\\")) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (!key.startsWith("local:"))
|
|
70
|
+
return key.includes("/") ? null : key;
|
|
71
|
+
const relative = key.slice("local:".length);
|
|
72
|
+
if (relative === "" ||
|
|
73
|
+
path.posix.isAbsolute(relative) ||
|
|
74
|
+
path.win32.isAbsolute(relative) ||
|
|
75
|
+
relative
|
|
76
|
+
.split("/")
|
|
77
|
+
.some((segment) => segment === "" || segment === "." || segment === "..")) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return key;
|
|
81
|
+
}
|
|
82
|
+
function safeLabel(value, agentKey) {
|
|
83
|
+
const label = value.trim();
|
|
84
|
+
if (label !== "" &&
|
|
85
|
+
!/[\0\r\n]/.test(label) &&
|
|
86
|
+
!path.posix.isAbsolute(label) &&
|
|
87
|
+
!path.win32.isAbsolute(label)) {
|
|
88
|
+
return label;
|
|
89
|
+
}
|
|
90
|
+
if (agentKey.startsWith("local:")) {
|
|
91
|
+
return agentKey.slice("local:".length) || "Local agent";
|
|
92
|
+
}
|
|
93
|
+
return agentKey;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The provider contract promises safe unique keys, but projection is the last
|
|
97
|
+
* server-side boundary before serialization. Re-assert that invariant here so
|
|
98
|
+
* a future provider cannot make the browser reject the whole graph payload.
|
|
99
|
+
*/
|
|
100
|
+
function normalizeInventory(scope, inventory) {
|
|
101
|
+
const prepared = inventory
|
|
102
|
+
.map((agent) => {
|
|
103
|
+
const fallbackKey = fallbackAgentKey(scope, agent.sourceRoot);
|
|
104
|
+
return {
|
|
105
|
+
agent,
|
|
106
|
+
candidateKey: safeAgentKey(agent.agentKey) ?? fallbackKey,
|
|
107
|
+
fallbackKey,
|
|
108
|
+
};
|
|
109
|
+
})
|
|
110
|
+
.sort((left, right) => left.candidateKey.localeCompare(right.candidateKey) ||
|
|
111
|
+
left.agent.sourceRoot.localeCompare(right.agent.sourceRoot) ||
|
|
112
|
+
left.agent.label.localeCompare(right.agent.label));
|
|
113
|
+
const counts = new Map();
|
|
114
|
+
for (const item of prepared) {
|
|
115
|
+
counts.set(item.candidateKey, (counts.get(item.candidateKey) ?? 0) + 1);
|
|
116
|
+
}
|
|
117
|
+
const used = new Set();
|
|
118
|
+
const duplicateKeys = new Set([...counts.entries()]
|
|
119
|
+
.filter(([, count]) => count > 1)
|
|
120
|
+
.map(([candidateKey]) => candidateKey));
|
|
121
|
+
const agents = prepared.map(({ agent, candidateKey, fallbackKey }) => {
|
|
122
|
+
const duplicate = (counts.get(candidateKey) ?? 0) > 1;
|
|
123
|
+
let agentKey = duplicate ? fallbackKey : candidateKey;
|
|
124
|
+
if (used.has(agentKey)) {
|
|
125
|
+
duplicateKeys.add(agentKey);
|
|
126
|
+
agentKey = fallbackKey;
|
|
127
|
+
}
|
|
128
|
+
const base = agentKey;
|
|
129
|
+
let suffix = 2;
|
|
130
|
+
while (used.has(agentKey)) {
|
|
131
|
+
duplicateKeys.add(base);
|
|
132
|
+
agentKey = `${base}~${suffix}`;
|
|
133
|
+
suffix += 1;
|
|
134
|
+
}
|
|
135
|
+
used.add(agentKey);
|
|
136
|
+
const resolutionAliases = [
|
|
137
|
+
...new Set([
|
|
138
|
+
...(agentKey !== candidateKey ? [candidateKey] : []),
|
|
139
|
+
...agent.resolutionAliases,
|
|
140
|
+
]
|
|
141
|
+
.map(safeAgentKey)
|
|
142
|
+
.filter((alias) => alias !== null)),
|
|
143
|
+
];
|
|
144
|
+
return {
|
|
145
|
+
...agent,
|
|
146
|
+
agentKey,
|
|
147
|
+
label: safeLabel(agent.label, agentKey),
|
|
148
|
+
resolutionAliases,
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
agents.sort((left, right) => left.agentKey.localeCompare(right.agentKey) ||
|
|
152
|
+
left.sourceRoot.localeCompare(right.sourceRoot));
|
|
153
|
+
const warnings = [];
|
|
154
|
+
for (const candidateKey of [...duplicateKeys].sort()) {
|
|
155
|
+
warnings.push({
|
|
156
|
+
code: "duplicate-agent-key",
|
|
157
|
+
agentKey: candidateKey,
|
|
158
|
+
message: `Multiple agents use ${candidateKey}; kept each with a local identity.`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return { agents, warnings };
|
|
162
|
+
}
|
|
163
|
+
export class StaticSystemGraphBuilder {
|
|
164
|
+
constructor(inventory, relationships = new CachedAgentRelationshipProvider(new SourceAgentRelationshipProvider())) {
|
|
165
|
+
this.inventory = inventory;
|
|
166
|
+
this.relationships = relationships;
|
|
167
|
+
this.callersByWorkspace = new Map();
|
|
168
|
+
}
|
|
169
|
+
async build(scope) {
|
|
170
|
+
const inventory = await this.inventory.listAgents(scope);
|
|
171
|
+
const normalized = normalizeInventory(scope, inventory.agents);
|
|
172
|
+
const agents = normalized.agents;
|
|
173
|
+
this.callersByWorkspace.set(scope.workspaceKey, agents);
|
|
174
|
+
this.retainRelationshipCallers();
|
|
175
|
+
const nodes = agents.map((agent) => ({
|
|
176
|
+
id: `agent:${agent.agentKey}`,
|
|
177
|
+
agentKey: agent.agentKey,
|
|
178
|
+
label: agent.label,
|
|
179
|
+
}));
|
|
180
|
+
const byTarget = new Map();
|
|
181
|
+
const registerTarget = (key, agent) => {
|
|
182
|
+
const candidates = byTarget.get(key) ?? [];
|
|
183
|
+
if (!candidates.some((candidate) => candidate.agentKey === agent.agentKey)) {
|
|
184
|
+
candidates.push(agent);
|
|
185
|
+
byTarget.set(key, candidates);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
for (const agent of agents) {
|
|
189
|
+
registerTarget(agent.agentKey, agent);
|
|
190
|
+
for (const alias of agent.resolutionAliases) {
|
|
191
|
+
registerTarget(alias, agent);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const edges = [];
|
|
195
|
+
const warnings = [
|
|
196
|
+
...inventory.warnings,
|
|
197
|
+
...normalized.warnings,
|
|
198
|
+
];
|
|
199
|
+
const seenEdges = new Set();
|
|
200
|
+
let relationshipsComplete = true;
|
|
201
|
+
// Source walks are independent. Run them together so first-open latency is
|
|
202
|
+
// bounded by the slowest agent tree rather than the sum of every tree.
|
|
203
|
+
const scans = await Promise.all(agents.map(async (caller) => {
|
|
204
|
+
try {
|
|
205
|
+
return {
|
|
206
|
+
caller,
|
|
207
|
+
result: await this.relationships.listRelationships(caller),
|
|
208
|
+
failed: false,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return {
|
|
213
|
+
caller,
|
|
214
|
+
result: {
|
|
215
|
+
relationships: [],
|
|
216
|
+
warnings: [],
|
|
217
|
+
},
|
|
218
|
+
failed: true,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
}));
|
|
222
|
+
for (const { caller, result, failed } of scans) {
|
|
223
|
+
if (failed) {
|
|
224
|
+
relationshipsComplete = false;
|
|
225
|
+
warnings.push({
|
|
226
|
+
code: "projection-failed",
|
|
227
|
+
agentKey: caller.agentKey,
|
|
228
|
+
message: `Could not inspect ${caller.label}.`,
|
|
229
|
+
});
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
for (const warning of result.warnings) {
|
|
233
|
+
if (warning.code === "dynamic-target") {
|
|
234
|
+
warnings.push({
|
|
235
|
+
code: "dynamic-target",
|
|
236
|
+
agentKey: caller.agentKey,
|
|
237
|
+
message: `${caller.label} has a dynamic agent target that V0 cannot resolve.`,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
for (const relationship of result.relationships) {
|
|
242
|
+
const candidates = byTarget.get(relationship.target) ?? [];
|
|
243
|
+
if (candidates.length !== 1) {
|
|
244
|
+
const target = /^[A-Za-z0-9@_.:-]+$/.test(relationship.target)
|
|
245
|
+
? relationship.target
|
|
246
|
+
: null;
|
|
247
|
+
warnings.push({
|
|
248
|
+
code: "unresolved-target",
|
|
249
|
+
agentKey: caller.agentKey,
|
|
250
|
+
message: candidates.length === 0
|
|
251
|
+
? target
|
|
252
|
+
? `${caller.label} invokes unknown agent ${target}.`
|
|
253
|
+
: `${caller.label} invokes an invalid agent target.`
|
|
254
|
+
: `${caller.label} invokes ambiguous agent ${target ?? "target"}.`,
|
|
255
|
+
});
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const target = candidates[0];
|
|
259
|
+
if (target.agentKey === caller.agentKey)
|
|
260
|
+
continue;
|
|
261
|
+
const from = `agent:${caller.agentKey}`;
|
|
262
|
+
const to = `agent:${target.agentKey}`;
|
|
263
|
+
const edgeKey = `${from}\0${to}\0${relationship.mode}`;
|
|
264
|
+
if (relationship.evidence.length > 1 || seenEdges.has(edgeKey)) {
|
|
265
|
+
warnings.push({
|
|
266
|
+
code: "duplicate-edge",
|
|
267
|
+
agentKey: caller.agentKey,
|
|
268
|
+
message: `${caller.label} invokes ${target.label} more than once.`,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
if (seenEdges.has(edgeKey))
|
|
272
|
+
continue;
|
|
273
|
+
seenEdges.add(edgeKey);
|
|
274
|
+
edges.push({
|
|
275
|
+
from,
|
|
276
|
+
to,
|
|
277
|
+
kind: "invokes",
|
|
278
|
+
basis: "static",
|
|
279
|
+
mode: relationship.mode,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
const modeOrder = { blocking: 0, async: 1 };
|
|
284
|
+
edges.sort((left, right) => left.from.localeCompare(right.from) ||
|
|
285
|
+
left.to.localeCompare(right.to) ||
|
|
286
|
+
modeOrder[left.mode] - modeOrder[right.mode]);
|
|
287
|
+
const uniqueWarnings = [
|
|
288
|
+
...new Map(warnings.map((warning) => [
|
|
289
|
+
`${warning.code}\0${warning.agentKey ?? ""}\0${warning.message}`,
|
|
290
|
+
warning,
|
|
291
|
+
])).values(),
|
|
292
|
+
].sort(warningOrder);
|
|
293
|
+
return {
|
|
294
|
+
cacheable: inventory.cacheable && relationshipsComplete,
|
|
295
|
+
graph: {
|
|
296
|
+
kind: "system",
|
|
297
|
+
scope: { kind: "working-tree", workspaceKey: scope.workspaceKey },
|
|
298
|
+
nodes,
|
|
299
|
+
edges,
|
|
300
|
+
warnings: uniqueWarnings,
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
retainWorkspaces(workspaceKeys) {
|
|
305
|
+
for (const workspaceKey of this.callersByWorkspace.keys()) {
|
|
306
|
+
if (!workspaceKeys.has(workspaceKey)) {
|
|
307
|
+
this.callersByWorkspace.delete(workspaceKey);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
this.retainRelationshipCallers();
|
|
311
|
+
}
|
|
312
|
+
retainRelationshipCallers() {
|
|
313
|
+
try {
|
|
314
|
+
this.relationships.retainCallers?.([...this.callersByWorkspace.values()].flat());
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
// Cache pruning is an optimization and cannot make projection fail.
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=system-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-graph.js","sourceRoot":"","sources":["../../src/core/system-graph.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Workflow registry (workstream W2's backend slice).
|
|
3
3
|
*
|
|
4
|
-
* Discovers orchestration projects by scanning a directory tree (bounded
|
|
5
|
-
* depth
|
|
6
|
-
*
|
|
4
|
+
* Discovers orchestration projects by scanning a directory tree (bounded by
|
|
5
|
+
* depth, by directories visited, and by the scan root's own repository) for
|
|
6
|
+
* `sapiom.json` marker files, tracks
|
|
7
|
+
* manually-connected paths, and persists the combined list to
|
|
8
|
+
* HARNESS_PATHS.workflows. Exposes an
|
|
7
9
|
* Express router implementing the /api/workflows surface from
|
|
8
10
|
* src/shared/types.ts; the integrator mounts it (and express.json()) on the
|
|
9
11
|
* shared app.
|
|
10
12
|
*/
|
|
11
13
|
import { type Router as ExpressRouter } from "express";
|
|
12
14
|
import { type WorkflowInfo } from "../shared/types.js";
|
|
15
|
+
import { AgentProjectScanBudget, type AgentProjectWalkOptions } from "./agent-project-discovery.js";
|
|
16
|
+
/** What one scan of a root turned up, and how far it can be trusted. */
|
|
17
|
+
export interface AgentProjectScanResult {
|
|
18
|
+
/** Projects discovered on this pass. */
|
|
19
|
+
found: WorkflowInfo[];
|
|
20
|
+
/** Subtrees left opaque by a transient filesystem error. */
|
|
21
|
+
unreconciledRoots: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Nested repository checkouts the walk declined to enter (see
|
|
24
|
+
* {@link isForeignRepositoryRoot}). A scan that comes back short is then able
|
|
25
|
+
* to say WHY it came back short, which is the difference between "there are
|
|
26
|
+
* no agents there" and "there is another repo there and you did not ask for
|
|
27
|
+
* it". The server logs the count on every scan.
|
|
28
|
+
*/
|
|
29
|
+
repositoryBoundaries: string[];
|
|
30
|
+
/** The traversal allowance this scan spent — `visited`, `envelopeDepth`. */
|
|
31
|
+
budget: AgentProjectScanBudget;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Scans `root` for agent projects, bounded by depth, by directories visited,
|
|
35
|
+
* AND by the repository the root belongs to (core/agent-project-discovery.ts
|
|
36
|
+
* owns that policy and the numbers behind it). A directory carrying a marker is
|
|
37
|
+
* registered and not descended into; a directory that is a repository checkout
|
|
38
|
+
* of its own is reported as a boundary and not descended into either, so one
|
|
39
|
+
* scan registers one project tree rather than every neighbouring clone.
|
|
40
|
+
*
|
|
41
|
+
* Every directory touched is confined to `root` (the tree the caller asked to
|
|
42
|
+
* scan): the walk starts at `root` itself and only ever descends into a direct
|
|
43
|
+
* child, so no crafted entry name can walk the scan outside `root` — and
|
|
44
|
+
* `resolveWithinRoot` re-asserts that at the sink, local to each fs read.
|
|
45
|
+
* Symlinked entries report `isDirectory() === false` (withFileTypes uses raw
|
|
46
|
+
* dirent info, not a followed stat) and so are never descended into either,
|
|
47
|
+
* which is what makes a symlink cycle terminate.
|
|
48
|
+
*
|
|
49
|
+
* Exported so the perf benchmark can measure the real scanner against an
|
|
50
|
+
* explicit budget rather than a copy of its traversal.
|
|
51
|
+
*/
|
|
52
|
+
export declare function scanAgentProjects(root: string, budget?: AgentProjectScanBudget, options?: AgentProjectWalkOptions): Promise<AgentProjectScanResult>;
|
|
13
53
|
export declare class WorkflowRegistry {
|
|
14
54
|
private readonly registryPath;
|
|
15
55
|
private workflows;
|
|
@@ -18,12 +58,22 @@ export declare class WorkflowRegistry {
|
|
|
18
58
|
* interleave and drop entries from the persisted file. Mirrors the pattern
|
|
19
59
|
* used by SessionManager.persist() (session-manager.ts:278,851-853). */
|
|
20
60
|
private writeQueue;
|
|
61
|
+
/** Epoch ms of the last confirmed-missing sweep — see LAZY_PRUNE_INTERVAL_MS. */
|
|
62
|
+
private lastPruneAt;
|
|
21
63
|
constructor(registryPath?: string);
|
|
22
64
|
private ensureLoaded;
|
|
23
65
|
private persist;
|
|
24
66
|
/** Chains `run` onto the write queue so concurrent mutations never
|
|
25
67
|
* interleave — a failed run never poisons later ones. */
|
|
26
68
|
private enqueue;
|
|
69
|
+
/**
|
|
70
|
+
* The registry as it stands — and the point at which stale entries actually
|
|
71
|
+
* leave. A read runs {@link prune} when one is due
|
|
72
|
+
* (LAZY_PRUNE_INTERVAL_MS), so an agent whose directory the user deleted
|
|
73
|
+
* disappears from `GET /api/workflows` on its own rather than waiting for the
|
|
74
|
+
* next server boot. Cheap by construction: one `stat` per entry, throttled,
|
|
75
|
+
* and the file is only rewritten when something was actually dropped.
|
|
76
|
+
*/
|
|
27
77
|
list(): Promise<WorkflowInfo[]>;
|
|
28
78
|
/**
|
|
29
79
|
* Drops entries whose `path` no longer exists on disk and persists the
|
|
@@ -35,12 +85,18 @@ export declare class WorkflowRegistry {
|
|
|
35
85
|
*/
|
|
36
86
|
prune(): Promise<WorkflowInfo[]>;
|
|
37
87
|
/**
|
|
88
|
+
* `budget` is overridable so a caller (and the tests that pin this rule) can
|
|
89
|
+
* scan with a narrower allowance than the shipped default; the reconciliation
|
|
90
|
+
* envelope follows whatever the scan actually managed to cover.
|
|
91
|
+
*
|
|
38
92
|
* Scans `root`, refreshes discovered projects, and removes scan-sourced rows
|
|
39
93
|
* in this scan's traversal envelope when their marker is confirmed gone or
|
|
40
|
-
* invalid. Rows beneath a temporarily unreadable directory survive this pass
|
|
41
|
-
*
|
|
94
|
+
* invalid. Rows beneath a temporarily unreadable directory survive this pass,
|
|
95
|
+
* as do rows below the depth the scan actually completed when the node budget
|
|
96
|
+
* cut it short; manually connected rows remain until their path itself is
|
|
97
|
+
* pruned.
|
|
42
98
|
*/
|
|
43
|
-
scan(root: string): Promise<WorkflowInfo[]>;
|
|
99
|
+
scan(root: string, budget?: AgentProjectScanBudget): Promise<WorkflowInfo[]>;
|
|
44
100
|
/** Registers an arbitrary path (the "+ Connect" flow); marker is optional at connect time. */
|
|
45
101
|
connectPath(inputPath: string): Promise<WorkflowInfo>;
|
|
46
102
|
}
|
|
@@ -50,9 +106,31 @@ export declare class WorkflowRegistry {
|
|
|
50
106
|
* with resolved slugs) without an unsafe cast — a missing method is then a
|
|
51
107
|
* compile error, not a runtime crash.
|
|
52
108
|
*/
|
|
109
|
+
/**
|
|
110
|
+
* What a requested scan found, AND what it deliberately declined to enter.
|
|
111
|
+
*
|
|
112
|
+
* The second half exists because the two are only honest together. A scan stops
|
|
113
|
+
* at a foreign repository root, so pointing it at a folder that is not itself a
|
|
114
|
+
* repo but holds several clones finds NOTHING while several agents sit on disk —
|
|
115
|
+
* and a UI told only `found: []` will state, in good faith, that the folder is
|
|
116
|
+
* empty and offer to create the *first* agent in it. `repositoryBoundaries`
|
|
117
|
+
* turns that false statement into the true one: these checkouts were not
|
|
118
|
+
* searched, open one as its own project.
|
|
119
|
+
*/
|
|
120
|
+
export interface WorkflowScanOutcome {
|
|
121
|
+
found: WorkflowInfo[];
|
|
122
|
+
/** Absolute paths of checkouts the walk stopped at rather than entering. */
|
|
123
|
+
repositoryBoundaries: string[];
|
|
124
|
+
}
|
|
53
125
|
export interface WorkflowRegistryLike {
|
|
54
126
|
list(): Promise<WorkflowInfo[]>;
|
|
55
127
|
scan(root: string): Promise<WorkflowInfo[]>;
|
|
128
|
+
/**
|
|
129
|
+
* The same scan, reporting the boundaries it stopped at. Optional so an
|
|
130
|
+
* embedder implementing this interface keeps compiling; the route degrades to
|
|
131
|
+
* `scan` with an empty boundary list, which is the pre-existing behaviour.
|
|
132
|
+
*/
|
|
133
|
+
scanWithBoundaries?(root: string): Promise<WorkflowScanOutcome>;
|
|
56
134
|
connectPath(inputPath: string): Promise<WorkflowInfo>;
|
|
57
135
|
}
|
|
58
136
|
export declare function createWorkflowsRouter(registry: WorkflowRegistryLike): ExpressRouter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-registry.d.ts","sourceRoot":"","sources":["../../src/core/workflow-registry.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"workflow-registry.d.ts","sourceRoot":"","sources":["../../src/core/workflow-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,EAAU,KAAK,MAAM,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAGL,sBAAsB,EAEtB,KAAK,uBAAuB,EAK7B,MAAM,8BAA8B,CAAC;AAwCtC,wEAAwE;AACxE,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,4DAA4D;IAC5D,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B;;;;;;OAMG;IACH,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,4EAA4E;IAC5E,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,sBAAqD,EAC7D,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC,CAmDjC;AA8FD,qBAAa,gBAAgB;IAUf,OAAO,CAAC,QAAQ,CAAC,YAAY;IATzC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,MAAM,CAAS;IACvB;;6EAEyE;IACzE,OAAO,CAAC,UAAU,CAAoC;IACtD,iFAAiF;IACjF,OAAO,CAAC,WAAW,CAAK;gBAEK,YAAY,GAAE,MAA4C;YAEzE,YAAY;YAWZ,OAAO;IAYrB;8DAC0D;IAC1D,OAAO,CAAC,OAAO;IASf;;;;;;;OAOG;IACG,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAarC;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IA2BtC;;;;;;;;;;;OAWG;IACG,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,sBAAqD,GAC5D,OAAO,CAAC,YAAY,EAAE,CAAC;IA0C1B,8FAA8F;IACxF,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAsB5D;AAED;;;;;GAKG;AACH;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,4EAA4E;IAC5E,oBAAoB,EAAE,MAAM,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5C;;;;OAIG;IACH,kBAAkB,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACvD;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,aAAa,CAuCnF"}
|