nomoreide 0.1.56 → 0.1.57

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.
@@ -0,0 +1,143 @@
1
+ /** Thrown by {@link resolveStartOrder} when the requested set contains a cycle. */
2
+ export class DependencyCycleError extends Error {
3
+ cycle;
4
+ constructor(cycle) {
5
+ super(`Service dependency cycle detected: ${cycle.join(" → ")}.`);
6
+ this.name = "DependencyCycleError";
7
+ this.cycle = cycle;
8
+ }
9
+ }
10
+ /** Build the full graph for every registered service (used by the UI panel). */
11
+ export function buildServiceGraph(services) {
12
+ const registered = new Set(services.map((service) => service.name));
13
+ const nodes = services.map((service) => {
14
+ const declared = dedupe(service.dependsOn ?? []).filter((dep) => dep !== service.name);
15
+ return {
16
+ name: service.name,
17
+ dependsOn: declared.filter((dep) => registered.has(dep)),
18
+ missing: declared.filter((dep) => !registered.has(dep)),
19
+ };
20
+ });
21
+ const edges = nodes.flatMap((node) => node.dependsOn.map((to) => ({ from: node.name, to })));
22
+ const { order, cycles } = topoSort(nodes);
23
+ return { nodes, edges, order, cycles };
24
+ }
25
+ /**
26
+ * Resolve the start order for `requested` services, expanding to include any
27
+ * transitive dependencies that are also registered. Deps come before the
28
+ * services that need them. Throws {@link DependencyCycleError} if the expanded
29
+ * set contains a cycle. Unknown deps are silently skipped (they surface in the
30
+ * UI graph instead — a missing dependency shouldn't block a manual bundle run).
31
+ */
32
+ export function resolveStartOrder(services, requested) {
33
+ const byName = new Map(services.map((service) => [service.name, service]));
34
+ const wanted = new Set();
35
+ const visit = (name) => {
36
+ if (wanted.has(name))
37
+ return;
38
+ const service = byName.get(name);
39
+ if (!service)
40
+ return; // not registered → caller handles the error on start
41
+ wanted.add(name);
42
+ for (const dep of service.dependsOn ?? []) {
43
+ if (dep !== name)
44
+ visit(dep);
45
+ }
46
+ };
47
+ for (const name of requested)
48
+ visit(name);
49
+ const subset = buildServiceGraph(services.filter((service) => wanted.has(service.name)));
50
+ if (subset.cycles.length > 0) {
51
+ throw new DependencyCycleError(subset.cycles[0]);
52
+ }
53
+ return subset.order;
54
+ }
55
+ function dedupe(values) {
56
+ return [...new Set(values)];
57
+ }
58
+ /**
59
+ * Kahn's algorithm. Returns the topological `order` and, for any nodes left
60
+ * unsorted (i.e. inside a cycle), the distinct `cycles` extracted via DFS.
61
+ */
62
+ function topoSort(nodes) {
63
+ const inDegree = new Map();
64
+ const dependents = new Map();
65
+ for (const node of nodes) {
66
+ inDegree.set(node.name, 0);
67
+ dependents.set(node.name, []);
68
+ }
69
+ for (const node of nodes) {
70
+ for (const dep of node.dependsOn) {
71
+ // dep must run before node → edge dep -> node.
72
+ inDegree.set(node.name, (inDegree.get(node.name) ?? 0) + 1);
73
+ dependents.get(dep)?.push(node.name);
74
+ }
75
+ }
76
+ const queue = nodes.filter((node) => inDegree.get(node.name) === 0).map((node) => node.name);
77
+ const order = [];
78
+ while (queue.length > 0) {
79
+ const name = queue.shift();
80
+ order.push(name);
81
+ for (const next of dependents.get(name) ?? []) {
82
+ const remaining = (inDegree.get(next) ?? 0) - 1;
83
+ inDegree.set(next, remaining);
84
+ if (remaining === 0)
85
+ queue.push(next);
86
+ }
87
+ }
88
+ if (order.length === nodes.length) {
89
+ return { order, cycles: [] };
90
+ }
91
+ // Nodes not emitted are part of one or more cycles. A topo sort can't order
92
+ // them, so callers should treat `order` as invalid when `cycles` is non-empty.
93
+ const stuck = new Set(nodes.map((node) => node.name).filter((name) => !order.includes(name)));
94
+ return { order: [], cycles: findCycles(nodes, stuck) };
95
+ }
96
+ /** DFS over the unsorted nodes to extract concrete cycle paths for display. */
97
+ function findCycles(nodes, stuck) {
98
+ const depMap = new Map(nodes.map((node) => [node.name, node.dependsOn]));
99
+ const cycles = [];
100
+ const seen = new Set();
101
+ const stack = [];
102
+ const onStack = new Set();
103
+ const dfs = (name) => {
104
+ if (!stuck.has(name))
105
+ return;
106
+ stack.push(name);
107
+ onStack.add(name);
108
+ for (const dep of depMap.get(name) ?? []) {
109
+ if (!stuck.has(dep))
110
+ continue;
111
+ if (onStack.has(dep)) {
112
+ const start = stack.indexOf(dep);
113
+ if (start !== -1)
114
+ cycles.push(stack.slice(start));
115
+ }
116
+ else if (!seen.has(dep)) {
117
+ dfs(dep);
118
+ }
119
+ }
120
+ stack.pop();
121
+ onStack.delete(name);
122
+ seen.add(name);
123
+ };
124
+ for (const name of stuck) {
125
+ if (!seen.has(name))
126
+ dfs(name);
127
+ }
128
+ return dedupeCycles(cycles);
129
+ }
130
+ /** Collapse rotations/duplicates so the same cycle is reported once. */
131
+ function dedupeCycles(cycles) {
132
+ const seen = new Set();
133
+ const result = [];
134
+ for (const cycle of cycles) {
135
+ const key = [...cycle].sort().join("|");
136
+ if (seen.has(key))
137
+ continue;
138
+ seen.add(key);
139
+ result.push(cycle);
140
+ }
141
+ return result;
142
+ }
143
+ //# sourceMappingURL=service-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-graph.js","sourceRoot":"","sources":["../../src/core/service-graph.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,11 @@ export interface ServiceDefinition {
9
9
  description?: string;
10
10
  /** Test Runner command; defaults to `npm test` when absent. */
11
11
  test?: string;
12
+ /**
13
+ * Names of services that must be started (and healthy) before this one, used
14
+ * to order `startBundle`. Self/unknown references are ignored at start time.
15
+ */
16
+ dependsOn?: string[];
12
17
  command?: string;
13
18
  cwd?: string;
14
19
  env?: Record<string, string>;
@@ -116,6 +121,11 @@ export interface NoMoreIdeConfig {
116
121
  githubTokens: GitHubToken[];
117
122
  /** User-saved git/GitHub workflows (forks/edits of the built-in templates). */
118
123
  workflows: Workflow[];
124
+ /**
125
+ * Which CLI the in-dock agent chat drives. Undefined = never chosen → fall
126
+ * back to startup-agent detection.
127
+ */
128
+ chatProvider?: "claude" | "codex";
119
129
  }
120
130
  export type ServiceState = "stopped" | "starting" | "running" | "exited";
121
131
  export interface ServiceStatus {