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,397 +0,0 @@
1
- /**
2
- * ndomo v5 migration smoke test.
3
- *
4
- * Verifies soft delete + auto-archive functionality:
5
- * 1. Create plan + 2 tasks + 1 session, mark completed → auto-archive fires
6
- * 2. listPlans() (default) excludes archived plan
7
- * 3. listPlans({ includeArchived: true }) includes archived plan
8
- * 4. searchPlans() (default) excludes archived plan
9
- * 5. Markdown file exists, >500 bytes, contains title/tasks/sessions
10
- * 6. plan_tasks.archived_at set for both tasks
11
- * 7. sessions.archived_at set for the session
12
- * 8. Re-archive throws "already archived"
13
- * 9. searchPlans returns results ordered by rank (FTS5 relevance)
14
- * 10. nextTaskForAgent skips archived tasks by default
15
- * 11. findPlansByCategory excludes archived by default
16
- * 12. plan_progress view excludes archived tasks from counts
17
- *
18
- * Usage: bun run scripts/smoke-v5.ts
19
- */
20
-
21
- import { Database } from "bun:sqlite";
22
- import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
23
- import { tmpdir } from "node:os";
24
- import { join } from "node:path";
25
- import { runMigrations } from "../src/db/migrations.ts";
26
- import { archivePlan } from "../src/db/plan-archive.ts";
27
- import {
28
- createPlan,
29
- findPlansByCategory,
30
- getPlanProgress,
31
- listPlans,
32
- searchPlans,
33
- } from "../src/db/plans.ts";
34
- import { startSession } from "../src/db/sessions.ts";
35
- import { createTasksBatch, listTasksByPlan, nextTaskForAgent } from "../src/db/tasks.ts";
36
- import type { Plan } from "../src/db/types.ts";
37
-
38
- let pass = 0;
39
- let fail = 0;
40
-
41
- function assert(cond: boolean, msg: string): void {
42
- if (cond) {
43
- pass++;
44
- console.log(` ✓ ${msg}`);
45
- } else {
46
- fail++;
47
- console.error(` ✗ ${msg}`);
48
- }
49
- }
50
-
51
- function assertThrows(fn: () => void, expectedMsg: string, msg: string): void {
52
- try {
53
- fn();
54
- fail++;
55
- console.error(` ✗ ${msg} (expected error, got none)`);
56
- } catch (err) {
57
- const errMsg = err instanceof Error ? err.message : String(err);
58
- if (errMsg.includes(expectedMsg)) {
59
- pass++;
60
- console.log(` ✓ ${msg}`);
61
- } else {
62
- fail++;
63
- console.error(` ✗ ${msg} (expected '${expectedMsg}', got '${errMsg}')`);
64
- }
65
- }
66
- }
67
-
68
- const PLAN_DEFAULTS = {
69
- title: "Test",
70
- status: "draft" as const,
71
- priority: 3,
72
- overview: "test",
73
- complexity: 3,
74
- createdBy: "smoke",
75
- updatedBy: "smoke",
76
- metadata: {},
77
- approvedAt: null,
78
- completedAt: null,
79
- sessionId: null,
80
- approach: "Test approach for smoke validation",
81
- sourceSessionId: null,
82
- sourceMessageId: null,
83
- category: null as Plan["category"],
84
- archivedAt: null,
85
- };
86
-
87
- const TASK_DEFAULTS = {
88
- agent: "smoke",
89
- files: [] as string[],
90
- complexity: 3,
91
- createdBy: "smoke",
92
- updatedBy: "smoke",
93
- sourceSessionId: null,
94
- sourceMessageId: null,
95
- reviewedBy: null,
96
- tokensUsed: null,
97
- durationMs: null,
98
- artifacts: [] as string[],
99
- dependencies: [] as string[],
100
- metadata: {},
101
- };
102
-
103
- // Use in-memory DB + temp dir for isolated smoke test
104
- const db = new Database(":memory:");
105
- db.exec("PRAGMA journal_mode = WAL");
106
- db.exec("PRAGMA foreign_keys = ON");
107
-
108
- const testMemDir = join(tmpdir(), `ndomo-smoke-v5-${Date.now()}`);
109
- mkdirSync(testMemDir, { recursive: true });
110
-
111
- console.log("ndomo v5 smoke test\n");
112
-
113
- // ── Run migrations ──────────────────────────────────────────────────────────
114
- console.log("Running migrations v1→v5...");
115
- runMigrations(db);
116
- const ver = db.query("SELECT MAX(version) as v FROM schema_version").get() as { v: number };
117
- assert(ver.v === 5, "schema_version = 5");
118
-
119
- // Verify archived_at columns exist
120
- const planCols = db.query("PRAGMA table_info(plans)").all() as Array<{ name: string }>;
121
- assert(
122
- planCols.some((c) => c.name === "archived_at"),
123
- "plans.archived_at column exists",
124
- );
125
-
126
- // ── Test 1: Create plan + tasks + session, archive via function ─────────────
127
- console.log("\nTest 1: Create plan + 2 tasks + 1 session, archive");
128
-
129
- const planOverrides = {
130
- id: "archive-test",
131
- slug: "archive-test-plan",
132
- title: "Archive Test Plan",
133
- overview: "A plan for testing the archive flow with tasks and sessions",
134
- };
135
-
136
- createPlan(db, {
137
- ...PLAN_DEFAULTS,
138
- ...planOverrides,
139
- status: "draft" as const,
140
- });
141
-
142
- createTasksBatch(db, "archive-test", [
143
- { ...TASK_DEFAULTS, description: "Implement feature A", orderIndex: 0 },
144
- { ...TASK_DEFAULTS, description: "Write tests for A", orderIndex: 1 },
145
- ]);
146
-
147
- startSession(db, {
148
- id: "session-archive-test",
149
- goal: "Build feature A",
150
- planId: "archive-test",
151
- });
152
-
153
- // Archive the plan
154
- const result = archivePlan(db, "archive-test", { memDir: testMemDir });
155
- assert(result.planId === "archive-test", `archivePlan returned planId=${result.planId}`);
156
- assert(result.tasksCount === 2, `archivePlan tasksCount=${result.tasksCount}`);
157
- assert(result.sessionsCount === 1, `archivePlan sessionsCount=${result.sessionsCount}`);
158
- assert(result.filePath.startsWith(testMemDir), `filePath in testMemDir: ${result.filePath}`);
159
-
160
- // ── Test 2: listPlans() default excludes archived ───────────────────────────
161
- console.log("\nTest 2: listPlans() excludes archived by default");
162
-
163
- // Create another active plan to ensure listPlans still returns it
164
- createPlan(db, {
165
- ...PLAN_DEFAULTS,
166
- id: "active-plan",
167
- slug: "active-plan",
168
- title: "Active Plan",
169
- });
170
-
171
- const activePlans = listPlans(db);
172
- assert(
173
- activePlans.every((p) => p.archivedAt === null),
174
- "listPlans() returns only active plans (archived_at IS NULL)",
175
- );
176
- assert(
177
- !activePlans.some((p) => p.id === "archive-test"),
178
- "listPlans() does NOT include archived plan",
179
- );
180
-
181
- // ── Test 3: listPlans({ includeArchived: true }) includes archived ──────────
182
- console.log("\nTest 3: listPlans({ includeArchived: true }) includes archived");
183
-
184
- const allPlans = listPlans(db, { includeArchived: true });
185
- assert(
186
- allPlans.some((p) => p.id === "archive-test"),
187
- "listPlans({ includeArchived: true }) includes archived plan",
188
- );
189
-
190
- // ── Test 4: searchPlans() excludes archived ─────────────────────────────────
191
- console.log("\nTest 4: searchPlans() excludes archived by default");
192
-
193
- // FTS search for a word from the archived plan's title
194
- const searchResults = searchPlans(db, "archive");
195
- assert(
196
- !searchResults.some((p) => p.id === "archive-test"),
197
- "searchPlans() does NOT find archived plan",
198
- );
199
-
200
- // ── Test 5: Markdown file validation ────────────────────────────────────────
201
- console.log("\nTest 5: Markdown file exists and is valid");
202
-
203
- const mdFile = result.filePath;
204
- assert(existsSync(mdFile), `markdown file exists: ${mdFile}`);
205
-
206
- const mdContent = readFileSync(mdFile, "utf-8");
207
- assert(mdContent.length > 500, `markdown > 500 bytes: ${mdContent.length} bytes`);
208
- assert(
209
- mdContent.includes("# Plan: Archive Test Plan"),
210
- "markdown contains '# Plan: Archive Test Plan'",
211
- );
212
- assert(mdContent.includes("Implement feature A"), "markdown contains task 1 description");
213
- assert(mdContent.includes("Write tests for A"), "markdown contains task 2 description");
214
- assert(mdContent.includes("session-"), "markdown contains session ID prefix");
215
-
216
- // ── Test 6: plan_tasks.archived_at set ──────────────────────────────────────
217
- console.log("\nTest 6: plan_tasks.archived_at is set");
218
-
219
- const archivedTasks = listTasksByPlan(db, "archive-test", { includeArchived: true });
220
- assert(
221
- archivedTasks.length === 2 && archivedTasks.every((t) => t.archivedAt !== null),
222
- "both tasks have archived_at set",
223
- );
224
-
225
- // ── Test 7: sessions.archived_at set ────────────────────────────────────────
226
- console.log("\nTest 7: sessions.archived_at is set");
227
-
228
- const archivedSession = db
229
- .query("SELECT archived_at FROM sessions WHERE id = ?")
230
- .get("session-archive-test") as { archived_at: number | null } | null;
231
- assert(
232
- archivedSession !== null && archivedSession.archived_at !== null,
233
- "session.archived_at is set",
234
- );
235
-
236
- // ── Test 8: Re-archive throws "already archived" ────────────────────────────
237
- console.log("\nTest 8: Re-archive throws 'already archived'");
238
-
239
- assertThrows(
240
- () => archivePlan(db, "archive-test", { memDir: testMemDir }),
241
- "already archived",
242
- "re-archive throws 'ndomo: plan already archived'",
243
- );
244
-
245
- // ── Test 9: searchPlans returns results ordered by rank ─────────────────────
246
- console.log("\nTest 9: searchPlans returns results ordered by rank (FTS5 relevance)");
247
-
248
- // Create 3 plans with different match-strength keywords
249
- createPlan(db, {
250
- ...PLAN_DEFAULTS,
251
- id: "rank-1",
252
- slug: "rank-test-1",
253
- title: "Database migration tool",
254
- overview: "A tool for running database migration automatically",
255
- });
256
-
257
- createPlan(db, {
258
- ...PLAN_DEFAULTS,
259
- id: "rank-2",
260
- slug: "rank-test-2",
261
- title: "Migration helper",
262
- overview: "A helper utility for migration tasks in the database layer",
263
- });
264
-
265
- createPlan(db, {
266
- ...PLAN_DEFAULTS,
267
- id: "rank-3",
268
- slug: "rank-test-3",
269
- title: "Simple utility",
270
- overview: "A basic utility for common tasks",
271
- });
272
-
273
- // Search for "database" — rank-1 and rank-2 should match, rank-1 has it in title
274
- const rankResults = searchPlans(db, "database", 10);
275
- assert(rankResults.length >= 2, `searchPlans found ${rankResults.length} results for "database"`);
276
- if (rankResults[0] && rankResults.length >= 2) {
277
- // rank-1 has "Database" in title (higher rank), should be first
278
- assert(
279
- rankResults[0].id === "rank-1",
280
- `searchPlans rank: rank-1 is first (got ${rankResults[0].id})`,
281
- );
282
- }
283
-
284
- // ── Test 10: nextTaskForAgent skips archived tasks ──────────────────────────
285
- console.log("\nTest 10: nextTaskForAgent skips archived tasks by default");
286
-
287
- // Create a plan with tasks, then archive it
288
- createPlan(db, {
289
- ...PLAN_DEFAULTS,
290
- id: "agent-archived-plan",
291
- slug: "agent-archived-plan",
292
- title: "Agent Archived Plan",
293
- });
294
-
295
- createTasksBatch(db, "agent-archived-plan", [
296
- { ...TASK_DEFAULTS, description: "Task for archived plan", orderIndex: 0, agent: "test-agent" },
297
- ]);
298
-
299
- // Archive the plan (this archives tasks too)
300
- archivePlan(db, "agent-archived-plan", { memDir: testMemDir });
301
-
302
- // nextTaskForAgent should NOT return archived task
303
- const archivedTask = nextTaskForAgent(db, "test-agent");
304
- assert(
305
- archivedTask === null,
306
- "nextTaskForAgent returns null for archived task (default includeArchived=false)",
307
- );
308
-
309
- // With includeArchived: true, should return the task
310
- const archivedTaskIncluded = nextTaskForAgent(db, "test-agent", { includeArchived: true });
311
- assert(
312
- archivedTaskIncluded !== null && archivedTaskIncluded.planId === "agent-archived-plan",
313
- "nextTaskForAgent with includeArchived=true returns archived task",
314
- );
315
-
316
- // ── Test 11: findPlansByCategory excludes archived by default ───────────────
317
- console.log("\nTest 11: findPlansByCategory excludes archived by default");
318
-
319
- // Create a plan with category, then archive it
320
- createPlan(db, {
321
- ...PLAN_DEFAULTS,
322
- id: "cat-archived-plan",
323
- slug: "cat-archived-plan",
324
- title: "Category Archived Plan",
325
- category: "feature",
326
- });
327
-
328
- archivePlan(db, "cat-archived-plan", { memDir: testMemDir });
329
-
330
- // Create an active plan with same category
331
- createPlan(db, {
332
- ...PLAN_DEFAULTS,
333
- id: "cat-active-plan",
334
- slug: "cat-active-plan",
335
- title: "Category Active Plan",
336
- category: "feature",
337
- });
338
-
339
- const catResults = findPlansByCategory(db, "feature");
340
- assert(
341
- !catResults.some((p) => p.id === "cat-archived-plan"),
342
- "findPlansByCategory default excludes archived plan",
343
- );
344
- assert(
345
- catResults.some((p) => p.id === "cat-active-plan"),
346
- "findPlansByCategory default includes active plan",
347
- );
348
-
349
- const catResultsAll = findPlansByCategory(db, "feature", 20, { includeArchived: true });
350
- assert(
351
- catResultsAll.some((p) => p.id === "cat-archived-plan"),
352
- "findPlansByCategory with includeArchived=true includes archived plan",
353
- );
354
-
355
- // ── Test 12: plan_progress view excludes archived tasks ─────────────────────
356
- console.log("\nTest 12: plan_progress view excludes archived tasks from counts");
357
-
358
- // Create a plan with tasks, check progress, archive, check again
359
- createPlan(db, {
360
- ...PLAN_DEFAULTS,
361
- id: "progress-test",
362
- slug: "progress-test",
363
- title: "Progress Test Plan",
364
- });
365
-
366
- createTasksBatch(db, "progress-test", [
367
- { ...TASK_DEFAULTS, description: "Progress task 1", orderIndex: 0 },
368
- { ...TASK_DEFAULTS, description: "Progress task 2", orderIndex: 1 },
369
- ]);
370
-
371
- // Check progress before archive — should show 2 tasks
372
- const progressBefore = getPlanProgress(db, "progress-test");
373
- const progressBeforeFirst = progressBefore[0];
374
- assert(
375
- progressBefore.length === 1 && progressBeforeFirst?.totalTasks === 2,
376
- `plan_progress before archive: totalTasks=${progressBeforeFirst?.totalTasks ?? 0}`,
377
- );
378
-
379
- // Archive the plan (archives tasks too)
380
- archivePlan(db, "progress-test", { memDir: testMemDir });
381
-
382
- // Check progress after archive — should show 0 tasks (archived excluded)
383
- const progressAfter = getPlanProgress(db, "progress-test");
384
- const progressAfterFirst = progressAfter[0];
385
- assert(
386
- progressAfter.length === 1 && progressAfterFirst?.totalTasks === 0,
387
- `plan_progress after archive: totalTasks=${progressAfterFirst?.totalTasks ?? 0} (archived excluded)`,
388
- );
389
-
390
- // ── Cleanup ─────────────────────────────────────────────────────────────────
391
- rmSync(testMemDir, { recursive: true, force: true });
392
- db.close();
393
-
394
- // ── Summary ─────────────────────────────────────────────────────────────────
395
- console.log(`\n${"─".repeat(50)}`);
396
- console.log(`Results: ${pass} passed, ${fail} failed`);
397
- process.exit(fail > 0 ? 1 : 0);
@@ -1,224 +0,0 @@
1
- #!/usr/bin/env bash
2
- # ndomo uninstaller — removes agents, skills, and config from ~/.config/opencode/
3
- # Usage: ./uninstall.sh [--keep-data]
4
-
5
- set -euo pipefail
6
-
7
- # ── Colors ────────────────────────────────────────────────────────────────────
8
- RED='\033[0;31m'
9
- GREEN='\033[0;32m'
10
- YELLOW='\033[1;33m'
11
- BLUE='\033[0;34m'
12
- BOLD='\033[1m'
13
- NC='\033[0m' # No Color
14
-
15
- # ── Helpers ───────────────────────────────────────────────────────────────────
16
- info() { printf "${BLUE}[info]${NC} %s\n" "$*"; }
17
- ok() { printf "${GREEN}[ok]${NC} %s\n" "$*"; }
18
- warn() { printf "${YELLOW}[warn]${NC} %s\n" "$*"; }
19
- err() { printf "${RED}[error]${NC} %s\n" "$*" >&2; }
20
-
21
- # ── Parse flags ───────────────────────────────────────────────────────────────
22
- KEEP_DATA=false
23
-
24
- for arg in "$@"; do
25
- case "$arg" in
26
- --keep-data) KEEP_DATA=true ;;
27
- --help|-h)
28
- echo "Usage: ./uninstall.sh [--keep-data]"
29
- echo ""
30
- echo "Options:"
31
- echo " --keep-data Skip removal of .slim/ directory and opencode-mem data"
32
- exit 0
33
- ;;
34
- *)
35
- err "Unknown option: $arg (try --help)"
36
- exit 1
37
- ;;
38
- esac
39
- done
40
-
41
- # ── Paths ─────────────────────────────────────────────────────────────────────
42
- CONFIG_DIR="${HOME}/.config/opencode"
43
-
44
- # ── Agent files to remove ─────────────────────────────────────────────────────
45
- AGENTS=(
46
- "foreman.md"
47
- "scout.md"
48
- "scribe.md"
49
- "painter.md"
50
- "smith.md"
51
- "sage.md"
52
- "guild.md"
53
- "go-smith.md"
54
- "js-smith.md"
55
- "python-smith.md"
56
- "vue-smith.md"
57
- "zig-smith.md"
58
- "rust-smith.md"
59
- "inspector.md"
60
- "chronicler.md"
61
- "ci-smith.md"
62
- "craftsman.md"
63
- "deploy-smith.md"
64
- "ops-scout.md"
65
- "ranger.md"
66
- "release-smith.md"
67
- "warden.md"
68
- )
69
-
70
- # ── Skill directories to remove ───────────────────────────────────────────────
71
- SKILLS=(
72
- "caveman"
73
- "bash-scripting"
74
- "cavecrew"
75
- "deepwork"
76
- "reflect"
77
- "worktrees"
78
- "dcp-integration"
79
- "mem-recall"
80
- )
81
-
82
- # ── Config files to remove ────────────────────────────────────────────────────
83
- CONFIGS=(
84
- "ndomo.json"
85
- "ndomo.schema.json"
86
- )
87
-
88
- echo ""
89
- printf "${YELLOW}${BOLD}ndomo uninstaller${NC}\n"
90
- echo ""
91
-
92
- # ── Step 1: Remove agent files ───────────────────────────────────────────────
93
- info "Removing agent files..."
94
- AGENT_DIR="${CONFIG_DIR}/agent"
95
- AGENT_REMOVED=0
96
- for name in "${AGENTS[@]}"; do
97
- target="${AGENT_DIR}/${name}"
98
- if [[ -f "$target" ]]; then
99
- rm -f "$target"
100
- ok "Removed agent/${name}"
101
- AGENT_REMOVED=$((AGENT_REMOVED + 1))
102
- fi
103
- done
104
- if [[ $AGENT_REMOVED -eq 0 ]]; then
105
- info "No ndomo agent files found"
106
- else
107
- ok "Removed ${AGENT_REMOVED} agent file(s)"
108
- fi
109
-
110
- # ── Step 2: Remove skill directories ─────────────────────────────────────────
111
- info "Removing skill directories..."
112
- SKILL_DIR="${CONFIG_DIR}/skills"
113
- SKILL_REMOVED=0
114
- for name in "${SKILLS[@]}"; do
115
- target="${SKILL_DIR}/${name}"
116
- if [[ -d "$target" ]]; then
117
- rm -rf "$target"
118
- ok "Removed skills/${name}/"
119
- SKILL_REMOVED=$((SKILL_REMOVED + 1))
120
- fi
121
- done
122
- if [[ $SKILL_REMOVED -eq 0 ]]; then
123
- info "No ndomo skill directories found"
124
- else
125
- ok "Removed ${SKILL_REMOVED} skill directory(ies)"
126
- fi
127
-
128
- # ── Step 3: Remove config files ──────────────────────────────────────────────
129
- info "Removing config files..."
130
- CONFIG_REMOVED=0
131
- for name in "${CONFIGS[@]}"; do
132
- target="${CONFIG_DIR}/${name}"
133
- if [[ -f "$target" ]]; then
134
- rm -f "$target"
135
- ok "Removed ${name}"
136
- CONFIG_REMOVED=$((CONFIG_REMOVED + 1))
137
- fi
138
- done
139
- if [[ $CONFIG_REMOVED -eq 0 ]]; then
140
- info "No ndomo config files found"
141
- else
142
- ok "Removed ${CONFIG_REMOVED} config file(s)"
143
- fi
144
-
145
- # ── Step 4: Data removal (.slim/, mem data) ──────────────────────────────────
146
- SLIM_DIR="${HOME}/.slim"
147
- MEM_DIR="${HOME}/.ndomo/mem"
148
-
149
- if [[ "$KEEP_DATA" == true ]]; then
150
- info "Keeping data (--keep-data specified)"
151
- else
152
- HAS_DATA=false
153
- [[ -d "$SLIM_DIR" ]] && HAS_DATA=true
154
- [[ -d "$MEM_DIR" ]] && HAS_DATA=true
155
-
156
- if [[ "$HAS_DATA" == true ]]; then
157
- echo ""
158
- printf "${YELLOW}${BOLD}Data directories found:${NC}\n"
159
- [[ -d "$SLIM_DIR" ]] && printf " - ${SLIM_DIR}\n"
160
- [[ -d "$MEM_DIR" ]] && printf " - ${MEM_DIR}\n"
161
- echo ""
162
- printf "${YELLOW}These may contain session data and memories.${NC}\n"
163
- printf "${YELLOW}This action cannot be undone.${NC}\n"
164
- echo ""
165
- read -rp "Remove data directories? [y/N] " confirm
166
- case "$confirm" in
167
- [yY]|[yY][eE][sS])
168
- if [[ -d "$SLIM_DIR" ]]; then
169
- rm -rf "$SLIM_DIR"
170
- ok "Removed ${SLIM_DIR}"
171
- fi
172
- if [[ -d "$MEM_DIR" ]]; then
173
- rm -rf "$MEM_DIR"
174
- ok "Removed ${MEM_DIR}"
175
- fi
176
- ;;
177
- *)
178
- info "Skipping data removal"
179
- ;;
180
- esac
181
- else
182
- info "No data directories found to clean"
183
- fi
184
- fi
185
-
186
- # ── Step 5: Remove ndomo package from node_modules/ ─────────────────────────
187
- info "Removing ndomo package from OpenCode config..."
188
- if [[ -L "$CONFIG_DIR/node_modules/ndomo" ]] || [[ -e "$CONFIG_DIR/node_modules/ndomo" ]]; then
189
- rm -rf "$CONFIG_DIR/node_modules/ndomo"
190
- ok "Removed ndomo from $CONFIG_DIR/node_modules/"
191
- else
192
- info "No ndomo in $CONFIG_DIR/node_modules/ found"
193
- fi
194
-
195
- if [[ -f "$CONFIG_DIR/package.json" ]] && command -v jq &>/dev/null; then
196
- jq 'del(.dependencies.ndomo)' "$CONFIG_DIR/package.json" > "$CONFIG_DIR/package.json.tmp" && mv "$CONFIG_DIR/package.json.tmp" "$CONFIG_DIR/package.json"
197
- ok "Removed ndomo entry from $CONFIG_DIR/package.json"
198
- fi
199
-
200
- # ── Step 6: Remove custom tools symlink ─────────────────────────────────────
201
- TOOLS_DIR="${CONFIG_DIR}/tools"
202
- if [[ -L "$TOOLS_DIR" ]]; then
203
- rm "$TOOLS_DIR"
204
- ok "Removed custom tools symlink"
205
- elif [[ -d "$TOOLS_DIR" ]]; then
206
- info "Custom tools directory at $TOOLS_DIR is not a symlink — skipping"
207
- else
208
- info "No custom tools symlink at $TOOLS_DIR"
209
- fi
210
-
211
- # ── Summary ──────────────────────────────────────────────────────────────────
212
- echo ""
213
- printf "${GREEN}${BOLD}════════════════════════════════════════${NC}\n"
214
- printf "${GREEN}${BOLD} ndomo uninstalled${NC}\n"
215
- printf "${GREEN}${BOLD}════════════════════════════════════════${NC}\n"
216
- echo ""
217
- printf "${BOLD}Removed:${NC}\n"
218
- printf " Agents: %d file(s)\n" "$AGENT_REMOVED"
219
- printf " Skills: %d directory(ies)\n" "$SKILL_REMOVED"
220
- printf " Config: %d file(s)\n" "$CONFIG_REMOVED"
221
- echo ""
222
- printf "${BOLD}Note:${NC} This does NOT uninstall opencode-mem or @tarquinen/opencode-dcp.\n"
223
- printf " Those are separate plugins managed by opencode.\n"
224
- echo ""
package/src/index.ts DELETED
@@ -1,37 +0,0 @@
1
- /**
2
- * ndomo — OpenCode multi-agent plugin.
3
- *
4
- * Entry point. Import as a plugin in opencode.json:
5
- * ```jsonc
6
- * { "plugin": ["ndomo"] }
7
- * ```
8
- */
9
-
10
- export type {
11
- BackgroundTask,
12
- DispatchOptions,
13
- IntegrityReport,
14
- MemoryEntry,
15
- ReconciliationReport,
16
- RoutingDecision,
17
- TaskRequest,
18
- TaskResult,
19
- Worktree,
20
- WorktreeState,
21
- } from "./lib.ts";
22
- export {
23
- BackgroundDispatcher,
24
- canRunParallel,
25
- cavemanCompress,
26
- createWorktree,
27
- getProjectTag,
28
- listActive,
29
- memorySearchOptions,
30
- prepareForMemory,
31
- reconcileResults,
32
- removeWorktree,
33
- routeTask,
34
- shouldStoreMemory,
35
- verifyIntegrity,
36
- } from "./lib.ts";
37
- export { NdomoPlugin, type NdomoPluginOptions } from "./plugin.ts";