@sapiom/harness 0.8.9 → 0.9.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +11 -1
  3. package/dist/core/agent-project-discovery.d.ts +235 -1
  4. package/dist/core/agent-project-discovery.d.ts.map +1 -1
  5. package/dist/core/agent-project-discovery.js +303 -1
  6. package/dist/core/agent-project-discovery.js.map +1 -1
  7. package/dist/core/canvas-interconnections.d.ts +31 -0
  8. package/dist/core/canvas-interconnections.d.ts.map +1 -1
  9. package/dist/core/canvas-interconnections.js +294 -21
  10. package/dist/core/canvas-interconnections.js.map +1 -1
  11. package/dist/core/canvas-render.d.ts +32 -0
  12. package/dist/core/canvas-render.d.ts.map +1 -1
  13. package/dist/core/canvas-render.js +50 -41
  14. package/dist/core/canvas-render.js.map +1 -1
  15. package/dist/core/definition-name.d.ts +12 -0
  16. package/dist/core/definition-name.d.ts.map +1 -1
  17. package/dist/core/definition-name.js +14 -5
  18. package/dist/core/definition-name.js.map +1 -1
  19. package/dist/core/system-graph-inventory.d.ts +68 -0
  20. package/dist/core/system-graph-inventory.d.ts.map +1 -0
  21. package/dist/core/system-graph-inventory.js +312 -0
  22. package/dist/core/system-graph-inventory.js.map +1 -0
  23. package/dist/core/system-graph-relationships.d.ts +41 -0
  24. package/dist/core/system-graph-relationships.d.ts.map +1 -0
  25. package/dist/core/system-graph-relationships.js +98 -0
  26. package/dist/core/system-graph-relationships.js.map +1 -0
  27. package/dist/core/system-graph-store.d.ts +45 -0
  28. package/dist/core/system-graph-store.d.ts.map +1 -0
  29. package/dist/core/system-graph-store.js +222 -0
  30. package/dist/core/system-graph-store.js.map +1 -0
  31. package/dist/core/system-graph-watcher.d.ts +51 -0
  32. package/dist/core/system-graph-watcher.d.ts.map +1 -0
  33. package/dist/core/system-graph-watcher.js +448 -0
  34. package/dist/core/system-graph-watcher.js.map +1 -0
  35. package/dist/core/system-graph.d.ts +43 -0
  36. package/dist/core/system-graph.d.ts.map +1 -0
  37. package/dist/core/system-graph.js +321 -0
  38. package/dist/core/system-graph.js.map +1 -0
  39. package/dist/core/workflow-registry.d.ts +84 -6
  40. package/dist/core/workflow-registry.d.ts.map +1 -1
  41. package/dist/core/workflow-registry.js +191 -91
  42. package/dist/core/workflow-registry.js.map +1 -1
  43. package/dist/core/workspace-watcher.d.ts +21 -13
  44. package/dist/core/workspace-watcher.d.ts.map +1 -1
  45. package/dist/core/workspace-watcher.js +79 -81
  46. package/dist/core/workspace-watcher.js.map +1 -1
  47. package/dist/index.d.ts +1 -0
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/server/agent-move.d.ts +134 -0
  51. package/dist/server/agent-move.d.ts.map +1 -0
  52. package/dist/server/agent-move.js +343 -0
  53. package/dist/server/agent-move.js.map +1 -0
  54. package/dist/server/index.d.ts.map +1 -1
  55. package/dist/server/index.js +275 -22
  56. package/dist/server/index.js.map +1 -1
  57. package/dist/server/rest.d.ts +3 -0
  58. package/dist/server/rest.d.ts.map +1 -1
  59. package/dist/server/rest.js +3 -0
  60. package/dist/server/rest.js.map +1 -1
  61. package/dist/server/studio-rail.d.ts +76 -0
  62. package/dist/server/studio-rail.d.ts.map +1 -0
  63. package/dist/server/studio-rail.js +234 -0
  64. package/dist/server/studio-rail.js.map +1 -0
  65. package/dist/server/system-graph.d.ts +14 -0
  66. package/dist/server/system-graph.d.ts.map +1 -0
  67. package/dist/server/system-graph.js +40 -0
  68. package/dist/server/system-graph.js.map +1 -0
  69. package/dist/server/workflow-graph.d.ts +43 -0
  70. package/dist/server/workflow-graph.d.ts.map +1 -0
  71. package/dist/server/workflow-graph.js +200 -0
  72. package/dist/server/workflow-graph.js.map +1 -0
  73. package/dist/shared/system-graph.d.ts +59 -0
  74. package/dist/shared/system-graph.d.ts.map +1 -0
  75. package/dist/shared/system-graph.js +76 -0
  76. package/dist/shared/system-graph.js.map +1 -0
  77. package/dist/shared/types.d.ts +45 -0
  78. package/dist/shared/types.d.ts.map +1 -1
  79. package/dist/shared/types.js.map +1 -1
  80. package/dist/web/assets/index-2Fab6dzf.js +508 -0
  81. package/dist/web/assets/index-D0doaFvT.css +32 -0
  82. package/dist/web/index.html +2 -2
  83. package/package.json +5 -5
  84. package/dist/web/assets/index-B18B2y5o.js +0 -494
  85. 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) for `sapiom.json` marker files, tracks manually-connected paths,
6
- * and persists the combined list to HARNESS_PATHS.workflows. Exposes an
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
- * manually connected rows remain until their path itself is pruned.
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;;;;;;;;;GASG;AAKH,OAAO,EAAU,KAAK,MAAM,IAAI,aAAa,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiJtE,qBAAa,gBAAgB;IAQf,OAAO,CAAC,QAAQ,CAAC,YAAY;IAPzC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,MAAM,CAAS;IACvB;;6EAEyE;IACzE,OAAO,CAAC,UAAU,CAAoC;gBAEzB,YAAY,GAAE,MAA4C;YAEzE,YAAY;YAWZ,OAAO;IAYrB;8DAC0D;IAC1D,OAAO,CAAC,OAAO;IAST,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAKrC;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAuBtC;;;;;OAKG;IACG,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IA+BjD,8FAA8F;IACxF,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAsB5D;AAED;;;;;GAKG;AACH,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,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACvD;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,aAAa,CAkCnF"}
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"}