ndomo 0.1.0 → 0.2.1

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 (65) hide show
  1. package/.env.example +4 -0
  2. package/README.es.md +29 -23
  3. package/README.md +64 -24
  4. package/bun.lock +447 -0
  5. package/docs/configuration.md +4 -4
  6. package/docs/installation.md +53 -34
  7. package/docs/installer.md +164 -0
  8. package/docs/integrations.md +1 -1
  9. package/docs/web-ui.md +124 -0
  10. package/package.json +43 -4
  11. package/scripts/install.sh +28 -0
  12. package/scripts/smoke-install.sh +47 -0
  13. package/scripts/smoke-web.sh +335 -0
  14. package/src/cli/__tests__/install.test.ts +733 -0
  15. package/src/cli/index.ts +8 -0
  16. package/src/cli/install.ts +1273 -0
  17. package/src/config/__tests__/schema.test.ts +223 -0
  18. package/src/config/schema.ts +129 -16
  19. package/src/http/__tests__/auth.test.ts +10 -10
  20. package/src/http/__tests__/spa.test.ts +296 -0
  21. package/src/http/auth.ts +8 -1
  22. package/src/http/server.ts +71 -2
  23. package/.bun-version +0 -1
  24. package/.dockerignore +0 -79
  25. package/.editorconfig +0 -18
  26. package/.github/CODEOWNERS +0 -8
  27. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -62
  28. package/.github/ISSUE_TEMPLATE/config.yml +0 -2
  29. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -34
  30. package/.github/dependabot.yml +0 -36
  31. package/.github/pull_request_template.md +0 -24
  32. package/.github/release.yml +0 -30
  33. package/.github/workflows/gitleaks.yml +0 -28
  34. package/.github/workflows/release-please.yml +0 -27
  35. package/.github/workflows/smoke.yml +0 -29
  36. package/.husky/commit-msg +0 -1
  37. package/CHANGELOG.md +0 -114
  38. package/Dockerfile +0 -32
  39. package/bin/ndomo-analyses.ts +0 -4
  40. package/bin/ndomo-status.ts +0 -4
  41. package/biome.json +0 -57
  42. package/commitlint.config.js +0 -3
  43. package/opencode.json +0 -5
  44. package/release-please-config.json +0 -11
  45. package/scripts/dev-bust-cache.sh +0 -164
  46. package/scripts/smoke-e2e.ts +0 -704
  47. package/scripts/smoke-hot.ts +0 -417
  48. package/scripts/smoke-v4.ts +0 -256
  49. package/scripts/smoke-v5.ts +0 -397
  50. package/scripts/uninstall.sh +0 -224
  51. package/src/index.ts +0 -37
  52. package/src/lib.ts +0 -65
  53. package/src/mem/scoped.ts +0 -65
  54. package/src/orchestrator/background.test.ts +0 -268
  55. package/src/orchestrator/background.ts +0 -293
  56. package/src/orchestrator/memory-hook.ts +0 -182
  57. package/src/orchestrator/reconciler.ts +0 -123
  58. package/src/orchestrator/scheduler.test.ts +0 -300
  59. package/src/orchestrator/scheduler.ts +0 -243
  60. package/src/plugin.test.ts +0 -2574
  61. package/src/plugin.ts +0 -1690
  62. package/src/worktrees/manager.ts +0 -236
  63. package/src/worktrees/state.ts +0 -87
  64. package/tests/integration/ranger-flow.test.ts +0 -257
  65. package/tsconfig.json +0 -31
@@ -1,243 +0,0 @@
1
- /**
2
- * Agent routing logic for the ndomo orchestrator.
3
- * Pure functions that determine which specialist agent handles a task.
4
- */
5
-
6
- /** Decision returned by the scheduler after routing a task. */
7
- export interface RoutingDecision {
8
- /** Target agent identifier (e.g. "scout", "go-smith", "sage"). */
9
- agent: string;
10
- /** Human-readable reason for the routing choice. */
11
- reason: string;
12
- /** Whether this task can run alongside other parallel tasks. */
13
- parallel: boolean;
14
- /** Task IDs that must complete before this one starts. */
15
- dependencies: string[];
16
- /** Agent that should review output before merge (advisory, not blocking). */
17
- requiresReview?: string;
18
- }
19
-
20
- /** Incoming task request from the foreman. */
21
- export interface TaskRequest {
22
- /** Natural language description of what to do. */
23
- description: string;
24
- /** Detected or declared tech stack. */
25
- stack?: "go" | "vue" | "js" | "python" | "zig" | "generic" | "unknown";
26
- /** Category of work. */
27
- type: "implement" | "explore" | "research" | "design" | "debug" | "audit" | "document" | "debate";
28
- /** Files targeted by this task (for conflict detection). */
29
- files?: string[];
30
- /** Risk assessment from the foreman. */
31
- risk: "low" | "medium" | "high";
32
- }
33
-
34
- /** Maps known tech stacks to their specialist agent IDs. */
35
- const STACK_AGENTS: Record<string, string> = {
36
- go: "go-smith",
37
- vue: "vue-smith",
38
- js: "js-smith",
39
- python: "python-smith",
40
- zig: "zig-smith",
41
- };
42
-
43
- /**
44
- * Route a task to the appropriate specialist agent.
45
- *
46
- * Priority order:
47
- * 1. Explore → scout
48
- * 2. Research → scribe
49
- * 3. Design + vue stack → painter
50
- * 4. Audit → inspector
51
- * 5. Document → chronicler
52
- * 6. Debate → guild
53
- * 7. Debug + high risk → sage
54
- * 8. Implement + known stack → stack-smith
55
- * 9. Implement + generic/unknown → smith
56
- * 10. High risk + implement → sage (advisory) + stack-smith
57
- * 11. Default → smith
58
- */
59
- export function routeTask(task: TaskRequest): RoutingDecision {
60
- const { type, stack, risk } = task;
61
-
62
- // 1. Explore → scout
63
- if (type === "explore") {
64
- return {
65
- agent: "scout",
66
- reason: "Exploration task delegated to scout for codebase reconnaissance.",
67
- parallel: true,
68
- dependencies: [],
69
- };
70
- }
71
-
72
- // 2. Research → scribe
73
- if (type === "research") {
74
- return {
75
- agent: "scribe",
76
- reason: "Research task delegated to scribe for documentation and investigation.",
77
- parallel: true,
78
- dependencies: [],
79
- };
80
- }
81
-
82
- // 3. Design + vue → painter
83
- if (type === "design" && stack === "vue") {
84
- return {
85
- agent: "painter",
86
- reason: "Vue design task delegated to painter for UI/UX composition.",
87
- parallel: true,
88
- dependencies: [],
89
- };
90
- }
91
-
92
- // 4. Audit → inspector
93
- if (type === "audit") {
94
- return {
95
- agent: "inspector",
96
- reason: "Audit task delegated to inspector for code quality review.",
97
- parallel: true,
98
- dependencies: [],
99
- };
100
- }
101
-
102
- // 5. Document → chronicler
103
- if (type === "document") {
104
- return {
105
- agent: "chronicler",
106
- reason: "Documentation task delegated to chronicler.",
107
- parallel: true,
108
- dependencies: [],
109
- };
110
- }
111
-
112
- // 6. Debate → guild
113
- if (type === "debate") {
114
- return {
115
- agent: "guild",
116
- reason: "Debate task delegated to guild for multi-perspective analysis.",
117
- parallel: false,
118
- dependencies: [],
119
- };
120
- }
121
-
122
- // 7. Debug + high risk → sage
123
- if (type === "debug" && risk === "high") {
124
- return {
125
- agent: "sage",
126
- reason: "High-risk debug task escalated to sage for careful analysis.",
127
- parallel: false,
128
- dependencies: [],
129
- };
130
- }
131
-
132
- // 8. Implement + known stack → stack-smith
133
- if (type === "implement" && stack && stack in STACK_AGENTS) {
134
- const stackAgent = STACK_AGENTS[stack];
135
- if (!stackAgent) {
136
- // Should never happen due to the check above, but satisfies strict nulls
137
- return {
138
- agent: "smith",
139
- reason: "Stack lookup failed, falling back to generic smith.",
140
- parallel: true,
141
- dependencies: [],
142
- };
143
- }
144
-
145
- // 10. High risk implement → sage advisory + stack-smith
146
- if (risk === "high") {
147
- return {
148
- agent: stackAgent,
149
- reason: `High-risk ${stack} implementation. Sage should review before merge.`,
150
- parallel: true,
151
- dependencies: [],
152
- requiresReview: "sage",
153
- };
154
- }
155
-
156
- return {
157
- agent: stackAgent,
158
- reason: `${stack} implementation delegated to ${stackAgent}.`,
159
- parallel: true,
160
- dependencies: [],
161
- };
162
- }
163
-
164
- // 9. Implement + generic/unknown → smith
165
- if (type === "implement") {
166
- return {
167
- agent: "smith",
168
- reason: "Generic implementation task delegated to smith.",
169
- parallel: true,
170
- dependencies: [],
171
- };
172
- }
173
-
174
- // 11. Default → smith
175
- return {
176
- agent: "smith",
177
- reason: "No specific routing rule matched, defaulting to smith.",
178
- parallel: true,
179
- dependencies: [],
180
- };
181
- }
182
-
183
- /**
184
- * A routing decision paired with its task ID, used for parallel conflict checks.
185
- */
186
- export interface RoutedTask {
187
- /** Unique task identifier. */
188
- id: string;
189
- /** The routing decision for this task. */
190
- decision: RoutingDecision;
191
- }
192
-
193
- /**
194
- * Check if a set of tasks can run in parallel without file conflicts.
195
- *
196
- * Two tasks conflict when:
197
- * - They target the same file (write race).
198
- * - One task's dependency ID matches another task in the batch (ordering violation).
199
- *
200
- * Tasks with no explicit file list are assumed non-conflicting (unknown paths,
201
- * benefit of the doubt).
202
- *
203
- * Accepts either:
204
- * - `RoutedTask[]` (preferred) — checks task ID dependencies.
205
- * - `RoutingDecision[]` (legacy) — checks agent-name dependencies.
206
- *
207
- * @param tasks - Array of routed tasks or routing decisions to evaluate.
208
- * @returns `true` if no two tasks share a target file or have inter-batch dependencies.
209
- */
210
- export function canRunParallel(tasks: RoutedTask[] | RoutingDecision[]): boolean {
211
- if (tasks.length === 0) return true;
212
-
213
- // Detect shape: RoutedTask has `id` + `decision`, RoutingDecision has `agent` + `parallel`
214
- const isRoutedTask = (t: unknown): t is RoutedTask =>
215
- typeof t === "object" && t !== null && "id" in t && "decision" in t;
216
-
217
- if (isRoutedTask(tasks[0])) {
218
- const routed = tasks as RoutedTask[];
219
- const allParallel = routed.every((t) => t.decision.parallel);
220
- if (!allParallel) return false;
221
-
222
- const taskIds = new Set(routed.map((t) => t.id));
223
- for (const task of routed) {
224
- for (const dep of task.decision.dependencies) {
225
- if (taskIds.has(dep)) return false;
226
- }
227
- }
228
- return true;
229
- }
230
-
231
- // Legacy path: RoutingDecision[] — dependencies are agent names
232
- const decisions = tasks as RoutingDecision[];
233
- const allParallel = decisions.every((t) => t.parallel);
234
- if (!allParallel) return false;
235
-
236
- const taskAgents = new Set(decisions.map((t) => t.agent));
237
- for (const task of decisions) {
238
- for (const dep of task.dependencies) {
239
- if (taskAgents.has(dep)) return false;
240
- }
241
- }
242
- return true;
243
- }