ndomo 0.1.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 (247) hide show
  1. package/.bun-version +1 -0
  2. package/.dockerignore +79 -0
  3. package/.editorconfig +18 -0
  4. package/.env.example +19 -0
  5. package/.github/CODEOWNERS +8 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.yml +62 -0
  7. package/.github/ISSUE_TEMPLATE/config.yml +2 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.yml +34 -0
  9. package/.github/dependabot.yml +36 -0
  10. package/.github/pull_request_template.md +24 -0
  11. package/.github/release.yml +30 -0
  12. package/.github/workflows/gitleaks.yml +28 -0
  13. package/.github/workflows/release-please.yml +27 -0
  14. package/.github/workflows/smoke.yml +29 -0
  15. package/.husky/commit-msg +1 -0
  16. package/CHANGELOG.md +114 -0
  17. package/Dockerfile +32 -0
  18. package/README.es.md +174 -0
  19. package/README.md +187 -0
  20. package/agents/chronicler.md +98 -0
  21. package/agents/ci-smith.md +136 -0
  22. package/agents/craftsman.md +341 -0
  23. package/agents/deploy-smith.md +138 -0
  24. package/agents/foreman.md +377 -0
  25. package/agents/go-smith.md +164 -0
  26. package/agents/guild.md +188 -0
  27. package/agents/inspector.md +83 -0
  28. package/agents/js-smith.md +127 -0
  29. package/agents/ops-scout.md +173 -0
  30. package/agents/painter.md +200 -0
  31. package/agents/python-smith.md +120 -0
  32. package/agents/ranger.md +307 -0
  33. package/agents/release-smith.md +165 -0
  34. package/agents/rust-smith.md +159 -0
  35. package/agents/sage.md +178 -0
  36. package/agents/scout.md +144 -0
  37. package/agents/scribe.md +156 -0
  38. package/agents/smith.md +201 -0
  39. package/agents/vue-smith.md +155 -0
  40. package/agents/warden.md +216 -0
  41. package/agents/zig-smith.md +156 -0
  42. package/bin/ndomo-analyses.ts +4 -0
  43. package/bin/ndomo-status.ts +4 -0
  44. package/biome.json +57 -0
  45. package/bun.lock +514 -0
  46. package/commitlint.config.js +3 -0
  47. package/config/ndomo.config.json +258 -0
  48. package/config/ndomo.schema.json +166 -0
  49. package/docs/agents.md +375 -0
  50. package/docs/bugs/plan-create-orphan-fk.md +131 -0
  51. package/docs/bugs/task_create_batch-order-index-collision.md +158 -0
  52. package/docs/configuration.md +276 -0
  53. package/docs/database.md +364 -0
  54. package/docs/features/feature-flexible-builder-v1.md +724 -0
  55. package/docs/features/feature-flexible-builder-v2.md +882 -0
  56. package/docs/features/feature-flexible-builder.md +974 -0
  57. package/docs/http-server.md +244 -0
  58. package/docs/installation.md +259 -0
  59. package/docs/integrations.md +129 -0
  60. package/docs/operations/anti-pattern-sub-agent-verify-2026-06-21.md +32 -0
  61. package/docs/operations/audit-v1.md +417 -0
  62. package/docs/operations/audit-v2.md +197 -0
  63. package/docs/operations/audit-v3.md +306 -0
  64. package/docs/operations/db-optimize-foundations.md +123 -0
  65. package/docs/operations/verify-gate-architecture.md +82 -0
  66. package/docs/workflows.md +448 -0
  67. package/opencode.json +5 -0
  68. package/package.json +65 -0
  69. package/release-please-config.json +11 -0
  70. package/scripts/dev-bust-cache.sh +164 -0
  71. package/scripts/install.sh +688 -0
  72. package/scripts/smoke-e2e.ts +704 -0
  73. package/scripts/smoke-hot.ts +417 -0
  74. package/scripts/smoke-http.sh +228 -0
  75. package/scripts/smoke-v4.ts +256 -0
  76. package/scripts/smoke-v5.ts +397 -0
  77. package/scripts/smoke.sh +9 -0
  78. package/scripts/uninstall.sh +224 -0
  79. package/skills/api-security-best-practices/SKILL.md +915 -0
  80. package/skills/bash-scripting/SKILL.md +201 -0
  81. package/skills/bun/SKILL.md +313 -0
  82. package/skills/cavecrew/SKILL.md +82 -0
  83. package/skills/caveman/SKILL.md +74 -0
  84. package/skills/caveman-review/README.md +33 -0
  85. package/skills/caveman-review/SKILL.md +55 -0
  86. package/skills/find-skills/SKILL.md +142 -0
  87. package/skills/frontend-design/LICENSE.txt +177 -0
  88. package/skills/frontend-design/SKILL.md +55 -0
  89. package/skills/golang-patterns/SKILL.md +674 -0
  90. package/skills/golang-security/SKILL.md +185 -0
  91. package/skills/golang-security/evals/evals.json +595 -0
  92. package/skills/golang-security/references/architecture.md +268 -0
  93. package/skills/golang-security/references/checklist.md +80 -0
  94. package/skills/golang-security/references/cookies.md +200 -0
  95. package/skills/golang-security/references/cryptography.md +424 -0
  96. package/skills/golang-security/references/filesystem.md +285 -0
  97. package/skills/golang-security/references/injection.md +315 -0
  98. package/skills/golang-security/references/logging.md +163 -0
  99. package/skills/golang-security/references/memory-safety.md +241 -0
  100. package/skills/golang-security/references/network.md +253 -0
  101. package/skills/golang-security/references/secrets.md +189 -0
  102. package/skills/golang-security/references/third-party.md +159 -0
  103. package/skills/golang-security/references/threat-modeling.md +189 -0
  104. package/skills/golang-testing/SKILL.md +720 -0
  105. package/skills/grill-me/SKILL.md +7 -0
  106. package/skills/javascript-testing-patterns/SKILL.md +537 -0
  107. package/skills/javascript-testing-patterns/references/advanced-testing-patterns.md +513 -0
  108. package/skills/modern-javascript-patterns/SKILL.md +43 -0
  109. package/skills/modern-javascript-patterns/references/advanced-patterns.md +487 -0
  110. package/skills/modern-javascript-patterns/references/details.md +457 -0
  111. package/skills/python-anti-patterns/SKILL.md +349 -0
  112. package/skills/python-design-patterns/SKILL.md +85 -0
  113. package/skills/python-design-patterns/references/details.md +353 -0
  114. package/skills/python-error-handling/SKILL.md +193 -0
  115. package/skills/python-error-handling/references/details.md +171 -0
  116. package/skills/python-testing-patterns/SKILL.md +278 -0
  117. package/skills/python-testing-patterns/references/advanced-patterns.md +411 -0
  118. package/skills/python-testing-patterns/references/details.md +349 -0
  119. package/skills/rust-patterns/SKILL.md +500 -0
  120. package/skills/rust-testing/SKILL.md +501 -0
  121. package/skills/security-review/SKILL.md +504 -0
  122. package/skills/security-review/cloud-infrastructure-security.md +361 -0
  123. package/skills/vue-best-practices/SKILL.md +154 -0
  124. package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
  125. package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
  126. package/skills/vue-best-practices/references/component-async.md +97 -0
  127. package/skills/vue-best-practices/references/component-data-flow.md +307 -0
  128. package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
  129. package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
  130. package/skills/vue-best-practices/references/component-slots.md +216 -0
  131. package/skills/vue-best-practices/references/component-suspense.md +228 -0
  132. package/skills/vue-best-practices/references/component-teleport.md +108 -0
  133. package/skills/vue-best-practices/references/component-transition-group.md +128 -0
  134. package/skills/vue-best-practices/references/component-transition.md +125 -0
  135. package/skills/vue-best-practices/references/composables.md +290 -0
  136. package/skills/vue-best-practices/references/directives.md +162 -0
  137. package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
  138. package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
  139. package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
  140. package/skills/vue-best-practices/references/plugins.md +166 -0
  141. package/skills/vue-best-practices/references/reactivity.md +344 -0
  142. package/skills/vue-best-practices/references/render-functions.md +201 -0
  143. package/skills/vue-best-practices/references/sfc.md +310 -0
  144. package/skills/vue-best-practices/references/state-management.md +135 -0
  145. package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
  146. package/skills/vue-pinia-best-practices/SKILL.md +21 -0
  147. package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
  148. package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
  149. package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
  150. package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
  151. package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
  152. package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
  153. package/skills/zig-0.16/SKILL.md +840 -0
  154. package/skills/zig-0.16/scripts/check-zig-version.sh +21 -0
  155. package/src/cli/analyses.ts +280 -0
  156. package/src/cli/index.ts +108 -0
  157. package/src/cli/serve.ts +192 -0
  158. package/src/cli/smoke.ts +131 -0
  159. package/src/cli/status.test.ts +204 -0
  160. package/src/cli/status.ts +263 -0
  161. package/src/cli/vacuum.test.ts +82 -0
  162. package/src/cli/vacuum.ts +96 -0
  163. package/src/config/schema.test.ts +88 -0
  164. package/src/config/schema.ts +64 -0
  165. package/src/db/analyses-migration.test.ts +210 -0
  166. package/src/db/analyses.test.ts +466 -0
  167. package/src/db/analyses.ts +375 -0
  168. package/src/db/auto-checkpoint.ts +131 -0
  169. package/src/db/client.test.ts +129 -0
  170. package/src/db/client.ts +55 -0
  171. package/src/db/fts-escape.ts +20 -0
  172. package/src/db/incidents.test.ts +201 -0
  173. package/src/db/incidents.ts +93 -0
  174. package/src/db/index.ts +86 -0
  175. package/src/db/migrations-v13.test.ts +141 -0
  176. package/src/db/migrations-v8.test.ts +301 -0
  177. package/src/db/migrations.ts +147 -0
  178. package/src/db/plan-archive.test.ts +180 -0
  179. package/src/db/plan-archive.ts +274 -0
  180. package/src/db/plan-create.test.ts +276 -0
  181. package/src/db/plan-create.ts +78 -0
  182. package/src/db/plan-files.test.ts +289 -0
  183. package/src/db/plan-update-status.ts +287 -0
  184. package/src/db/plans.test.ts +490 -0
  185. package/src/db/plans.ts +534 -0
  186. package/src/db/resolve-project-dir.test.ts +143 -0
  187. package/src/db/resolve-project-dir.ts +75 -0
  188. package/src/db/rollbacks.test.ts +150 -0
  189. package/src/db/rollbacks.ts +67 -0
  190. package/src/db/schema.ts +907 -0
  191. package/src/db/sessions.test.ts +80 -0
  192. package/src/db/sessions.ts +135 -0
  193. package/src/db/shutdown.test.ts +147 -0
  194. package/src/db/shutdown.ts +45 -0
  195. package/src/db/tasks.test.ts +921 -0
  196. package/src/db/tasks.ts +747 -0
  197. package/src/db/types.ts +619 -0
  198. package/src/http/__tests__/auth.test.ts +196 -0
  199. package/src/http/__tests__/routes.test.ts +465 -0
  200. package/src/http/__tests__/sse.test.ts +317 -0
  201. package/src/http/auth.ts +72 -0
  202. package/src/http/middleware/cors.ts +53 -0
  203. package/src/http/middleware/security-headers.ts +21 -0
  204. package/src/http/routes/events.ts +112 -0
  205. package/src/http/routes/health.ts +51 -0
  206. package/src/http/routes/plans.ts +66 -0
  207. package/src/http/routes/sessions.ts +50 -0
  208. package/src/http/routes/tasks.ts +60 -0
  209. package/src/http/server.ts +95 -0
  210. package/src/http/sse.ts +116 -0
  211. package/src/index.ts +37 -0
  212. package/src/lib.ts +65 -0
  213. package/src/mem/scoped.ts +65 -0
  214. package/src/orchestrator/background.test.ts +268 -0
  215. package/src/orchestrator/background.ts +293 -0
  216. package/src/orchestrator/memory-hook.ts +182 -0
  217. package/src/orchestrator/reconciler.ts +123 -0
  218. package/src/orchestrator/scheduler.test.ts +300 -0
  219. package/src/orchestrator/scheduler.ts +243 -0
  220. package/src/plugin.test.ts +2574 -0
  221. package/src/plugin.ts +1690 -0
  222. package/src/sdk/client.ts +66 -0
  223. package/src/worktrees/manager.ts +236 -0
  224. package/src/worktrees/state.ts +87 -0
  225. package/tests/integration/ranger-flow.test.ts +257 -0
  226. package/tools/analysis_archive.ts +28 -0
  227. package/tools/analysis_create.ts +55 -0
  228. package/tools/analysis_get.ts +33 -0
  229. package/tools/analysis_link_plan.ts +44 -0
  230. package/tools/analysis_list.ts +48 -0
  231. package/tools/analysis_search.ts +36 -0
  232. package/tools/analysis_update.ts +44 -0
  233. package/tools/plan_approve.ts +31 -0
  234. package/tools/plan_create.ts +58 -0
  235. package/tools/plan_get.ts +40 -0
  236. package/tools/plan_list.ts +37 -0
  237. package/tools/plan_search.ts +34 -0
  238. package/tools/plan_update_status.ts +71 -0
  239. package/tools/session_checkpoint.ts +31 -0
  240. package/tools/session_end.ts +26 -0
  241. package/tools/session_start.ts +43 -0
  242. package/tools/task_create_batch.ts +70 -0
  243. package/tools/task_list.ts +35 -0
  244. package/tools/task_next_for_agent.ts +30 -0
  245. package/tools/task_search.ts +34 -0
  246. package/tools/task_update_status.ts +37 -0
  247. package/tsconfig.json +31 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * ndomo — analysis_create custom tool.
3
+ *
4
+ * Create a new analysis record in the standalone analyses table.
5
+ * Use for analyst findings, architecture audits, onboarding notes,
6
+ * or cartography outputs. Optionally link to a source plan via sourcePlanId.
7
+ */
8
+
9
+ import { tool } from "@opencode-ai/plugin";
10
+ import type { InsertAnalysis } from "ndomo/db";
11
+ import { closeDb, createAnalysis, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
12
+
13
+ export default tool({
14
+ description:
15
+ "Create a new analysis record in the standalone analyses table. Use for analyst findings, architecture audits, onboarding notes, or cartography outputs. Optionally link to a source plan via sourcePlanId.",
16
+ args: {
17
+ slug: tool.schema.string(),
18
+ title: tool.schema.string(),
19
+ projectPath: tool.schema.string(),
20
+ summary: tool.schema.string(),
21
+ findingsJson: tool.schema.string(),
22
+ sourcePlanId: tool.schema.string().optional(),
23
+ agent: tool.schema.string().optional(),
24
+ sessionId: tool.schema.string().optional(),
25
+ },
26
+ execute: async (args, ctx) => {
27
+ // Validate findingsJson is valid JSON
28
+ try {
29
+ JSON.parse(args.findingsJson);
30
+ } catch {
31
+ throw new Error("ndomo: findingsJson must be valid JSON");
32
+ }
33
+
34
+ const projectDir = resolveProjectDir(ctx);
35
+ const db = openDb(projectDir);
36
+ runMigrations(db);
37
+ try {
38
+ const input: InsertAnalysis = {
39
+ slug: args.slug,
40
+ title: args.title,
41
+ projectPath: args.projectPath,
42
+ summary: args.summary,
43
+ findingsJson: args.findingsJson,
44
+ agent: args.agent ?? "ranger",
45
+ createdBy: ctx.agent ?? "ranger",
46
+ ...(args.sourcePlanId !== undefined && { sourcePlanId: args.sourcePlanId }),
47
+ ...(args.sessionId !== undefined && { sessionId: args.sessionId }),
48
+ };
49
+ const result = createAnalysis(db, input);
50
+ return JSON.stringify(result, null, 2);
51
+ } finally {
52
+ closeDb(db);
53
+ }
54
+ },
55
+ });
@@ -0,0 +1,33 @@
1
+ /**
2
+ * ndomo — analysis_get custom tool.
3
+ *
4
+ * Get a single analysis by id. Returns the analysis with parsed findingsJson.
5
+ */
6
+
7
+ import { tool } from "@opencode-ai/plugin";
8
+ import { closeDb, getAnalysis, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
9
+
10
+ export default tool({
11
+ description: "Get a single analysis by id. Returns the analysis with parsed findingsJson.",
12
+ args: {
13
+ id: tool.schema.string(),
14
+ },
15
+ execute: async (args, ctx) => {
16
+ const projectDir = resolveProjectDir(ctx);
17
+ const db = openDb(projectDir);
18
+ runMigrations(db);
19
+ try {
20
+ const result = getAnalysis(db, args.id);
21
+ if (!result) {
22
+ throw new Error(`ndomo: analysis '${args.id}' not found`);
23
+ }
24
+ return JSON.stringify(
25
+ { ...result, findingsJson: JSON.parse(result.findingsJson) },
26
+ null,
27
+ 2,
28
+ );
29
+ } finally {
30
+ closeDb(db);
31
+ }
32
+ },
33
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ndomo — analysis_link_plan custom tool.
3
+ *
4
+ * Link an existing analysis to a source plan (set source_plan_id).
5
+ * Pass null to unlink.
6
+ */
7
+
8
+ import { tool } from "@opencode-ai/plugin";
9
+ import {
10
+ closeDb,
11
+ linkAnalysisToPlan,
12
+ openDb,
13
+ resolveProjectDir,
14
+ runMigrations,
15
+ unlinkAnalysisFromPlan,
16
+ } from "ndomo/db";
17
+
18
+ export default tool({
19
+ description:
20
+ "Link an existing analysis to a source plan (set source_plan_id). Pass null to unlink.",
21
+ args: {
22
+ id: tool.schema.string(),
23
+ planId: tool.schema.string().nullable(),
24
+ },
25
+ execute: async (args, ctx) => {
26
+ const projectDir = resolveProjectDir(ctx);
27
+ const db = openDb(projectDir);
28
+ runMigrations(db);
29
+ try {
30
+ if (args.planId === null) {
31
+ const result = unlinkAnalysisFromPlan(db, args.id);
32
+ return JSON.stringify({ ok: true, id: result.id, sourcePlanId: null }, null, 2);
33
+ }
34
+ const result = linkAnalysisToPlan(db, args.id, args.planId);
35
+ return JSON.stringify(
36
+ { ok: true, id: result.id, sourcePlanId: result.sourcePlanId },
37
+ null,
38
+ 2,
39
+ );
40
+ } finally {
41
+ closeDb(db);
42
+ }
43
+ },
44
+ });
@@ -0,0 +1,48 @@
1
+ /**
2
+ * ndomo — analysis_list custom tool.
3
+ *
4
+ * List analyses with optional filters: sourcePlanId, agent, projectPath, archived, limit.
5
+ */
6
+
7
+ import { tool } from "@opencode-ai/plugin";
8
+ import { closeDb, listAnalyses, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
9
+
10
+ export default tool({
11
+ description:
12
+ "List analyses with optional filters: sourcePlanId, agent, projectPath, archived, limit.",
13
+ args: {
14
+ sourcePlanId: tool.schema.string().optional(),
15
+ agent: tool.schema.string().optional(),
16
+ projectPath: tool.schema.string().optional(),
17
+ archived: tool.schema.boolean().optional(),
18
+ limit: tool.schema.number().optional(),
19
+ },
20
+ execute: async (args, ctx) => {
21
+ const projectDir = resolveProjectDir(ctx);
22
+ const db = openDb(projectDir);
23
+ runMigrations(db);
24
+ try {
25
+ const opts: {
26
+ sourcePlanId?: string;
27
+ agent?: string;
28
+ projectPath?: string;
29
+ archived?: boolean;
30
+ limit?: number;
31
+ } = {};
32
+ if (args.sourcePlanId !== undefined) opts.sourcePlanId = args.sourcePlanId;
33
+ if (args.agent !== undefined) opts.agent = args.agent;
34
+ if (args.projectPath !== undefined) opts.projectPath = args.projectPath;
35
+ if (args.archived !== undefined) opts.archived = args.archived;
36
+ if (args.limit !== undefined) opts.limit = args.limit;
37
+
38
+ const results = listAnalyses(db, opts);
39
+ return JSON.stringify(
40
+ results.map((r) => ({ ...r, findingsJson: JSON.parse(r.findingsJson) })),
41
+ null,
42
+ 2,
43
+ );
44
+ } finally {
45
+ closeDb(db);
46
+ }
47
+ },
48
+ });
@@ -0,0 +1,36 @@
1
+ /**
2
+ * ndomo — analysis_search custom tool.
3
+ *
4
+ * Full-text search over analyses (title + summary + findings) using FTS5.
5
+ * Returns matching analyses.
6
+ */
7
+
8
+ import { tool } from "@opencode-ai/plugin";
9
+ import { closeDb, openDb, resolveProjectDir, runMigrations, searchAnalyses } from "ndomo/db";
10
+
11
+ export default tool({
12
+ description:
13
+ "Full-text search over analyses (title + summary + findings) using FTS5. Returns matching analyses.",
14
+ args: {
15
+ query: tool.schema.string(),
16
+ limit: tool.schema.number().optional(),
17
+ },
18
+ execute: async (args, ctx) => {
19
+ const projectDir = resolveProjectDir(ctx);
20
+ const db = openDb(projectDir);
21
+ runMigrations(db);
22
+ try {
23
+ const opts: { limit?: number } = {};
24
+ if (args.limit !== undefined) opts.limit = args.limit;
25
+
26
+ const results = searchAnalyses(db, args.query, opts);
27
+ return JSON.stringify(
28
+ results.map((r) => ({ ...r, findingsJson: JSON.parse(r.findingsJson) })),
29
+ null,
30
+ 2,
31
+ );
32
+ } finally {
33
+ closeDb(db);
34
+ }
35
+ },
36
+ });
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ndomo — analysis_update custom tool.
3
+ *
4
+ * Update an existing analysis. Only provided fields are changed. Bumps updated_at.
5
+ */
6
+
7
+ import { tool } from "@opencode-ai/plugin";
8
+ import type { InsertAnalysis } from "ndomo/db";
9
+ import { closeDb, openDb, resolveProjectDir, runMigrations, updateAnalysis } from "ndomo/db";
10
+
11
+ export default tool({
12
+ description: "Update an existing analysis. Only provided fields are changed. Bumps updated_at.",
13
+ args: {
14
+ id: tool.schema.string(),
15
+ title: tool.schema.string().optional(),
16
+ summary: tool.schema.string().optional(),
17
+ findingsJson: tool.schema.string().optional(),
18
+ },
19
+ execute: async (args, ctx) => {
20
+ // Validate findingsJson if provided
21
+ if (args.findingsJson !== undefined) {
22
+ try {
23
+ JSON.parse(args.findingsJson);
24
+ } catch {
25
+ throw new Error("ndomo: findingsJson must be valid JSON");
26
+ }
27
+ }
28
+
29
+ const projectDir = resolveProjectDir(ctx);
30
+ const db = openDb(projectDir);
31
+ runMigrations(db);
32
+ try {
33
+ const patch: Partial<InsertAnalysis> = {};
34
+ if (args.title !== undefined) patch.title = args.title;
35
+ if (args.summary !== undefined) patch.summary = args.summary;
36
+ if (args.findingsJson !== undefined) patch.findingsJson = args.findingsJson;
37
+
38
+ const result = updateAnalysis(db, args.id, patch);
39
+ return JSON.stringify(result, null, 2);
40
+ } finally {
41
+ closeDb(db);
42
+ }
43
+ },
44
+ });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ndomo — plan_approve custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import { approvePlan, closeDb, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
12
+
13
+ export default tool({
14
+ description: "Mark a plan as approved. Sets approved_at to the current timestamp.",
15
+ args: { id: tool.schema.string() },
16
+ execute: async (args, ctx) => {
17
+ const projectDir = resolveProjectDir(ctx);
18
+ const db = openDb(projectDir);
19
+ runMigrations(db);
20
+ try {
21
+ return JSON.stringify(
22
+ approvePlan(db, args.id, {
23
+ sessionId: ctx.sessionID,
24
+ updatedBy: ctx.agent ?? "unknown",
25
+ }),
26
+ );
27
+ } finally {
28
+ closeDb(db);
29
+ }
30
+ },
31
+ });
@@ -0,0 +1,58 @@
1
+ /**
2
+ * ndomo — plan_create custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import crypto from "node:crypto";
11
+ import { tool } from "@opencode-ai/plugin";
12
+ import type { PlanMetadata } from "ndomo/db";
13
+ import { closeDb, createPlan, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
14
+
15
+ export default tool({
16
+ description: "Create a new plan in the ndomo state database.",
17
+ args: {
18
+ slug: tool.schema.string(),
19
+ title: tool.schema.string(),
20
+ overview: tool.schema.string(),
21
+ approach: tool.schema.string().optional(),
22
+ priority: tool.schema.number().optional(),
23
+ complexity: tool.schema.number().int().min(1).max(5).optional(),
24
+ sessionId: tool.schema.string().optional(),
25
+ metadata: tool.schema.record(tool.schema.string(), tool.schema.unknown()).optional(),
26
+ },
27
+ execute: async (args, ctx) => {
28
+ const projectDir = resolveProjectDir(ctx);
29
+ const db = openDb(projectDir);
30
+ runMigrations(db);
31
+ try {
32
+ const typedMeta = (args.metadata ?? {}) as PlanMetadata;
33
+ const plan = createPlan(db, {
34
+ id: crypto.randomUUID(),
35
+ slug: args.slug,
36
+ title: args.title,
37
+ status: "draft" as const,
38
+ priority: args.priority ?? 0,
39
+ approvedAt: null,
40
+ completedAt: null,
41
+ sessionId: args.sessionId ?? null,
42
+ overview: args.overview,
43
+ approach: args.approach ?? null,
44
+ complexity: args.complexity ?? 3,
45
+ createdBy: ctx.agent ?? "unknown",
46
+ updatedBy: ctx.agent ?? "unknown",
47
+ sourceSessionId: ctx.sessionID,
48
+ sourceMessageId: ctx.messageID,
49
+ category: typedMeta.category ?? null,
50
+ metadata: typedMeta,
51
+ archivedAt: null,
52
+ });
53
+ return JSON.stringify(plan);
54
+ } finally {
55
+ closeDb(db);
56
+ }
57
+ },
58
+ });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * ndomo — plan_get custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import {
12
+ closeDb,
13
+ getPlan,
14
+ getPlanBySlug,
15
+ openDb,
16
+ resolveProjectDir,
17
+ runMigrations,
18
+ } from "ndomo/db";
19
+
20
+ export default tool({
21
+ description: "Get a plan by ID or slug.",
22
+ args: {
23
+ id: tool.schema.string().optional(),
24
+ slug: tool.schema.string().optional(),
25
+ },
26
+ execute: async (args, ctx) => {
27
+ if (!args.id && !args.slug) {
28
+ throw new Error("ndomo: plan_get requires id or slug");
29
+ }
30
+ const projectDir = resolveProjectDir(ctx);
31
+ const db = openDb(projectDir);
32
+ runMigrations(db);
33
+ try {
34
+ const plan = args.id ? getPlan(db, args.id) : getPlanBySlug(db, args.slug as string);
35
+ return JSON.stringify(plan);
36
+ } finally {
37
+ closeDb(db);
38
+ }
39
+ },
40
+ });
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ndomo — plan_list custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import type { PlanStatus } from "ndomo/db";
12
+ import { closeDb, listPlans, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
13
+
14
+ export default tool({
15
+ description: "List plans, optionally filtered by status and session.",
16
+ args: {
17
+ status: tool.schema
18
+ .enum(["draft", "approved", "executing", "completed", "failed", "abandoned"])
19
+ .optional(),
20
+ sessionId: tool.schema.string().optional(),
21
+ limit: tool.schema.number().optional(),
22
+ },
23
+ execute: async (args, ctx) => {
24
+ const projectDir = resolveProjectDir(ctx);
25
+ const db = openDb(projectDir);
26
+ runMigrations(db);
27
+ try {
28
+ const opts: { status?: PlanStatus; sessionId?: string; limit?: number } = {};
29
+ if (args.status) opts.status = args.status;
30
+ if (args.sessionId) opts.sessionId = args.sessionId;
31
+ if (args.limit !== undefined) opts.limit = args.limit;
32
+ return JSON.stringify(listPlans(db, opts));
33
+ } finally {
34
+ closeDb(db);
35
+ }
36
+ },
37
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * ndomo — plan_search custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import { closeDb, openDb, resolveProjectDir, runMigrations, searchPlans } from "ndomo/db";
12
+
13
+ export default tool({
14
+ description: "Full-text search over plan titles, overviews, and approaches using SQLite FTS5.",
15
+ args: {
16
+ query: tool.schema.string(),
17
+ limit: tool.schema.number().optional(),
18
+ includeArchived: tool.schema.boolean().optional(),
19
+ },
20
+ execute: async (args, ctx) => {
21
+ const projectDir = resolveProjectDir(ctx);
22
+ const db = openDb(projectDir);
23
+ runMigrations(db);
24
+ try {
25
+ return JSON.stringify(
26
+ searchPlans(db, args.query, args.limit ?? 20, {
27
+ includeArchived: args.includeArchived ?? false,
28
+ }),
29
+ );
30
+ } finally {
31
+ closeDb(db);
32
+ }
33
+ },
34
+ });
@@ -0,0 +1,71 @@
1
+ /**
2
+ * ndomo — plan_update_status custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ *
9
+ * Special: also auto-archives to markdown on terminal statuses.
10
+ */
11
+
12
+ import { tool } from "@opencode-ai/plugin";
13
+ import type { ArchiveResult, PlanStatus } from "ndomo/db";
14
+ import {
15
+ archivePlan,
16
+ closeDb,
17
+ openDb,
18
+ resolveArchiveDir,
19
+ resolveProjectDir,
20
+ runMigrations,
21
+ updatePlanStatus,
22
+ } from "ndomo/db";
23
+
24
+ export default tool({
25
+ description:
26
+ "Update a plan's status (draft, approved, executing, completed, failed, abandoned). Auto-archives to markdown on terminal status.",
27
+ args: {
28
+ id: tool.schema.string(),
29
+ status: tool.schema.enum([
30
+ "draft",
31
+ "approved",
32
+ "executing",
33
+ "completed",
34
+ "failed",
35
+ "abandoned",
36
+ ]),
37
+ },
38
+ execute: async (args, ctx) => {
39
+ const projectDir = resolveProjectDir(ctx);
40
+ const db = openDb(projectDir);
41
+ runMigrations(db);
42
+ try {
43
+ const updated = updatePlanStatus(db, args.id, args.status as PlanStatus, {
44
+ sessionId: ctx.sessionID,
45
+ updatedBy: ctx.agent ?? "unknown",
46
+ });
47
+
48
+ // Auto-archive on terminal status
49
+ const TERMINAL_STATUSES = new Set(["completed", "failed", "abandoned"]);
50
+ let archiveResult: ArchiveResult | null = null;
51
+ let archiveError: string | null = null;
52
+
53
+ if (updated && TERMINAL_STATUSES.has(args.status)) {
54
+ try {
55
+ archiveResult = archivePlan(db, updated.id, { memDir: resolveArchiveDir(projectDir) });
56
+ } catch (err) {
57
+ archiveError = err instanceof Error ? err.message : String(err);
58
+ console.warn(`[ndomo] auto-archive failed for plan ${updated.id}: ${archiveError}`);
59
+ }
60
+ }
61
+
62
+ return JSON.stringify({
63
+ plan: updated,
64
+ archived: archiveResult,
65
+ archiveError,
66
+ });
67
+ } finally {
68
+ closeDb(db);
69
+ }
70
+ },
71
+ });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * ndomo — session_checkpoint custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import { checkpointSession, closeDb, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
12
+
13
+ export default tool({
14
+ description:
15
+ "Save a checkpoint in an active session with arbitrary state and optional key decisions.",
16
+ args: {
17
+ id: tool.schema.string(),
18
+ state: tool.schema.record(tool.schema.string(), tool.schema.unknown()),
19
+ keyDecisions: tool.schema.string().optional(),
20
+ },
21
+ execute: async (args, ctx) => {
22
+ const projectDir = resolveProjectDir(ctx);
23
+ const db = openDb(projectDir);
24
+ runMigrations(db);
25
+ try {
26
+ return JSON.stringify(checkpointSession(db, args.id, args.state, args.keyDecisions));
27
+ } finally {
28
+ closeDb(db);
29
+ }
30
+ },
31
+ });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * ndomo — session_end custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import { closeDb, endSession, openDb, resolveProjectDir, runMigrations } from "ndomo/db";
12
+
13
+ export default tool({
14
+ description: "Mark a session as ended. Sets ended_at to the current timestamp.",
15
+ args: { id: tool.schema.string() },
16
+ execute: async (args, ctx) => {
17
+ const projectDir = resolveProjectDir(ctx);
18
+ const db = openDb(projectDir);
19
+ runMigrations(db);
20
+ try {
21
+ return JSON.stringify(endSession(db, args.id));
22
+ } finally {
23
+ closeDb(db);
24
+ }
25
+ },
26
+ });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * ndomo — session_start custom tool.
3
+ *
4
+ * Mirror of the equivalent plugin tool in src/plugin.ts, exposed as a
5
+ * standalone OpenCode custom tool. Opens its own DB connection and runs
6
+ * migrations on first use. Use this when you want DB access from outside
7
+ * the plugin (e.g. from agents that don't load the plugin).
8
+ */
9
+
10
+ import { tool } from "@opencode-ai/plugin";
11
+ import type { SessionMetadata } from "ndomo/db";
12
+ import { closeDb, openDb, resolveProjectDir, runMigrations, startSession } from "ndomo/db";
13
+
14
+ export default tool({
15
+ description:
16
+ "Start a new ndomo session with a goal. Sessions track continuity across multiple agents.",
17
+ args: {
18
+ id: tool.schema.string(),
19
+ goal: tool.schema.string(),
20
+ planId: tool.schema.string().optional(),
21
+ metadata: tool.schema.record(tool.schema.string(), tool.schema.unknown()).optional(),
22
+ },
23
+ execute: async (args, ctx) => {
24
+ const projectDir = resolveProjectDir(ctx);
25
+ const db = openDb(projectDir);
26
+ runMigrations(db);
27
+ try {
28
+ const typedMeta = (args.metadata ?? {}) as SessionMetadata;
29
+ return JSON.stringify(
30
+ startSession(db, {
31
+ id: args.id,
32
+ goal: args.goal,
33
+ ...(args.planId !== undefined && { planId: args.planId }),
34
+ metadata: typedMeta,
35
+ createdBy: ctx.agent ?? "unknown",
36
+ sourceMessageId: ctx.messageID,
37
+ }),
38
+ );
39
+ } finally {
40
+ closeDb(db);
41
+ }
42
+ },
43
+ });